论文链接:Neural Machine Translation by Jointly Learning to Align and Translate
这是介绍Seq2Seq系列的第三篇文章,主要讲带有attention机制的Seq2Seq模型。
首先,作者回顾了一下RNN Encoder-Decoder模型:
就不展开了,列出上面的公式是为了和attention的机制比较,注意前两个公式是Encoder部分的,后两个公式是Decoder部分。
Attention机制:
ci 被称作context vector, 取决于annotations序列 h1,...,hTx (即Encoder的隐层状态序列)。
上论文中的图:
图片中Encoder采用的RNN是双向的RNN。
context vector的计算公式是:
其内在的想法是,当前decoder的输出,与输入序列是相关的,但是与每一部分的相关程度并不一样。权值满足 ∑Txj=1αij=1 。 (h1,...,hTx) 表征的是输入序列。
α 既然表征的是当前输出与输入序列各个元素的相关程度,那么它肯定是与当前decoder的隐层状态以及annotation相关:
其中 a(.) 是非线性函数(请注意,其实一个神经网络也是一个输入关于输出的非线性函数)。
α 是归一化的 eij ,归一化的方式是softmax:
先停下来总结一下:
带Attention的RNN的decoder部分的输出计算公式为
g(yi−1,si,ci)
,隐层计算公式为
si=f(si−1,yi−1,ci)
(
yi−1
是上一时刻的输出,下一时刻的输入,这是Seq2Seq模型的特点,请记住。),相比普通的RNN多出来的是
ci
。
当翻译句子”the cat on the mat”(输入序列),下一时刻的decode希望输出cat的法语单词,这时候如果能够用到cat这个单词对应的word embedding(指输入cat时,encoder的隐层状态向量),而不是整个序列经过编码后得到的隐层状态要更好一点。这个是我理解的attention的
ci
与Seq2Seq中将整个输入序列编码后得到的隐层状态
c
的区别。
attention只是(或者说 主要,因为
我个人偏向的理解是attention只是用到了输入序列的局部信息,因为
继续
在Encoder部分,作者使用的是双向的RNN(bidirectional RNN),这种RNN同时将输入序列以正向 和 反向的方式输入到Encoder中,很多人表示这种做法比单向的RNN要好。
上面是正向和反向Encoder得到的隐层状态序列,最终的隐层状态序列处理方法也很简单:
hj=[hTj−→;hTj←−]T
把向量连接起来组成一个维度更大的向量。
基本模型到此就完了。
这篇文章很好的一点是在实验部分很详细地讲述了模型的训练细节:
比如mini batch, batch size取80个句子,
句子最大长度 30,50 (两种)
隐层单元取1000(居然不是1024 -_-)
随机低度下降 使用Adadelta方法(可以说是很详细了)
等等。
另外补充一个东西:
尽管我们说在Decoder端,上一时刻是输出是下一时刻的输入,这只是在测试和使用模型进行生成任务(比如翻译)时成立。但是在监督训练时,由于真实的label是知道的,所以Decoder的每一时刻的输入都是由label来决定(也就是真实的译文)。
此外,在使用模型进行翻译时,每一时刻的输出也不一定取每一时刻的概率最大值,而一般使用Beam Search技术(一种启发式算法,这部分有时间再补充)。
理由是最终序列要保证
p(y1,...yt)=∏Tt=1p(yt|y1,...,yt−1)
(每一时刻取值概率的乘积)是最大的,然而,使
p(yt|y1,...,yt−1)
最大的
yt
并不能最后的概率积保证最大。比如(0.5, 0.2, 0.3)和(0.2, 0.6, 0.7)尽管在前一时刻0.5大于0.2但不能保证最终的概率积保证最大。
在文章的附录部分,对于带attention的RNN有详细的公式推导,很值得一读。限于个人水平以及时间关系,就不贴出来了。
有时间的话,我想梳理一下曾经看过的TensorFlow的tf.contrib.legacy_seq2seq部分的代码。算作TO DO LIST吧。
本文完