自然语言处理 - Self-attention 到 Transformer

先修知识:

在这里插入图片描述


1. 引言

读完“先修知识”一栏中的文章之后,你会发现:RNN由于其顺序结构训练速度常常受到限制,既然Attention模型本身可以看到全局的信息, 那么一个自然的疑问是我们能不能去掉RNN结构,仅仅依赖于Attention模型呢,这样我们可以使训练并行化,同时拥有全局信息?
这一篇就主要根据谷歌的这篇 Attention is All you need 论文来回顾一下仅依赖于Attention机制的Transformer架构。

2. Transformer总体结构

Transformer的结构也采用了 Encoder-Decoder 架构。但其结构更加复杂,论文中Encoder层由6个Encoder堆叠在一起,Decoder层也一样。
在这里插入图片描述
每一个Encoder和Decoder的内部结构如下图:
在这里插入图片描述

  • Encoder包含两层,一个Self-attention层(Multi-Head Attention)和一个前馈神经网络层(feed forward),Self-attention层能帮助当前节点不仅仅只关注当前的词,从而能获取到上下文的语义。
  • Decoder也包含Encoder提到的两层网络,但是在这两层中间还有一层Attention层,帮助当前节点获取到当前需要关注的重点内容。

2.1 Encoder层详细说明

首先,模型需要对输入的数据进行一个embedding操作,并输入到Encoder层,Self-attention处理完数据后把数据送给前馈神经网络,前馈神经网络的计算可以并行,得到的输出会输入到下一个Encoder。大致结构如下:
在这里插入图片描述
x 1 , x 2 x_1, x_2 x1,x2就是embedding, z 1 , z 2 z_1, z_2 z1,z2是经过self-attention之后的输出, r 1 , r 2 r_1, r_2 r1,r2是经过feed forward网络之后的输出,它们会被输入到下一层encoder中去。

2.1.1 Embedding层

Transformer模型中缺少一种解释输入序列中单词顺序的方法,它跟序列模型还不一样。为了处理这个问题,Transformer给Encoder层和Decoder层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,这个向量采用了一种很独特的方法来让模型学习到这个值,这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。
所以,最终一个词的embedding,就是它的语义信息embedding(预训练模型查表)+序列信息embedding (positional encoding):
在这里插入图片描述

2.1.2 Self-attention层

让我们从宏观视角看自注意力机制,精炼一下它的工作原理。

例如,下列句子是我们想要翻译的输入句子:

The animal didn't cross the street because **it** was too tired

这个“it”在这个句子是指什么呢?它指的是street还是这个animal呢?这对于人类来说是一个简单的问题,但是对于算法则不是。

当模型处理这个单词“it”的时候,自注意力机制会允许“it”与“animal”建立联系。

随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。

在这里插入图片描述
如上图所示,当我们在编码器#5(栈中最上层编码器)中编码“it”这个单词的时,注意力机制的部分会去关注“The Animal”,将它的表示的一部分编入“it”的编码中。接下来我们看一下Self-Attention详细的处理过程。

(1) 首先,对于输入序列的每个单词,它都有三个向量编码,分别为:Query、Key、Value。这三个向量是用embedding向量与三个矩阵( W Q , W K , W V W^Q, W^K, W^V WQ,WK,WV )相乘得到的结果。这三个矩阵的值在BP的过程中会一直进行更新。

(2) 第二步计算Self-Attention的分数值,该分数值决定了当我们在某个位置encode一个词时,对输入句子的其他部分的关注程度。这个分数值的计算方法是Query与Key做点乘。以下图为例,假设我们在为这个例子中的第一个词“Thinking”计算自注意力向量,我们需要拿输入句子中的每个单词对“Thinking”打分。这些分数决定了在编码单词“Thinking”的过程中重视句子其它部分的程度。
在这里插入图片描述
(3) 再对每个分数做softmax:
在这里插入图片描述
(4) 下一步就是把每个Value向量和softmax得到的值进行相乘,然后对相乘的值进行相加,得到的结果即是一个词语的self-attention embedding值。
在这里插入图片描述
这样,自注意力的计算就完成了。得到的向量就可以传递给前馈神经网络。

2.1.3 Multi-Headed Attention

通过增加一种叫做“多头”注意力(“multi-headed”attention)的机制,论文进一步完善了自注意力层。

接下来我们将看到,对于“多头”注意力机制,我们有多个Query/Key/Value权重矩阵集 W Q , W K , W V W^Q, W^K, W^V WQ,WK,WV( Transformer使用八个注意力头)。
在这里插入图片描述
现在对于每一个词语,我们有了八个向量 z 0 , . . . . , z 7 z_0,....,z_7 z0,....,z7,它们分别由八个head产生。但是对于下一个feed-forward层,我们应该把每个词语都用一个向量来表示。所以下一步,我们需要把这八个向量压缩成一个向量。

