Attention and Transformer

Attention

Seq2Seq模型

最初的用于机器翻译的Seq2Seq模型是由Encoder RNN和Decoder RNN组成的:

上图中,Encoder RNN的输入为源语言单词序列,为每次根据输入更新的隐藏状态向量,之后Encoder部分的最后一个隐藏状态作为Decoder的初始隐藏状态包含了输入句子的所有信息,通过它Decoder就知道了这句英语,然后Decoder模型与文本生成器的方式一步步的生成目标语言的单词。

从上述描述中可知Seq2Seq模型通过最后一个状态来记忆整个源语言句子的信息,这就导致该模型难以处理长的句子,Encoder的最后一个状态可能会漏掉一些信息,假如源语言句子中的某些单词被忘记了,Decoder就无从得知完整的句子,也就不可能产生正确的翻译。

从上诉图片中也可以证明我们之前的推测,在Seq2Seq模型结合Attention机制后这种情况就可以得到大大的缓解。

注:BLEU是衡量翻译的准确率,它有许多变体如BLEU-1用于衡量单词翻译的准确率,更高阶的BLEU可以衡量句子的流畅性

Attention改进Seq2Seq模型

Seq2Seq翻译模型加入Attention后的优缺点:

  • 加入Attention机制后能够大幅改善模型的性能
  • 使用了Attention机制后,Seq2Seq模型就不会遗漏源输入的细节
  • 在Attention机制作用下,Decoder部分就能知道该聚焦哪儿
  • 但是Attention机制也带来了更大的计算量

但Encoder对输入计算完成后,通过得到Decoder的初始状态输入为,同时Encoder所有时间步的隐藏状态都要保持下来,然后需要计算与每一个隐藏状态的相关性得到,通过下列公式计算:

有多种方法来计算这个相关性:

方法一(在原始的Attention论文中使用的):

该方法首先将进行拼接,然后与一个矩阵相乘,之后通过函数进行激活,将向量每个元素限制到(-1,1)之间,然后将激活后的向量与一个向量进行相乘得到,这里的向量和矩阵都是可以学习的参数,之后将进行Softmax操作正则化得到,这里得到的就作为隐藏状态与各个的相关权重系数。

方法二(Transformer使用的方法):

该方法的输入依旧是,之后它们分别与一个矩阵相乘做线性变化,得到两个向量,两个线性变换矩阵是学习得到的。第二部是计算的内积,因为有m个,所以内积输出也会得到m个,第三步与上个方法一样将通过Softmax进行正则化得到相关性权重系数。

根据上述得到的每个Encoder时间步隐藏状态的相关性权重系数与隐藏状态向量进行加权求和可以得到一个Context vector

每个向量与一个Decoder的状态向量对应。

回到Decoder部分,如何通过得到呢?原始的RNN通过下列公式进行迭代计算: 而引入Attention机制后的RNN计算方法如下: 然后得到的在类似于之前的步骤一样与Encoder的各个时间步的隐藏状态计算一个相关性权重系数,就可以得到,之后不断迭代通过得到,通过得到,不断迭代一直到结束。

时间复杂度

Attention的时间复杂度为,即输入序列长度输出序列长度。

Attention:权重可视化

上图展示了Decoder出来的每个单词与输入单词的相关性,连线越深表示联系越紧密。

Self-Attention

Attention不仅可以用于Seq2Seq RNN模型中,它可以用于所有的RNN模型中。Self-Attention模型最初的论文就是用在LSTM模型中的。下面以原始的RNN举例,介绍Self-Attention的工作机制。

首先对于一个RNN网络,初始的状态向量与Context Vector 都为0,然后通过与第一个输入计算,计算方法如何呢?普通RNN通过下列公式进行更新: 而使用Self-Attention机制的RNN通过另外一种方式进行更新:

唯一的区别是把换为。计算完后,通过当前时间步以及之前时间步隐藏状态的加权平均得到,由于=0所以,

然后通过输入计算得到隐藏状态。然后计算当前时间步的Context vector ,首先由当前隐藏状态与包含当前时间步及以前时间步的隐藏状态进行比较得到一个相关性权重系数:

然后就通过隐藏状态的加权求和得到。

之后不断地重复这个过程直到结束。

Self-Attention总结

