NLP-第十七期-神经网络翻译Seq2Seq代码实践 Keras

背景

本系列从第十二期开启 神经网络翻译NMT及聊天机器人Chatbot 的模型,已经涉及Seq2Seq,Attention Mechanism,Beam Search 等模型。前期基本上都是从抽象的角度出发进行总结。

本期将给大家带来Seq2Seq模型代码的讲解,代码来来自于 Toward Datascience 的Ravindra Kompella。并加上自己的理解。

本期带来的模型是基础的Seq2Seq 模型,并不涉及Attention Mechanism。对于Seq2Seq 模型的抽象原理讲解,可以参考本系列第十三期。

Seq2Seq模型简介

Seq2Seq 模型其实就是 Encoder-Decoder模型 加上一个 循环神经网络。其思路是将 一段句子 encoder 成一个向量,再将此向量“解压”成目标语句。

关于此模型的优缺点和其他的理解,详细的可以参考本系列第十二期。

Seq2Seq训练

本次建立的模型将会基于下图进行讲解,

首先,我们拥有的数据集是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('')[0]

# Append '' for start of the sentence and '' to signify end of the sentence

fra_line = '' + str(lines[line]).split('')[1] + ''

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模型

下期预告

好像Beam Search还没完结

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181002A0BTMU00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券