初步了解 RNN, Seq2Seq, Attention 注意力机制

@TOC
</font>
<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">
循环神经网络 RNN 结构被广泛应用于自然语言处理、机器翻译、语音识别、文字识别等方向。本文主要介绍经典的 RNN 结构,以及 RNN 的变种(包括 Seq2Seq 结构和 Attention 机制)。希望这篇文章能够帮助初学者更好地入门。
1.经典的 RNN 结构

这就是最经典的 RNN 结构,它的输入是:

输出为:

也就是说,输入和输出序列必有相同的时间长度!








2.Sequence to Sequence 模型

在 Seq2Seq 结构中,编码器 Encoder 把所有的输入序列都编码成一个统一的语义向量 Context,然后再由解码器 Decoder 解码。在解码器 Decoder 解码的过程中,不断地将前一个时刻 t-1 的输出作为后一个时刻 **t **的输入,循环解码,直到输出停止符为止。




3.Embedding
还有一点细节,就是如何将前一时刻输出类别 index(数值)送入下一时刻输入(向量)进行解码。假设每个标签对应的类别 index 如下:






4.Seq2Seq 训练问题


5.Attention 注意力机制

在 Seq2Seq 结构中,encoder 把所有的输入序列都编码成一个统一的语义向量 Context,然后再由 Decoder 解码。由于 context 包含原始序列中的所有信息,它的长度就成了限制模型性能的瓶颈。如机器翻译问题,当要翻译的句子较长时,一个 Context 可能存不下那么多信息,就会造成精度的下降。除此之外,如果按照上述方式实现,只用到了编码器的最后一个隐藏层状态,信息利用率低下。
所以如果要改进 Seq2Seq 结构,最好的切入角度就是:利用 Encoder 所有隐藏层状态 h(t)解决 Context 长度限制问题。

上下文 context 表示成如下的方式(h 的加权平均):

那么权重 alpha(attention weight)可表示成 Q 和 K 的乘积,小 h 即 V(下图中很清楚的看出,Q 是大 H,K 和 V 是小 h):


6.乘法 VS 加法 attention
加法注意力:
还是以传统的 RNN 的 seq2seq 问题为例子,加性注意力是最经典的注意力机制,它使用了有一个隐藏层的前馈网络(全连接)来计算注意力分配:

乘法注意力:
就是常见的用乘法来计算 attention score:

乘法注意力不用使用一个全连接层,所以空间复杂度占优;另外由于乘法可以使用优化的矩阵乘法运算,所以计算上也一般占优。论文中的乘法注意力除了一个 scale factor:

论文中指出当 dk 比较小的时候,乘法注意力和加法注意力效果差不多;但当 d_k 比较大的时候,如果不使用 scale factor,则加法注意力要好一些,因为乘法结果会比较大,容易进入 softmax 函数的“饱和区”,梯度较小。
7.Luong Attention(简单了解)



注:这里就是把 Decoder 中的每一次的输入:上一层的输出 y 换成了 Attention。
8.Self-Attention

9.《Attention is all you need》
9.1 encoder

注: 词向量加上了 positional embedding,即给位置 1,2,3,4...n 等编码(也用一个 embedding 表示)。然后在编码的时候可以使用正弦和余弦函数,使得位置编码具有周期性,并且有很好的表示相对位置的关系的特性(对于任意的偏移量 k,PE[pos+k]可以由 PE[pos]表示):

输入的序列长度是 n,embedding 维度是 d,所以输入是 n*d 的矩阵,N=6,6 个重复一样的结构,由两个子层组成:子层 1:
Multi-head self-attention
残余连接和 LN: Output = LN (x+sublayer(x))
子层 2:
Position-wise fc 层(跟卷积很像):对 n*d 的矩阵的每一行进行操作(相当于把矩阵每一行铺平,接一个 FC),同一层的不同行 FC 层用一样的参数,不同层用不同的参数(对于全连接的节点数目,先从 512 变大为 2048,再缩小为 512),这里的 max 表示使用 relu 激活函数
残差连接(待)
输出:
整个 encoder 的输出也是 n*d 的矩阵
9.2 Decoder

输入:假设已经翻译出 k 个词,向量维度还是 d,同样使用 N=6 个重复的层,依然使用残余连接和 LN3 个子层,比 encoder 多一个 attention 层,是 Decoder 端去 attend encoder 端的信息的层(待)Sub-L1:
self-attention,同 encoder,但要 Mask 掉未来的信息,得到 k*d 的矩阵 (这个暂且不懂代码实现)
Sub-L2:
和 encoder 做 attention 的层,输出 k*d 的矩阵,这里就不是 self-Attention 了。
Sub-L3:
全连接层,输出 k*d 的矩阵,用第 k 行去预测输出 y
10.mutli-head attention


获取每个子任务的 Q、K、V:
通过全连接进行线性变换映射成多个 Q、K、V,线性映射得到的结果维度可以不变、也可以减少(类似降维)
或者通过 Split 对 Q、K、V 进行划分(分段)

如果采用线性映射的方式,使得维度降低;或者通过 split 的方式使得维度降低,那么多个 head 做 attention 合并起来的复杂度和原来一个 head 做 attention 的复杂度不会差多少,而且多个 head 之间做 attention 可以并行。
版权声明: 本文为 InfoQ 作者【Studying_swz】的原创文章。
原文链接:【http://xie.infoq.cn/article/6ea6027cbd594aae467c5340d】。文章转载请联系作者。
评论