2017-10-19 188 views
1

我使用Keras作为(字符)序列到序列RNN应用程序。由于我有一个相对较少的A - > B例子,以及更多的B例子,我决定尝试一种自动编码器方法:首先训练一个网络来学习B上的身份函数,为成员产生一个嵌入的B,然后训练一个网络来学习A - >嵌入(B)。通过将第二个网络与第一个网络的解码器一半相结合,希望它能够推广生产合理的Bs。用部分共享权重串联训练两个Keras模型

的代码中,Building Autoencoders in Keras教程为蓝本,看起来是这样的(好几层,辍学,正则化等已经离开了为简单起见):

class Example: 
    def __init(self, ...): 
     # Sets dense_size, rnn, rnn_size, embed_size, input_len, output_len, etc. 

    def apply_encoder(self, input_word): 
     input_masked = Masking()(input_word) 
     input_dense = TimeDistributed(Dense(self.dense_size), name='input_dense')(input_masked) 
     rnn = self.rnn(self.rnn_size, name='input_rnn')(input_dense) 
     embedding = Dense(self.embed_size, name='embedding')(rnn) 
     return embedding 

    def apply_decoder(self, embedding): 
     repeated = RepeatVector(self.output_len, name='repeat')(embedding) 
     rnn = self.rnn(self.rnn_size, name='output_rnn')(repeated) 
     output_dense = TimeDistributed(Dense(self.dense_size), name='output_dense')(rnn) 
     output_word = TimeDistributed(
      Dense(self.chars, activation='softmax'), 
      name='output_word' 
      )(output_dense) 
     return output_word 

    def build_net(self): 
     input_word = Input(shape=(self.input_len, self.chars), name='input_word') 
     embedding = self.apply_encoder(input_word) 
     output_word = self.apply_decoder(embedding) 

     self.autoencoder = Model(input_word, output_word) 
     self.encoder = Model(input_word, embedding) 

     embed_input = Input(shape=(self.embed_size,), name='input_embedding') 
     decoder_output = self.apply_decoder(embed_input) 

     self.decoder = Model(embed_input, decoder_output) 

    def save_models(self): 
     open('models/autoencoder.json', 'w').write(self.autoencoder.to_json()) 
     open('models/encoder.json', 'w').write(self.encoder.to_json()) 
     open('models/decoder.json', 'w').write(self.decoder.to_json()) 

第一个脚本列车autoencoder在B→B;那么另一个脚本实例化encoder两次,并在A上训练encoderA - >encoderB.predict(B);最后,查询脚本使用encoderAdecoderB进行预测。

这一切都很好,但表现并不像我想的那么好,所以我真正想做的是同时训练两个模型。我想要的是两个编码器型号单独编码器的一半,但共享权重为解码器的一半。然后,我在一批A→B的训练模型A和一批B→B的训练模型B之间交替,这两个批次应更新两个编码器,但每批更新共享解码器。

我的问题是,我怎样才能构建这两个模型,使权重以我想要的方式共享? Here是一个类似的问题,但它只解释了如何做我已经完成的工作。如果后端很重要(可能没有),我可以使用TF或Theano。

回答

1

使用功能性API制作零件模型,并将它们加入,就好像它们是图层一样。

不同的是,要创建的两个解码器(通过调用应用解码器两次)

编码器A:

aInput = Input(...) 
encodedA = LotsOfLayers(...)(aInput) 

self.encoderA = Model(aInput,encodedA) 

编码器B:

bInput = Input(...) 
encodedB = LotsOfLayers(...)(bInput) 

self.encoderB = Model(bInput,encodedB) 

解码器:

我们只创建一个解码器在这里:

encodedInput = Input(...) 
decodedOutput = LotsOfLayers(...)(encodedInput) 

self.decoder = Model(encodedInput, decodedOutput) 

AutoencoderB:

这里的 “猫跳”:

autoInput = Input(sameShapeAsEncoderBInput) 
encoded = self.encoderB(autoInput) 
decoded = self.decoder(encoded) 

self.autoencoderB = Model(autoInput,decoded) 

预测从A:

遵循相同的逻辑:

anotherAInput = Input(sameShapeAsEncoderAInput) 
encoded = self.encoderA(anotherAInput) 
decoded = self.decoder(encoded) 

self.predictorFromA = Model(anotherAInput,decoded) 

这将使解码器是相同的(分担权重),两者AutoencoderB和预测从A

+1

谢谢,我想我明白了!我会尝试今晚应用它,然后给你复选标记:) – hobbs

+1

它的作品非常漂亮。我想我所缺少的是'Input'就像一个占位符,当你编写两个模型时,第一个插槽的输出到第二个输入的输出中。 – hobbs