NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

背景

NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

本系列從第十二期開啟 神經網絡翻譯NMT及聊天機器人Chatbot 的模型,已經涉及Seq2Seq,Attention Mechanism,Beam Search 等模型。前期基本上都是從抽象的角度出發進行總結。

本期將給大家帶來Seq2Seq模型代碼的講解,代碼來來自於 Toward Datascience 的Ravindra Kompella。並加上自己的理解。

本期帶來的模型是基礎的Seq2Seq 模型,並不涉及Attention Mechanism。對於Seq2Seq 模型的抽象原理講解,可以參考本系列第十三期。

Seq2Seq模型簡介

NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

Seq2Seq 模型其實就是 Encoder-Decoder模型 加上一個 循環神經網絡。其思路是將 一段句子 encoder 成一個向量,再將此向量“解壓”成目標語句。

關於此模型的優缺點和其他的理解,詳細的可以參考本系列第十二期。

NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

Seq2Seq訓練

本次建立的模型將會基於下圖進行講解,

NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

首先,我們擁有的數據集是10000個英文句子 與其 對應的法語句子。我們的訓練樣本是10000個

總體的訓練步驟:

  • 對於所有的英文和法語句子,建立一個以 字母 為基礎的one-hot 向量。這些向量將作為Encoder和Decoder的輸入值;

個人解釋:需要解釋下 以 字母為基礎。很多NLP的模型會使用Word Embedding層或者借用 Global Vector 等等。但是今天的例子,採用的是one-hot向量。主要是因為我們是以字母為基礎,畢竟英文只有26個字母,不會造成Sparsity的問題(詳情請見本系列第三期)

  • 逐個將每個英文字母,輸入Encoder 直到英文句子的末尾;
  • 獲取Encoder 最終的 States(hidden states和 cell states),然後將這個最終的states導入Decoder 作為初始狀態;
  • Decoder每次都會有三個輸入值,兩個由Encoder發起的States 和 法語的逐字母輸入;
  • 在每一個Decoder輸出值,輸出值導入到Softmax層 與 實際的目標值進行比較並計算loss

詳細的代碼實踐:

第一步.

處理原始數據,並且蒐集所有的英文 和 法語 字母。並且將英文與法語字母轉換為Dictionary

# Process english and french sentences
for line in range(nb_samples):
eng_line = str(lines[line]).split('\t')[0]
# Append '\t' for start of the sentence and '\n' to signify end of the sentence
fra_line = '\t' + str(lines[line]).split('\t')[1] + '\n'
eng_sent.append(eng_line)
fra_sent.append(fra_line)
for ch in eng_line:
if (ch not in eng_chars):
eng_chars.add(ch)
for ch in fra_line:
if (ch not in fra_chars):
fra_chars.add(ch)

第二步,建立起以字母為基礎的one-hot vector

比如字母a 為變成【1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.....】共26位

tokenized_eng_sentences = np.zeros(shape = (nb_samples,max_len_eng_sent,len(eng_chars)), dtype='float32')
tokenized_fra_sentences = np.zeros(shape = (nb_samples,max_len_fra_sent,len(fra_chars)), dtype='float32')
target_data = np.zeros((nb_samples, max_len_fra_sent, len(fra_chars)),dtype='float32')

# Vectorize the english and french sentences
for i in range(nb_samples):
for k, ch in enumerate(eng_sent[i]):
tokenized_eng_sentences[i, k, eng_char_to_index_dict[ch]] = 1
for k, ch in enumerate(fra_sent[i]):
tokenized_fra_sentences[i, k, fra_char_to_index_dict[ch]] = 1
# decoder_target_data will be ahead by one timestep and will not include the start character.
if k > 0:
target_data[i, k - 1, fra_char_to_index_dict[ch]] = 1

第三步

建立Encoder模型,對於encoder中的LSTM模型,我們將return state 設置為True,另外Return Sequence 模型為False。這意味著,雖然我們是逐字母輸入,但是LSTM不會逐字母輸出sequence,我們只輸出最終的states。因為基礎的Seq2Seq模型只使用Encoder輸出的最終Vector


# Encoder model
encoder_input = Input(shape=(None,len(eng_chars)))
encoder_LSTM = LSTM(256,return_state = True)
encoder_outputs, encoder_h, encoder_c = encoder_LSTM (encoder_input)
encoder_states = [encoder_h, encoder_c]

第四步

Decoder 的輸入值,為逐字母的法語字母, 和 上一個 神經元的States。另外,Decoder 的初始States 是來源於 Encoder, 大家能看到第四行的initial_state=encoder_states


# Decoder model
decoder_input = Input(shape=(None,len(fra_chars)))
decoder_LSTM = LSTM(256,return_sequences=True, return_state = True)

decoder_out, _ , _ = decoder_LSTM(decoder_input, initial_state=encoder_states)
decoder_dense = Dense(len(fra_chars),activation='softmax')
decoder_out = decoder_dense (decoder_out)

第五步

最終集合該模型,loss 類型選擇為Categorical Crossentropy

model = Model(inputs=[encoder_input, decoder_input],outputs=[decoder_out])
# Run training
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
model.fit(x=[tokenized_eng_sentences,tokenized_fra_sentences],
y=target_data,
batch_size=64,
epochs=50,
validation_split=0.2)

開始訓練

因為模型訓練設置成50輪,下圖展現的是每次的loss 和 validation loss。大家能看到validation loss在14輪開始就沒有顯著下降,很可能表明已經出現overfitting。

不過,此模型的目的是簡單的展示一個Seq2Seq模型

NLP-第十七期-神經網絡翻譯Seq2Seq代碼實踐 Keras

下期預告

好像Beam Search還沒完結


分享到:


相關文章: