之前总结过 RNNLM ,是一个SequenceModel,其结构类似如下:
这里面是一个一个的输出。我们如果以这种方式做机器翻译,每一个时刻输入一个词,相应的翻译一个词,显然这种一个一个单词的翻译方式不是很好,因为没有联系上下文进行翻译。我们希望先把一整句话喂给模型,然后模型在这一个整句的角度上来进翻译。这样翻译的效果更好。
所以本篇博文要总结的是Seq2Seq Model,给出一个完整的句子,能得出另外一个完整的句子。
下面我们以机器翻译来讲解下面几个要点。
其中 f1,f2,f3 是输入信息做完 embedding 后的矩阵,Encoder部分是一个两层的 LSTM 神经网络,这个神经网络不做任何输出,只输出最后一步的 h,c ,我们可以理解这个 h,c 是已经总结了的输入信息, Decoder部分 也是一个两层的 LSTM 神经网络,并且其隐藏层 h,c 的初始值为 Encoder 部分输出的 h,c ,然后在 Decoder 部分进行翻译。
注意在 Encoder 部分每一步并不预测任何东西,其初始的 h,c 为全零向量,并且与 Decoder 是完全不同的参数。
首先注意 Encoder 和 Decoder 部分都是两层的 LSTM 神经网络。回顾下 LSTM Cell 大致结构:
以及它的计算公式:
Encoder−Decoder 超参数
Encoder 部分参数
Decoder 部分参数
首先需要注意到模型训练和模型预测是两个不同的过程,在训练时,我们知道每一步真正的 reference ,而在预测时是不知道每一步的 reference 的。
在上图的网络结构中,都是以上一时刻真正的 reference 作为下一时刻的 input 来训练模型。
那么 train 出这样一个模型,应该如何进行预测呢?因为在预测阶段我们是不知道 reference 的,我们可以尝试这样做,把上一次的输出作为下一次的输入。
很显然,这样做的后果很严重:
一步错,步步错!
那么应如何解决上面这个问题呢?我们尝试这样做,现在假设语料库只有 A,B 两个 word ,那么:
我们看上图的 LSTM 结构,共有三个时间段,第一个时间段会输出两个单词 P(A),P(B) 的概率,并不真正的输出最大概率对应的 word 作为当时刻的输出,分别以 [A,B]T 作为下一个时刻的输入,然后得到这一时刻输出 P(A),P(B),P(A),P(B) 的概率矩阵,以此类推,直到最后我们可以得到输出是 AAA,AAB,ABA,ABB,..... 各个序列的概率,选择概率最大的作为真正的输出序列。
这里需要注意,在 Decoder 部分,第三个时间步处两个输入的 B 表示不同的含义,第一个 B 的前驱为 A ,第二个 B 的前驱为 B 。
这样我们可以计算出输出序列 P(AAA)=0.6∗0.4∗0.5=0.12,P(AAB)=0.6∗0.4∗0.5=0.12,P(ABA)=0.6∗0.6∗0.4=0.144.... 如此类推计算,可以计算出最大概率对应的序列,作为预测结果。
在语料库中的 words 很少的情况下,可以利用这样类似于穷举的方式来获得概率最大的那个序列作为预测结果,但是如果语料库中的 words 很多时,这种穷举的方式肯定就变得不可行了,那么这个时候应该如何做呢?
可以尝试这样做,例如语料库有3个 words ,我们可以设置 Beam size=2 ,也就是每次选择前一时刻输出概率最大的前2个 words 作为当前的输入。
这里需要注意,当对应输入是 a,b 时,输出最大概率的两个 word 为 b,c ,并且其前驱都是 a ,那么此时以 b 为前驱的就丢掉了。
当语料库中只有两个 words 时,取 Beam size=2 时,其过程如下:
可以以下面这张图更好的理解 Beam Search 过程:
注意在每个时间步时,可能有相同的 word 作为输入,但是他们的意义是不同的,其前驱不一样。
上面讲的传统的 Encoder−Decoder 神经网络结构在应对较短文本翻译时效果不错,但是随着文本长度的增加,其翻译效果会迅速的恶化。由此提出了 Attention 这种结构,使得模型能够学习如何对 input 和 output 进行对齐。
简单来说,例如将“我 爱 你”翻译成 "i love you" ,这里模型如何学习到如何将翻译出的 "i" 对齐到( attention ) 到”我“。
例如下图:
那么问题来了,如何让模型学习对其( Attention ) 呢?
在 attention 的原始论文中是这样说的:
这里我久不从数学公式角度来说明,只说下它的大致思路。
上图中上半部分为 Decoder ,其中 s 为其 hidden−states 输出信息, y 为其 output 。下半部分为 Encoder , X 为其 Input , h 为 hidden−states 。
假设在 t 时刻,其 Decoder 部分对应的 hidden−states 为 St ,这个时候,我们把 St 与 Encoder 部分的所有 hidden−state 信息做个相似度的计算,得出 at,1,at,2,at,3,... ,然后再把这些计算出来的相似度做个 softmax ,再进行如下计算:
将得出的 cj 作为 Decoder 部分的输入。
这样讲的估计有许多人没明白咋回事,为什么这样做就能 Attention 呢?
我觉得这篇原始论文讲的虽然详细但是不够直观。我引用下台大李宏毅教授所讲 attention 的 ppt 来详细进行讲解。
假设我们再 Encoder 部分输入“机器学习” 四个字,经过 word−Embedding 以后作为输入喂给一个 RNN ,然后经过隐藏层得出隐藏层信息 h1,h2,... ,这时候在 Decoder 部分的第一个时刻的 hidden−state 假设为 z0 , z0 的和 h1,h2,,, 进行相似度的计算,得出各个时刻的 a10,a20,... ,然后在 ai 与对应的 hi 相乘求和得到这 c0 ,其大致过程如下:
我们可以看出 encoder 和 decoder 是联合的进行训练,在训练过程中,在某个时刻模型会学习到当前应该 focus 到 input 的哪一部分,这体现在 a10,a20,... 不同的系数权重上, attention 就是在学习这些系数。
得出的 C0 作为 Decoder 的下一时刻的输入。后面的时刻同理。
其实对于 attention 没有固定的套路,例如 softmax 这一步不一定非要做,听说有人做实验发现不做 softmax 效果还好些。其变种有很多。