未验证 提交 db19fac6 编写于 作者: G Guo Sheng 提交者: GitHub

Update machine translation in book for 1.8 (#2121)

上级 c27a0a2e
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
### 说明 ### 说明
1. 硬件要求 本文可支持在CPU、GPU下运行 1. 硬件要求 本文可支持在CPU、GPU下运行
2. 对docker file cuda/cudnn的支持 如果您使用了本文配套的docker镜像,请注意:该镜像对GPU的支持仅限于CUDA 8,cuDNN 5 2. 对docker file cuda/cudnn的支持 如果您使用了本文配套的docker镜像,请注意:该镜像对GPU的支持仅限于CUDA 8,cuDNN 5
3. 文档中代码和seq2seq.py不一致的问题 请注意:为使本文更加易读易用,我们拆分、调整了seq2seq.py的代码并放入本文。本文中代码与seq2seq.py的运行结果一致,如希望直接看到训练脚本输出效果,可运行[seq2seq.py](https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/seq2seq.py) 3. 文档中代码和seq2seq.py不一致的问题 请注意:为使本文更加易读易用,我们拆分、调整了seq2seq.py的代码并放入本文。本文中代码与seq2seq.py的运行结果一致,如希望直接看到训练脚本输出效果,可运行[seq2seq.py](https://github.com/PaddlePaddle/FluidDoc/blob/develop/doc/fluid/user_guides/nlp_case/machine_translation/seq2seq.py)
## 背景介绍 ## 背景介绍
...@@ -436,15 +436,16 @@ def loss_func(logits, label, trg_sequence_length): ...@@ -436,15 +436,16 @@ def loss_func(logits, label, trg_sequence_length):
return avg_cost return avg_cost
def optimizer_func(): def optimizer_func():
# 设置梯度裁剪 # 定义梯度裁剪策略
fluid.clip.set_gradient_clip( clip = fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0)
clip=fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0))
# 定义先增后降的学习率策略 # 定义先增后降的学习率策略
lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim, 1000) lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim, 1000)
# 定义优化器
return fluid.optimizer.Adam( return fluid.optimizer.Adam(
learning_rate=lr_decay, learning_rate=lr_decay,
regularization=fluid.regularizer.L2DecayRegularizer( regularization=fluid.regularizer.L2DecayRegularizer(
regularization_coeff=1e-4)) regularization_coeff=1e-4),
grad_clip=clip)
``` ```
## 训练模型 ## 训练模型
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
### 说明 ### 说明
1. 硬件要求 本文可支持在CPU、GPU下运行 1. 硬件要求 本文可支持在CPU、GPU下运行
2. 对docker file cuda/cudnn的支持 如果您使用了本文配套的docker镜像,请注意:该镜像对GPU的支持仅限于CUDA 8,cuDNN 5 2. 对docker file cuda/cudnn的支持 如果您使用了本文配套的docker镜像,请注意:该镜像对GPU的支持仅限于CUDA 8,cuDNN 5
3. 文档中代码和seq2seq.py不一致的问题 请注意:为使本文更加易读易用,我们拆分、调整了seq2seq.py的代码并放入本文。本文中代码与seq2seq.py的运行结果一致,如希望直接看到训练脚本输出效果,可运行[seq2seq.py](https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/seq2seq.py)。 3. 文档中代码和seq2seq.py不一致的问题 请注意:为使本文更加易读易用,我们拆分、调整了seq2seq.py的代码并放入本文。本文中代码与seq2seq.py的运行结果一致,如希望直接看到训练脚本输出效果,可运行[seq2seq.py](https://github.com/PaddlePaddle/FluidDoc/blob/develop/doc/fluid/user_guides/nlp_case/machine_translation/seq2seq.py)。
## 背景介绍 ## 背景介绍
...@@ -94,7 +94,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN ...@@ -94,7 +94,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN
- 重置门(reset gate):如果重置门关闭,会忽略掉历史信息,即历史不相干的信息不会影响未来的输出。 - 重置门(reset gate):如果重置门关闭,会忽略掉历史信息,即历史不相干的信息不会影响未来的输出。
- 更新门(update gate):将LSTM的输入门和遗忘门合并,用于控制历史信息对当前时刻隐层输出的影响。如果更新门接近1,会把历史信息传递下去。 - 更新门(update gate):将LSTM的输入门和遗忘门合并,用于控制历史信息对当前时刻隐层输出的影响。如果更新门接近1,会把历史信息传递下去。
<p align="center"> <p align="center">
<img src="image/gru.png" width=700><br/> <img src = "https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/image/gru.png?raw=true" width="700"><br/>
图2. GRU(门控循环单元) 图2. GRU(门控循环单元)
</p> </p>
...@@ -126,11 +126,11 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN ...@@ -126,11 +126,11 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN
编码阶段分为三步: 编码阶段分为三步:
1. one-hot vector表示:将源语言句子$x=\left \{ x_1,x_2,...,x_T \right \}$的每个词$x_i$表示成一个列向量$w_i\epsilon \left \{ 0,1 \right \}^{\left | V \right |},i=1,2,...,T$。这个向量$w_i$的维度与词汇表大小$\left | V \right |$ 相同,并且只有一个维度上有值1(该位置对应该词在词汇表中的位置),其余全是0。 1. one-hot vector表示:将源语言句子$x = \left(x_1,x_2,...,x_T\right)$的每个词$x_i$表示成一个列向量$w_i$。这个向量$w_i$的维度与词汇表大小$\left | V \right |$ 相同,并且只有一个维度上有值1(该位置对应该词在词汇表中的位置),其余全是0。
2. 映射到低维语义空间的词向量:one-hot vector表示存在两个问题,1)生成的向量维度往往很大,容易造成维数灾难;2)难以刻画词与词之间的关系(如语义相似性,也就是无法很好地表达语义)。因此,需再one-hot vector映射到低维的语义空间,由一个固定维度的稠密向量(称为词向量)表示。记映射矩阵为$C\epsilon R^{K\times \left | V \right |}$,用$s_i=Cw_i$表示第$i$个词的词向量,$K$为向量维度。 2. 映射到低维语义空间的词向量:one-hot vector表示存在两个问题,1)生成的向量维度往往很大,容易造成维数灾难;2)难以刻画词与词之间的关系(如语义相似性,也就是无法很好地表达语义)。因此,需再one-hot vector映射到低维的语义空间,由一个固定维度的稠密向量(称为词向量)表示。记映射矩阵为$C\epsilon R^{K\times \left | V \right |}$,用$s_i=Cw_i$表示第$i$个词的词向量,$K$为向量维度。
3. 用RNN编码源语言词序列:这一过程的计算公式为$h_i=\varnothing _\theta \left ( h_{i-1}, s_i \right )$,其中$h_0$是一个全零的向量,$\varnothing _\theta$是一个非线性激活函数,最后得到的$\mathbf{h}=\left \{ h_1,..., h_T \right \}$就是RNN依次读入源语言$T$个词的状态编码序列。整句话的向量表示可以采用$\mathbf{h}$在最后一个时间步$T$的状态编码,或使用时间维上的池化(pooling)结果。 3. 用RNN编码源语言词序列:这一过程的计算公式为$h_i=\phi_{\theta} \left ( h_{i-1}, s_i \right )$,其中$h_0$是一个全零的向量,$\phi _{\theta}$是一个非线性激活函数,最后得到的$\mathbf{h}=\left(h_1,..., h_T \right)$就是RNN依次读入源语言$T$个词的状态编码序列。整句话的向量表示可以采用$\mathbf{h}$在最后一个时间步$T$的状态编码,或使用时间维上的池化(pooling)结果。
第3步也可以使用双向循环神经网络实现更复杂的句编码表示,具体可以用双向GRU实现。前向GRU按照词序列$(x_1,x_2,...,x_T)$的顺序依次编码源语言端词,并得到一系列隐层状态$(\overrightarrow{h_1},\overrightarrow{h_2},...,\overrightarrow{h_T})$。类似的,后向GRU按照$(x_T,x_{T-1},...,x_1)$的顺序依次编码源语言端词,得到$(\overleftarrow{h_1},\overleftarrow{h_2},...,\overleftarrow{h_T})$。最后对于词$x_i$,通过拼接两个GRU的结果得到它的隐层状态,即$h_i=\left [ \overrightarrow{h_i^T},\overleftarrow{h_i^T} \right ]^{T}$。 第3步也可以使用双向循环神经网络实现更复杂的句编码表示,具体可以用双向GRU实现。前向GRU按照词序列$(x_1,x_2,...,x_T)$的顺序依次编码源语言端词,并得到一系列隐层状态$(\overrightarrow{h_1},\overrightarrow{h_2},...,\overrightarrow{h_T})$。类似的,后向GRU按照$(x_T,x_{T-1},...,x_1)$的顺序依次编码源语言端词,得到$(\overleftarrow{h_1},\overleftarrow{h_2},...,\overleftarrow{h_T})$。最后对于词$x_i$,通过拼接两个GRU的结果得到它的隐层状态,即$h_i=\left [ \overrightarrow{h_i^T},\overleftarrow{h_i^T} \right ]^{T}$。
<div align="center"> <div align="center">
...@@ -149,7 +149,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN ...@@ -149,7 +149,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN
其中$\phi _{\theta '}$是一个非线性激活函数;$c$是源语言句子的上下文向量,在不使用注意力机制时,如果[编码器](#编码器)的输出是源语言句子编码后的最后一个元素,则可以定义$c=h_T$;$u_i$是目标语言序列的第$i$个单词,$u_0$是目标语言序列的开始标记`<s>`,表示解码开始;$z_i$是$i$时刻解码RNN的隐层状态,$z_0$是一个全零的向量。 其中$\phi _{\theta '}$是一个非线性激活函数;$c$是源语言句子的上下文向量,在不使用注意力机制时,如果[编码器](#编码器)的输出是源语言句子编码后的最后一个元素,则可以定义$c=h_T$;$u_i$是目标语言序列的第$i$个单词,$u_0$是目标语言序列的开始标记`<s>`,表示解码开始;$z_i$是$i$时刻解码RNN的隐层状态,$z_0$是一个全零的向量。
1. 将$z_{i+1}$通过`softmax`归一化,得到目标语言序列的第$i+1$个单词的概率分布$p_{i+1}$。概率分布公式如下: 2. 将$z_{i+1}$通过`softmax`归一化,得到目标语言序列的第$i+1$个单词的概率分布$p_{i+1}$。概率分布公式如下:
<div align="center"> <div align="center">
<img src="https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/image/probability_formula.png?raw=true" width="400"><br/> <img src="https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/image/probability_formula.png?raw=true" width="400"><br/>
...@@ -157,9 +157,9 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN ...@@ -157,9 +157,9 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN
其中$W_sz_{i+1}+b_z$是对每个可能的输出单词进行打分,再用softmax归一化就可以得到第$i+1$个词的概率$p_{i+1}$。 其中$W_sz_{i+1}+b_z$是对每个可能的输出单词进行打分,再用softmax归一化就可以得到第$i+1$个词的概率$p_{i+1}$。
1. 根据$p_{i+1}$和$u_{i+1}$计算代价。 3. 根据$p_{i+1}$和$u_{i+1}$计算代价。
2. 重复步骤1~3,直到目标语言序列中的所有词处理完毕。 4. 重复步骤1~3,直到目标语言序列中的所有词处理完毕。
机器翻译任务的生成过程,通俗来讲就是根据预先训练的模型来翻译源语言句子。生成过程中的解码阶段和上述训练过程的有所差异,具体介绍请见[柱搜索算法](#柱搜索算法)。 机器翻译任务的生成过程,通俗来讲就是根据预先训练的模型来翻译源语言句子。生成过程中的解码阶段和上述训练过程的有所差异,具体介绍请见[柱搜索算法](#柱搜索算法)。
...@@ -188,7 +188,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN ...@@ -188,7 +188,7 @@ GRU\[[2](#参考文献)\]是Cho等人在LSTM上提出的简化版本,也是RNN
其中,$align$可以看作是一个对齐模型,用来衡量目标语言中第$i$个词和源语言中第$j$个词的匹配程度。具体而言,这个程度是通过解码RNN的第$i$个隐层状态$z_i$和源语言句子的第$j$个上下文片段$h_j$计算得到的。传统的对齐模型中,目标语言的每个词明确对应源语言的一个或多个词(hard alignment);而在注意力模型中采用的是soft alignment,即任何两个目标语言和源语言词间均存在一定的关联,且这个关联强度是由模型计算得到的实数,因此可以融入整个NMT框架,并通过反向传播算法进行训练。 其中,$align$可以看作是一个对齐模型,用来衡量目标语言中第$i$个词和源语言中第$j$个词的匹配程度。具体而言,这个程度是通过解码RNN的第$i$个隐层状态$z_i$和源语言句子的第$j$个上下文片段$h_j$计算得到的。传统的对齐模型中,目标语言的每个词明确对应源语言的一个或多个词(hard alignment);而在注意力模型中采用的是soft alignment,即任何两个目标语言和源语言词间均存在一定的关联,且这个关联强度是由模型计算得到的实数,因此可以融入整个NMT框架,并通过反向传播算法进行训练。
<p align="center"> <p align="center">
<img src="image/decoder_attention.png" width=500><br/> <img src = "https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/image/decoder_attention.png?raw=true" width="500"><br/>
图6. 基于注意力机制的解码器 图6. 基于注意力机制的解码器
</p> </p>
...@@ -478,15 +478,16 @@ def loss_func(logits, label, trg_sequence_length): ...@@ -478,15 +478,16 @@ def loss_func(logits, label, trg_sequence_length):
return avg_cost return avg_cost
def optimizer_func(): def optimizer_func():
# 设置梯度裁剪 # 定义梯度裁剪策略
fluid.clip.set_gradient_clip( clip = fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0)
clip=fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0))
# 定义先增后降的学习率策略 # 定义先增后降的学习率策略
lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim, 1000) lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim, 1000)
# 定义优化器
return fluid.optimizer.Adam( return fluid.optimizer.Adam(
learning_rate=lr_decay, learning_rate=lr_decay,
regularization=fluid.regularizer.L2DecayRegularizer( regularization=fluid.regularizer.L2DecayRegularizer(
regularization_coeff=1e-4)) regularization_coeff=1e-4),
grad_clip=clip)
``` ```
## 训练模型 ## 训练模型
...@@ -650,7 +651,7 @@ for data in loader(): ...@@ -650,7 +651,7 @@ for data in loader():
```txt ```txt
Original sentence: Original sentence:
A man in an orange hat starring at something . A man in an orange hat starring at something .
Translated score and sentence: Translated sentence:
Ein Mann mit einem orangen Schutzhelm starrt auf etwas . Ein Mann mit einem orangen Schutzhelm starrt auf etwas .
Ein Mann mit einem gelben Schutzhelm starrt auf etwas . Ein Mann mit einem gelben Schutzhelm starrt auf etwas .
Ein Mann mit einem gelben Schutzhelm starrt etwas an . Ein Mann mit einem gelben Schutzhelm starrt etwas an .
......
...@@ -216,14 +216,14 @@ def loss_func(logits, label, trg_sequence_length): ...@@ -216,14 +216,14 @@ def loss_func(logits, label, trg_sequence_length):
def optimizer_func(): def optimizer_func():
fluid.clip.set_gradient_clip(clip=fluid.clip.GradientClipByGlobalNorm( clip = fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0)
clip_norm=5.0))
lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim, lr_decay = fluid.layers.learning_rate_scheduler.noam_decay(hidden_dim,
1000) 1000)
return fluid.optimizer.Adam( return fluid.optimizer.Adam(
learning_rate=lr_decay, learning_rate=lr_decay,
regularization=fluid.regularizer.L2DecayRegularizer( regularization=fluid.regularizer.L2DecayRegularizer(
regularization_coeff=1e-4)) regularization_coeff=1e-4),
grad_clip=clip)
def inputs_generator(batch_size, pad_id, is_train=True): def inputs_generator(batch_size, pad_id, is_train=True):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册