【NLP-12】Transformer(Atention is all you need)
目录
- transformer简介
- transformer模型分析
- 相关对比和问题
一句话简介:2017年(Atention is all you need)引出,采用了 从Encoder(2个子层)-Decoder(3个子层)架构,包含几个重要组件:Self-Attention,Multi-Headed Attention(8个矩阵,类似CNN中的多个卷积核)以及FFN,masked mutil-head attetion,LN,Positional Encoding这些组件。
一、transformer简介
1.1 基础介绍
首先回顾下将Attention(实质上就是Encoder中隐层输出的加权和)机制从encoer-decoder 框架中抽出,进一步抽象化,其本质上如下图
计算Attention的整个流程大致如下:
1)计算Query和source中各个Key的相似性,得到每个Key对应的Value的权重系数。在这里我认为Key的值是source的隐层输出,Key是等于Value的,Query是target的word embedding(这种想法保留);
2)利用计算出来的权重系数对各个Value的值加权求和,就得到了我们的Attention的结果。
1.2 Transformer介绍
《Attention Is All You Need》是一篇Google提出的将Attention思想发挥到极致的论文。这篇论文中提出一个全新的模型,叫 Transformer,抛弃了以往深度学习任务里面使用到的 CNN(当然实际构建构成中也用到了CNN的思想) 和 RNN。大热的Bert就是基于Transformer构建的,这个模型广泛应用于NLP领域,例如机器翻译,问答系统,文本摘要和语音识别等等方向。
二、transformer模型分析
2.1 总体结构
Transformer的结构和Attention模型一样,Transformer模型中也采用了 encoer-decoder 架构。但其结构相比于Attention更加复杂,论文中encoder层由6个encoder堆叠在一起,decoder层也一样。
不了解Attention模型的,可以回顾之前的文章:【NLP-11-1】注意力机制(Attention)
每一个encoder和decoder的内部结构如下图:
1)encoder,包含两层,一个self-attention层和一个前馈神经网络,self-attention能帮助当前节点不仅仅只关注当前的词,从而能获取到上下文的语义。
输入的序列长度是n,embedding维度是d,所以输入是n*d的矩阵 由两个子层组成:
Sub-L1:
- Multi-head self-attention
- 残余连接和LN:
- Output = LN (x+sublayer(x))
- N=6,6个重复一样的结构
Sub-L2:
- Position-wise fc层(跟卷积很像)
- 对n*d的矩阵的每一行进行操作(相当于把矩阵每一行铺平,接一个FC),同一层的不同行FC层用一样的参数,不同层用不同的参数(对于全连接的节点数目,先从512变大为2048,再缩小为512),这里的max表示使用relu激活函数:
整个encoder的输出也是n*d的矩阵
2)decoder也包含encoder提到的两层网络,但是在这两层中间还有一层attention层,帮助当前节点获取到当前需要关注的重点内容。
•输入:假设已经翻译出k个词,向量维度还是d
•同样使用N=6个重复的层,依然使用残余连接和LN
•3个子层,比encoder多一个attention层,是Decoder端去attend encoder端的信息的层:
Sub-L1:self-attention,同encoder,但要Mask掉未来的信息,得到k*d的矩阵
Sub-L2:和encoder做attention的层,输出k*d的矩阵
Sub-L3:全连接层,输出k*d的矩阵,用第k行去预测输出y
另外特征提取方面的图,再看下各层的位置,后续会展开描述:
2.2 Self-Attention
self-attention在上一篇文章【NLP-11】注意力机制(Attention)中也有介绍。思想和attention类似,但是self-attention是Transformer用来将其他相关单词的"理解"转换成我们正在处理的单词的一种思路,实际上相当于QKV都来自本身,可以表示成Attention(X,X,X)形式。
作用的话我们看个例子:The animal didn't cross the street because it was too tired
这里的 it 到底代表的是 animal 还是 street 呢,对于我们来说能很简单的判断出来,但是对于机器来说,是很难判断的,self-attention就能够让机器把 it 和 animal 联系起来。
Google论文的主要贡献之一是它表明了内部注意力在机器翻译(甚至是一般的Seq2Seq任务)的序列编码上是相当重要的,而之前关于Seq2Seq的研究基本都只是把注意力机制用在解码端。类似的事情是,目前SQUAD阅读理解的榜首模型R-Net也加入了自注意力机制,这也使得它的模型有所提升。
2.3 Multi-Headed Attention
这个是Google提出的新概念,是Attention机制的完善。不过从形式上看,它其实就再简单不过了,就是把Q,K,V通过参数矩阵映射一下,然后再做Attention,把这个过程重复做h次,结果拼接起来就行了,可谓"大道至简了。tranformer是使用了8组,所以最后得到的结果是8个矩阵。
表达式的计算如下:
1)假设现在头数为h,首先按照每一时序上的向量长度(如果是词向量的形式输入,可以理解为embedding size的值)等分成h份。
2)然后将上面等分后的h份数据分别通过不同的权重映射得到新的Q, K, W的值。
3)将上述映射后的h份数据计算相应的Attention的值。
4)按照之前分割的形式重新拼接起来,再映射到原始的向量维度。就得到Multi-Head Attention的值。在这里每一次映射的矩阵都不相同,因此映射之后再计算也就会得到不一样的结果。Multi-Head Attention的机制有点类似与卷积中的多个卷积核,在卷积网络中,我们认为不同的卷积核会捕获不同的局部信息,在这里也是一样,我们认为Multi-Head Attention主要有两个作用:
1)增加了模型捕获不同位置信息的能力,如果你直接用映射前的Q, K, V计算,只能得到一个固定的权重概率分布,而这个概率分布会重点关注一个位置或个几个位置的信息,但是基于Multi-Head Attention的话,可以和更多的位置上的词关联起来。
2)因为在进行映射时不共享权值,因此映射后的子空间是不同的,认为不同的子空间涵盖的信息是不一样的,这样最后拼接的向量涵盖的信息会更广。
2.4 Layer normalization
在transformer中,每一个子层(self-attetion,Feed Forward Neural Network)之后都会接一个残缺模块,并且有一个Layer normalization。
Normalization有很多种,但是它们都有一个共同的目的,那就是把输入转化成均值为0方差为1的数据。我们在把数据送入激活函数之前进行normalization(归一化),因为我们不希望输入数据落在激活函数的饱和区。
Batch Normalization
BN的主要思想就是:在每一层的每一批数据上进行归一化。我们可能会对输入数据进行归一化,但是经过该网络层的作用后,我们的数据已经不再是归一化的了。随着这种情况的发展,数据的偏差越来越大,我的反向传播需要考虑到这些大的偏差,这就迫使我们只能使用较小的学习率来防止梯度消失或者梯度爆炸。BN的具体做法就是对每一小批数据,在批这个方向上做归一化。
Layer normalization
它也是归一化数据的一种方式,不过LN 是在每一个样本上计算均值和方差,有点类似CV用到的instance normalization而不是BN那种在批方向计算均值和方差!公式如下:
直观比较下两者差异:
2.5 Feed Forward Neural Network(FFN层)
前馈神经网络没法输入 8 个矩阵呀,这该怎么办呢?所以我们需要一种方式,把 8 个矩阵降为 1 个,首先,我们把 8 个矩阵连在一起,这样会得到一个大的矩阵,再随机初始化一个矩阵和这个组合好的矩阵相乘,最后得到一个最终的矩阵。
具体公式可以表示为:FFN(x)=Relu(xW1+b1)W2+b2
层采用了全连接层加Relu函数实现,其实关于在这里并不一定要用全连接层,也可以使用卷积层来实现。
2.6 masked mutil-head attetion
mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。其中,padding mask 在所有的 scaled dot-product attention 里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到。
padding mask
什么是 padding mask 呢?因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0!而我们的 padding mask 实际上是一个张量,每个值都是一个Boolean,值为 false 的地方就是我们要进行处理的地方。
Sequence mask
文章前面也提到,sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。
那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。
对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。其他情况,attn_mask 一律等于 padding mask。
2.7 Output层
当decoder层全部执行完毕后,怎么把得到的向量映射为我们需要的词呢,很简单,只需要在结尾再添加一个全连接层和softmax层,假如我们的词典是1w个词,那最终softmax会输入1w个词的概率,概率值最大的对应的词就是我们最终的结果。
2.9 Positional Encoding
引入的原因:transformer模型因为抛弃了CNN和RNN,而使用attention机制来关注重点信息,故缺少时序序列比较重要的位置信息,顾引入此模块。
transformer给encoder层和decoder层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,这个向量采用了一种很独特的方法来让模型学习到这个值,这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。这个位置向量的具体计算方法有很多种,论文中的计算方法如下:
其中pos是指当前词在句子中的位置,i是指向量中每个值的index,可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码。
最后把这个Positional Encoding与embedding的值相加,作为输入送到下一层。
Position Embedding并不算新鲜的玩意,在FaceBook的《Convolutional Sequence to Sequence Learning》也用到了这个东西。但在Google的这个作品中,它的Position Embedding有几点区别:
1、以前在RNN、CNN模型中其实都出现过Position Embedding,但在那些模型中,Position Embedding是锦上添花的辅助手段,也就是"有它会更好、没它也就差一点点"的情况,因为RNN、CNN本身就能捕捉到位置信息。但是在这个纯Attention模型中,Position Embedding是位置信息的唯一来源,因此它是模型的核心成分之一,并非仅仅是简单的辅助手段。
2、Position Embedding本身是一个绝对位置的信息,但在语言中,相对位置也很重要,Google选择前述的位置向量公式的一个重要原因是:这表明位置p+k的向量可以表示成位置p的向量的线性变换,这提供了表达相对位置信息的可能性。
三、相关对比和问题
3.1 Transformer为什么需要进行Multi-head Attention
原论文中说到进行Multi-head Attention的原因是将模型分为多个头,形成多个子空间,可以让模型去关注不同方面的信息,最后再将各个方面的信息综合起来。其实直观上也可以想到,如果自己设计这样的一个模型,必然也不会只做一次attention,多次attention综合的结果至少能够起到增强模型的作用,也可以类比CNN中同时使用多个卷积核的作用,直观上讲,多头的注意力有助于网络捕捉到更丰富的特征/信息。
3.2 Transformer相比于RNN/LSTM,有什么优势?
RNN系列的模型,并行计算能力很差。RNN并行计算的问题就出在这里,因为 T 时刻的计算依赖 T-1 时刻的隐层计算结果,而 T-1 时刻的计算依赖 T-2 时刻的隐层计算结果,如此下去就形成了所谓的序列依赖关系。
Transformer的特征抽取能力比RNN系列的模型要好。
具体实验对比可以参考:参考文献【4】
但是值得注意的是,并不是说Transformer就能够完全替代RNN系列的模型了,任何模型都有其适用范围,同样的,RNN系列模型在很多任务上还是首选,熟悉各种模型的内部原理,知其然且知其所以然。
3.3 Transformer对比seq2seq优势?
seq2seq缺点:seq2seq最大的问题在于将Encoder端的所有信息压缩到一个固定长度的向量中,并将其作为Decoder端首个隐藏状态的输入,来预测Decoder端第一个单词(token)的隐藏状态。在输入序列比较长的时候,这样做显然会损失Encoder端的很多信息,而且这样一股脑的把该固定向量送入Decoder端,Decoder端不能够关注到其想要关注的信息。
Transformer优点:transformer不但对seq2seq模型这两点缺点有了实质性的改进(Multi-head Attention模块),而且还引入了self-attention模块,让源序列和目标序列首先"自关联"起来,这样的话,源序列和目标序列自身的embedding表示所蕴含的信息更加丰富,而且后续的FFN层也增强了模型的表达能力,并且Transformer并行计算的能力是远远超过seq2seq系列的模型,因此我认为这是transformer优于seq2seq模型的地方。
3.4 Transformer缺陷
- Transformer不像CNN那样可以抽取局部特征,RNN + CNN + Transformer的结合可能会带来更好的效果;
- 位置信息其实在NLP中非常重要,Transformer中用的Position Embedding也不是一个最终的解决方案。
- 捕捉长距离信息能力还有待提升,这个不足将在Transformer-XL中进行改进。可见后面文章。
3.5 Transformer优势
- 并行运算能力
- 有CNN的速度,兼有RNN的性能
- 使得深度网络在NLP领域成为可能
- 为大火的Bert的产生打下了坚实的基础
参考文献
【1】The Illustrated Transformer : https://jalammar.github.io/illustrated-transformer/
【2】transformer : https://www.cnblogs.com/jiangxinyang/p/10069330.html
【3】《Attention is All You Need》浅读(简介+代码): https://kexue.fm/archives/4765
【4】自然语言处理三大特征抽取器(CNN/RNN/TF)比较: https://zhuanlan.zhihu.com/p/54743941
【5】github大火的transformers: https://github.com/huggingface/transformers