2017-10-19 230 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