使用了Self-Attention后,RNN可以避免遗忘,另外还可以帮助RNN关注与当前输入最相关的部分。

上图是论文中的原图,红色的代表输入,紫色代表与当前输入最相关的词语。

Transformer Model: Attention without RNN

Attention

之前介绍的Seq2Seq模型中,使用了Attention层进行改善。Seq2Seq模型可分为Encoder和Decoder部分,Encoder的输入为m个向量,Encoder的最后一个隐藏状态向量作为Decoder的初始状态,再加入Attention层后,每个Decoder的输入对应一个Context Vector ,而它是通过下列公式进行先计算一个权重参数,然后通过权重参数对所有的Encoder隐藏状态进行加权求和得到的:

其中align()函数的原理如下:

  • 首先计算key和query向量:

  • 然后计算权重:

  • 还需要计算一个value向量: 上述线性映射矩阵都是可学习的参数。

有了query、key和value向量后,通过将value与权重参数进行加权求和得到Context Vector

现在的问题是如何在这个Seq2Seq模型中移除RNN层而只保留Attention层呢?

首先我们考虑Seq2Seq模型的输入和输出:

上图中是Seq2Seq模型中Encoder的输入,而右侧是Deocder的输入。

通过Encoder部分的输入我们可以得到Key和Value:

所以,通过Encoder的输入就可以得到全部的key和value。

之后通过Decoder的输入可以得到所有的query:

然后通过得到的所有key和value以及每个query得到相应的权重向量

然后通过权重系数得到相应的Context Vector

每个query得到一个权重系数向量,然后得到相应的Conetxt Vector直到结束,最后Attention输出的就是所有的Context Vector

有个疑问是这里的是怎么得到的呢?

拿生成的过程举例,首先通过得到相应的query,然后通过query得到相应的Context Vector,之后对Context Vector进行Softmax操作得到一个分布,之后对进行采样就可以得到了。

之后可以将整个结构看出一个Attention层:

这个Attention层的输入为,输出为所有的Context Vector,三个线性投影矩阵为可学习的参数。

Self-Attention

self-attention取代rnn的过程与attention的过程十分类似,略有不同的是self-attention的输入两个都是

其详细过程为,通过输入得到Query、Key和Value:

然后通过所有的Key和当前的query计算得到一个权重参数向量,与此类似逐步得到所有的相应的权重向量:

然后各个权重向量与所有的value进行计算得到当前的Context Vector

与此类似可以得到所有的Context Vector

至此,我们可以将self-attention看作一个层,其两个输入都是,输出是,三个线性投影向量都是可学习的参数

Transformer Model: From Shallow to Deep

本节主要讲如何由简单的Attention层和Self-Attention层搭建起简易的Transfomer骨架。

首先对于一个Self-Attention层,我们可以称之为“单头自注意力层”,我们可以使用l个“单头自注意力层”进行堆叠得到多头自注意力层:

对于其中的每个自注意力层,它们的参数相互不共享(参数即三个线性变换矩阵),同时把这些自注意力层的输出也堆叠起来就可以的得到的输出:

而多头注意力层的构造方式也类似将多个注意力层进行堆叠以及将输出也进行拼接。

对于多头自注意力层的输出,将其通过一个全连接层并使用ReLU激活函数进行激活得到新的输出

上图的全连接层参数共享。

为了使网络更深,我们可以以上面的方式堆叠多层:

如果将一个多头自注意力层与一个全连接层合起来看成一个Block,那么这个Block的输入是512×m(m为输入序列长度),输出也是512×m

最初的Transformer一共使用了6个Block:

然后是对注意力层进行堆叠,首先将输入通过一个6个Block的Encoder模块得到矩阵:

然后将Decoder的输出通过多头自注意力层得到输出矩阵

然后将矩阵和矩阵作为输入通过一个多头注意力层,得到z矩阵:

之后对于每个向量通过全连接层得到矩阵:

这里的全连接层的参数是共享的。

这样就可以组成一个Decoder的block:

然后通过Encoder Block和Decoder Block组成Transformer结构:

首先是Encoder网络:

然后将Encoder网络的输出作为Decoder网络的输入,每个Decoder Block都会使用到Encoder网络的输出:

这样就组成了基本的Transformer结构。