可以直接把这些矩阵拼接在一起,然后用一个附加的权重矩阵 W O W^O WO与它们相乘。
在这里插入图片描述
这几乎就是多头自注意力的全部。这确实有好多矩阵,我们试着把它们集中在一个图片中,这样可以一眼看清。
在这里插入图片描述
既然我们已经摸到了注意力机制的这么多“头”,那么让我们重温之前的例子,看看我们在例句中编码“it”一词时,不同的注意力“头”集中在哪里:
在这里插入图片描述
当我们编码“it”一词时,一个注意力头集中在“animal”上,而另一个则集中在“tired”上,从某种意义上说,模型对“it”一词的表达在某种程度上是“animal”和“tired”的代表。

2.1.4 The Residuals and Layer normalization

在继续进行下去之前,我们需要提到一个encoder中的细节:在每个encoder中都有一个残差连接,并且都跟随着一个Layer Normalization(层-归一化)步骤。
在这里插入图片描述
如果我们去可视化这些向量以及这个和自注意力相关联的layer-norm操作,那么看起来就像下面这张图描述一样:
在这里插入图片描述

2.3 Decoder层详细说明

根据decoder的总体结构图可以看出,Decoder部分其实和Encoder部分大同小异:
在这里插入图片描述

2.3.1 masked multi-head attention

mask表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。其中,padding mask 在所有的attention 里面都需要用到,而 sequence mask 只有在 Decoder 的 self-attention 里面用到。

(1)padding mask

什么是 padding mask 呢?因为每个批次输入序列长度是不一样的,所以我们要对输入序列进行对齐。就是给在较短的序列后面填充 0,截取较长序列。因为这些填充的位置其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。

具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0。

(2)Sequence mask

sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。

那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。

  • 对于 decoder 的 self-attention,里面使用到的attention同时需要 padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。
  • 其他情况,attn_mask 一律等于 padding mask。

3. Q/A

(1) Transformer为什么需要进行Multi-head Attention?这样做有什么好处?Multi-head Attention的计算过程?

原论文中说进行Multi-head Attention的原因是将模型分为多个头,形成多个子空间,可以让模型去关注不同方面的信息,最后再将各个方面的信息综合起来。其实直观上也可以想到,如果自己设计这样的一个模型,必然也不会只做一次attention,多次attention综合的结果至少能够起到增强模型的作用,也可以类比CNN中同时使用多个卷积核的作用,直观上讲,多头的注意力有助于网络捕捉到更丰富的特征/信息。Multi-head Attention的计算过程前面已经详细讲过。

(2) Transformer相比于RNN/LSTM,有什么优势?为什么?

RNN系列的模型,并行计算能力很差,因为 T 时刻的计算依赖 T-1 时刻的隐层计算结果,而 T-1 时刻的计算依赖 T-2 时刻的隐层计算结果,如此下去就形成了所谓的序列依赖关系。

Transformer的特征抽取能力也比RNN系列的模型要好。

但是值得注意的是,并不是说Transformer就能够完全替代RNN系列的模型了,任何模型都有其适用范围,同样的,RNN系列模型在很多任务上还是首选。

(3) 为什么说Transformer可以代替seq2seq?

seq2seq缺点:这里用代替这个词略显不妥当,seq2seq虽已老,但始终还是有其用武之地,seq2seq最大的问题在于将Encoder端的所有信息压缩到一个固定长度的向量中,并将其作为Decoder端首个隐藏状态的输入,来预测Decoder端第一个单词(token)的隐藏状态。在输入序列比较长的时候,这样做显然会损失Encoder端的很多信息。而且这样一股脑的把该固定向量送入Decoder端,Decoder端不能够关注到其想要关注的信息。上述两点都是seq2seq模型的缺点,后续论文对这两点有所改进,但是由于主体模型仍然为RNN(LSTM)系列的模型,因此模型的并行能力还是受限。

Transformer优点:transformer不但对seq2seq模型这两点缺点有了实质性的改进(多头交互式attention模块),而且还引入了self-attention模块,让源序列和目标序列首先“自关联”起来,这样的话,源序列和目标序列自身的embedding表示所蕴含的信息更加丰富。并且Transformer并行计算的能力是远远超过seq2seq系列的模型,因此我认为这是transformer优于seq2seq模型的地方。

(4) Transformer如何并行化的?

Transformer的并行化我认为主要体现在self-attention模块。对于某个序列 x 1 , x 2 , . . . x n x_1, x_2, ...x_n x1,x2,...xn,self-attention模块可以直接计算 x i , x j x_i, x_j xi,xj的点乘结果,而RNN系列的模型就必须按照顺序从 x 1 x_1 x1计算到 x n x_n xn​。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41332009/article/details/114441708