seq2seq 的 keras 實現

amadan發表於2021-09-09

上一篇 提到了 cho 和 Sutskever 的兩篇論文,今天來看一下如何用 keras 建立 seq2seq。

圖片描述

第一個 LSTM 為 Encoder,只在序列結束時輸出一個語義向量,所以其 "return_sequences" 引數設定為 "False"

使用 "RepeatVector" 將 Encoder 的輸出(最後一個 time step)複製 N 份作為 Decoder 的 N 次輸入

第二個 LSTM 為 Decoder, 因為在每一個 time step 都輸出,所以其 "return_sequences" 引數設定為 "True"

from keras.models import Sequentialfrom keras.layers.recurrent import LSTMfrom keras.layers.wrappers import TimeDistributedfrom keras.layers.core import Dense, RepeatVectordef build_model(input_size, max_out_seq_len, hidden_size):
    
    model = Sequential()    
    # Encoder(第一個 LSTM)     model.add( LSTM(input_dim=input_size, output_dim=hidden_size, return_sequences=False) )
    
    
    model.add( Dense(hidden_size, activation="relu") )    
    # 使用 "RepeatVector" 將 Encoder 的輸出(最後一個 time step)複製 N 份作為 Decoder 的 N 次輸入
    model.add( RepeatVector(max_out_seq_len) )    
    # Decoder(第二個 LSTM) 
    model.add( LSTM(hidden_size, return_sequences=True) )    
    # TimeDistributed 是為了保證 Dense 和 Decoder 之間的一致
    model.add( TimeDistributed(Dense(output_dim=input_size, activation="linear")) )
    
    model.compile(loss="mse", optimizer='adam')    return model

也可以用 GRU 作為 RNN 單元,程式碼如下,區別就是將 LSTM 處換成 GRU:

from keras.layers.recurrent import GRUfrom keras.layers.wrappers import TimeDistributedfrom keras.models import Sequential, model_from_jsonfrom keras.layers.core import Dense, RepeatVector    

def build_model(input_size, seq_len, hidden_size):
    """建立一個 sequence to sequence 模型"""
    model = Sequential()
    model.add(GRU(input_dim=input_size, output_dim=hidden_size, return_sequences=False))
    model.add(Dense(hidden_size, activation="relu"))
    model.add(RepeatVector(seq_len))
    model.add(GRU(hidden_size, return_sequences=True))
    model.add(TimeDistributed(Dense(output_dim=input_size, activation="linear")))
    model.compile(loss="mse", optimizer='adam')    return model

上面是一個最簡單的 seq2seq 模型,因為沒有將 Decoder 的每一個時刻的輸出作為下一個時刻的輸入。


當然,我們可以直接用 keras 的 seq2seq 模型:

下面是幾個例子:

簡單的 seq2seq 模型:

import seq2seqfrom seq2seq.models import SimpleSeq2Seq

model = SimpleSeq2Seq(input_dim=5, hidden_dim=10, output_length=8, output_dim=8)
model.compile(loss='mse', optimizer='rmsprop')

深度 seq2seq 模型:encoding 有 3 層,  decoding 有 3 層

import seq2seqfrom seq2seq.models import SimpleSeq2Seq

model = SimpleSeq2Seq(input_dim=5, hidden_dim=10, output_length=8, output_dim=8, depth=3)
model.compile(loss='mse', optimizer='rmsprop')

encoding 和 decoding 的層數也可以不同:encoding 有 4 層,  decoding 有 5 層

import seq2seqfrom seq2seq.models import SimpleSeq2Seq

model = SimpleSeq2Seq(input_dim=5, hidden_dim=10, output_length=8, output_dim=20, depth=(4, 5))
model.compile(loss='mse', optimizer='rmsprop')

上面幾種也是最簡單的 SimpleSeq2Seq 的應用。


在論文 Sequence to Sequence Learning with Neural Networks 給出的 seq2seq 中,encoder 的隱藏層狀態要傳遞給 decoder,而且 decoder 的每一個時刻的輸出作為下一個時刻的輸入,而且這裡內建的模型中,還將隱藏層狀態貫穿了整個 LSTM:

圖片描述

import seq2seqfrom seq2seq.models import Seq2Seq

model = Seq2Seq(batch_input_shape=(16, 7, 5), hidden_dim=10, output_length=8, output_dim=20, depth=4)
model.compile(loss='mse', optimizer='rmsprop')

cho 的這篇論文 Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation 中的 seq2seq 模型實現為:decoder 在每個時間點的語境向量都會獲得一個 'peek'

圖片描述

import seq2seqfrom seq2seq.models import Seq2Seq

model = Seq2Seq(batch_input_shape=(16, 7, 5), hidden_dim=10, output_length=8, output_dim=20, depth=4, peek=True)
model.compile(loss='mse', optimizer='rmsprop')

在論文 Neural Machine Translation by Jointly Learning to Align and Translate 中帶有注意力機制的 seq2seq:沒有隱藏狀態的傳播,而且 encoder 是雙向的 LSTM

圖片描述

圖片描述

import seq2seqfrom seq2seq.models import AttentionSeq2Seq

model = AttentionSeq2Seq(input_dim=5, input_length=7, hidden_dim=10, output_length=8, output_dim=20, depth=4)
model.compile(loss='mse', optimizer='rmsprop')

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2310/viewspace-2806003/,如需轉載,請註明出處,否則將追究法律責任。

相關文章