本文会首先介绍神经网络机器翻译(Neural Machine Translation )技术的原理,再介绍如何使用 TensorFlow NMT 训练一个中英翻译引擎。
一、Encoder -- Decoder模型的原理
Encoder-Decoder 模型是使用神经网络进行机器翻译的基本方法,一般也称作 Seq2Seq 模型 。原始的 N VS N RNN结构要求输入序列和输出序列等长,而Encoder-Decoder 模型可以有效地建模输入序列和输出不等长的问题 。 具体来说,它会先用一个 Encoder 将输入的序列编码为一个上下文向量 c, 再使用 Decoder对c进行解码,将之变为输出序列。对应到机器翻译问题中,输入的句子被 Encoder 编码为向量 c,c 中存储了神经网络对句子的理解,再利用 Decoder 解码 c,以生成翻译之后的句子 。
二、注意力机制
在 Encoder-Decoder 结构中, Encoder 把所高的输入序列都编码成一个统一的语义特征 c 再解码,因此, c 中必须包含原始序列中的所有信息,它的长度成了限制模型性能的瓶颈。如在机器翻译问题中 , 当被翻译的句子较长 时,一个 c可能无法存诸如此多的信息,翻译精度会下降 。注意力机制( Attention) 通过在每个时间输入不同的 c 来解决这个问题 。使用注意力机制后,每一个 c会自动选取与当前所要输出的 y最合适的上下文信息。
三、使用TensorFlow NMT 搭建神经网络翻译引擎
2017 年 7 月, Google 公司公布了基于 TensorFlow 构建的 NMT 项目,该项目采用了最新的深度学习技术,可以让每个人轻松地训练、自己的神经网络翻译引擎 。 NMT 项目支持基本的 Encoder-Decoder 结构,也支持注意力机制。
1、将越南语翻译为英语
(1)未使用注意力模型
TensorFlowNMT代码下载地址:https://github.com/tensorflow/nmt,运行命令下载越南语与英语的平行语料库:bash nmt/scripts/download_iwslt15.sh ./tmp/nmt-data,下载的文件将会保存在/tmp/nmt_data/目录下。利用这个语料库,就可以开始训练模型了,新建一个/tmp/nmt_model文件夹保存模型,训练模型命令如下:
python -m nmt.nmt
--src=vi # 源语言越南语
--tgt=en # 目标语言英语
--vocab_prefix=tmp/nmt-data/vocab # 词汇表
--train_prefix=tmp/nmt-data/train # 训练集
--dev_prefix=tmp/nmt-data/tst2012 # 验证集
--test_prefix=tmp/nmt-data/tst2013 # 测试集
--out_dir=tmp/nmt_model # 模型保存地址
--num_train_steps=12000
--steps_per_stats=100 # 每100步打印信息
--num_layers=2 # 使用两层LSTM
--num_units=128 # 隐藏单元个数
--drop_out=0.2
--metrics=bleu
深受版本不同的危害...
报错:AttributeError: module 'tensorflow.contrib.data' has no attribute 'Dataset',这是版本不同导致的问题,改为tf.data.TextLineDataset()即可。
报错:TypeError: map() got an unexpected keyword argument 'num_threads',解决方案:用到这两个参数num_threads、output_buffer_size的地方,把该参数全部去掉就可以。
报错:AttributeError: 'MapDataset' object has no attribute 'group_by_window',解决方案:将 batched_dataset = src_tgt_dataset.group_by_window(key_func=key_func, reduce_func=reduce_func, window_size=batch_size) 改为 batched_dataset = src_tgt_dataset.apply(tf.contrib.data.group_by_window( key_func=key_func, reduce_func=reduce_func, window_size=batch_size))即可。
报错:UnboundLocalError: local variable 'batched_dataset' referenced before assign,这是变量未定义就使用导致的错误,仔细检查一下定义和使用的地方,我的是代码对齐问题。
如何可使用训练好的模型对新的句子进行翻译?首先创建一个 /tmp/my_infer_file.vi 文件,并将测试集 /tmp/nmt_data/tst2013.vi 中的越南语句子复制一些到 /tmp/my一infer_file.vi里。执行命令:
python -m nmt.nmt
--out_dir=tmp/nmt_model
--inference_input_file=tmp/my_infer_file.vi
--inference_output_file=tmp/nmt_model/output_infer
(2)使用注意力模型
使用上述命令只是在训练基础的 Encoder-Decoder 模型 ,并没再加入注意力机制。在 TensorFlowNMT 中对模型加入注意力机制很简单,只需要使用--attention 具体指定一种注意力机制即可 。 此处一共提供了 4 种选顶 : bahdanau、 normed_bahdanau、 luong、 scaled_luong。运行命令进行训练和测试如下:
mkdir /tmp/nmt_attention_model
# 训练
python -m nmt.nmt
--attention=scaled_luong
--src=vi # 源语言越南语
--tgt=en # 目标语言英语
--vocab_prefix=tmp/nmt-data/vocab # 词汇表
--train_prefix=tmp/nmt-data/train # 训练集
--dev_prefix=tmp/nmt-data/tst2012 # 验证集
--test_prefix=tmp/nmt-data/tst2013 # 测试集
--out_dir=tmp/nmt_attention_model # 模型保存地址
--num_train_steps=12000
--steps_per_stats=100 # 每100步打印信息
--num_layers=2 # 使用两层LSTM
--num_units=128 # 隐藏单元个数
--drop_out=0.2
--metrics=bleu
# 测试
python -m nmt.nmt
--out_dir=tmp/nmt_attention_model
--inference_input_file=tmp/my_infer_file.vi
--inference_output_file=tmp/nmt_model/output_infer
四、TensorFlow NMT 源码简介
主要介绍词嵌入、 Encoder-Decoder 模型 、 注意力机制三部分的源码。
1、词嵌入
在 model.py 文件中,构建了基本的词嵌入及 Encoder-Decoder模型 。model.py下载地址:https://github.com/tensorflow/nmt/blob/master/nmt/model.py
embedding_encoder = tf.get_variable("embedding_encoder", [src_vocab_size, src_embed_size], dtype) # encoder_emb_lookup_fn 查找某个单词id对应的词嵌入向量 self.encoder_emb_inp = self.encoder_emb_lookup_fn(self.embedding_encoder, sequence)
2、Encoder
词嵌入之后得到新的输入 encoder_emb_inp, 它的形状为 (max_time,batch_size, embedding_size),它将被传入 Encoder中。
cell = self._build_encoder_cellencoder_cell = (hparams, num_layers,num_residual_layers) # encoder_outpus : [max_time, batch_size, num_units) # encoder_state: [batch size, num units) 相当于上下文表示向量c # 将新建的RNN展开时间维度 encoder_outputs, encoder_state = tf.nn.dynamic_rnn( cell, self.encoder_emb_inp, dtype=dtype, sequence_length=sequence_length, time_major=self.time_major, swap_memory=True)
3、Decoder
cell, decoder_initial_state = self._build_decoder_cell( hparams, encoder_outputs, encoder_state, iterator.source_sequence_length) # Helper helper = tf.contrib.seq2seq.TrainingHelper( decoder_emb_inp, iterator.target_sequence_length, time_major=self.time_major) # Decoder my_decoder = tf.contrib.seq2seq.BasicDecoder( cell, helper, decoder_initial_state,) # Dynamic decoding outputs, final_context_state, _ = tf.contrib.seq2seq.dynamic_decode( my_decoder, output_time_major=self.time_major, swap_memory=True, scope=decoder_scope)
4、注意力机制的 Encoder-Decoder 模型(attention model.py)
对原先的 decoder_cell 用 tf.contrib.seq2seq.AttentionWrapper 包装后, 得到新的 decoder cell 会自动具有注意力机制 。 使用 decoder_cell 对上下文进行解码的方法与之前一致 。
attention_mechanism = create_attention_mechanism(attention_option, num_units,memory,source_sequence_length) cell = tf.contrib.seq2seq.AttentionWrapper( cell, attention_mechanism, attention_layer_size=num_units, alignment_history=alignment_history, name="attention")
五、总结
本文介绍了基本RNN结构:Encoder-Decoder,以及他的改进——注意力机制。