paper:Attention Is All You Need

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014665013/article/details/86184534


更多源码介绍详见 姊妹篇

1.为什么是attention

正如论文的题目所说的,Transformer中抛弃了传统的CNN和RNN,整个网络结构完全是由Attention机制组成。更准确地讲,Transformer由且仅由self-Attenion和Feed Forward Neural Network组成。一个基于Transformer的可训练的神经网络可以通过堆叠Transformer的形式进行搭建,作者的实验是通过搭建编码器和解码器各6层,总共12层的Encoder-Decoder,并在机器翻译中取得了BLEU值得新高。

作者采用Attention机制的原因是考虑到RNN(或者LSTM,GRU等)的计算限制为是顺序的,也就是说RNN相关算法只能从左向右依次计算或者从右向左依次计算,这种机制带来了两个问题:

  • 时间片 t 的计算依赖 t-1 时刻的计算结果,这样限制了模型的并行能力;
  • 顺序计算的过程中信息会丢失,尽管LSTM等门机制的结构一定程度上缓解了长期依赖的问题,但是对于特别长期的依赖现象,LSTM依旧无能为力。

Transformer的提出解决了上面两个问题,首先它使用了Attention机制,将序列中的任意两个位置之间的距离是缩小为一个常量;其次它不是类似RNN的顺序结构,因此具有更好的并行性,符合现有的GPU框架。论文中给出Transformer的定义是:

Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution。

原文有些细节解释的并不是很清楚,但是The Illustrated Transformer 给出了详细的解释,可参阅~

2.分层详解Transformer

下面我们自上而下的对transformer进行分析,这样可以让整体更加清晰~(不至于发出我在哪,我在做了什么,接下来我又要做什么的疑问)

先看一下官方给出的模型结构:
在这里插入图片描述

论文中的验证Transformer的实验室基于机器翻译的,下面我们就以机器翻译为例子详细剖析Transformer的结构,在机器翻译中,Transformer可概括为如图1:
在这里插入图片描述
其内部的实现Encoder-Decoder结构:
在这里插入图片描述
如论文中所设置的,编码器由6个编码block组成,同样解码器是6个解码block组成。与所有的生成模型相同的是,编码器的输出会作为解码器的输入,这里需要注意的是,encoder的结果作为decoder stack里面每一层的输入:
在这里插入图片描述

其中encoder的结构如下图所示,这里的Encoder Stack里面的每个Encoder是不共享变量的:
在这里插入图片描述
Decoder的结构和encoder的不同之处在于Decoder多了一个Encoder-Decoder Attention,两个Attention分别用于计算输入和输出的权值:
Self-Attention:当前翻译和已经翻译的前文之间的关系;
Encoder-Decnoder Attention:当前翻译和编码的特征向量之间的关系。

最后我们在详细说下Encoder和Decoder的内部细节:

  • self-attention:通过该模块得到一个加权之后的特征向量 Z Z ,这个 Z Z 便是论文公式1中的 A t t e n t i o n ( Q , K , V ) Attention(Q,K,V) ,后面会详解:
    (1) A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V) = softmax(\frac {QK^T}{\sqrt{d_k}})V \tag 1
  • Feed Forward Neural Network,这个全连接有两层,第一层的激活函数是ReLU,第二层是一个线性激活函数,可以表示为:
    (2) F F N ( Z ) = m a x ( 0 , Z W 1 + b 1 ) + b 2 FFN(Z) = max(0,ZW_1+b_1)+b_2 \tag 2

3.向量详解Transformer

3.1.输入向量

上面介绍了Model的各个模块,接下来我们再从Vectors/tensors的角度来详细分解各个模块,明白从输入到输出所经过的各种操作。
首先通过Word2Vec等词嵌入方法将输入语料转化成特征向量,论文中使用的词嵌入的维度为 d m o d e l = 512 d_{model}=512 :
在这里插入图片描述
在最底层的block中, x 将直接作为Transformer的输入,而在其他层中,输入则是上一个block的输出。为了画图更简单,我们使用更简单的例子来表示接下来的过程:
在这里插入图片描述

3.2.self attention

Self-Attention是Transformer最核心的内容,然而作者并没有详细讲解,下面我们来补充一下作者遗漏的地方。回想Bahdanau等人提出的用Attention[2],其核心内容是为输入向量的每个单词学习一个权重,例如在下面的例子中我们判断it代指的内容:

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

这里的it指的是什么意思,street还是animal,self-attention 通过查看其他位置的单词,最终得出结论:it指的是animals.
通过加权之后可以得到类似下图的加权情况,在讲解self-attention的时候我们也会使用图8类似的表示方式:
在这里插入图片描述

在self-attention中,需要算出每个单词 x i x_i 对应的3个不同的向量,它们分别是Query向量 q i q_i ,Key向量 k i k_i 和Value向量 v i v_i ,长度均是64。那他们是怎么算出来的呢?是由嵌入向量 X 乘以三个不同的权值矩阵 W Q W^Q W K W^K W V W^V 得到的,其中三个矩阵的尺寸也是相同的,均是 512 × 64 512\times 64 ,这样的最后得到的Q K V的维度为sequence_length*64 。
Q = X × W Q Q = X \times W^Q
K = X × W K K = X \times W^K
V = X × W V V = X \times W^V
其中 X = [ x 1 , x 2 . . . ] , Q = [ q 1 , q 2 . . . ] , K = [ k 1 , k 2 . . . ] , V = [ v 1 , v 2 . . . ] X=[x_1,x_2...], Q=[q_1,q_2...],K=[k_1,k_2...],V=[v_1,v_2...] .

这里图片中 q 1 = x 1 × W Q q_1 = x_1 \times W^Q k 1 , v 1 k_1,v_1 同理

那么Query,Key,Value是什么意思呢?它们在Attention的计算中扮演着什么角色呢?我们先看一下Attention的计算方法,整个过程可以分成7步:

  1. 如上文,将输入单词转化成嵌入向量 x i x_i
  2. 根据嵌入向量得到 q i k i v i q_i , k_i , v_i 三个向量;
  3. 为每个向量计算一个 s c o r e i score_{i} 向量: s c o r e i = q i K score_{i} = q_i \cdot K
  4. 为了梯度的稳定,Transformer使用了 s c o r e i score_i 归一化,即除以 d k \sqrt{d_k}
  5. s c o r e i score_i 施以softmax激活函数;
  6. softmax点乘Value值 v ,得到加权的每个输入向量的评分 v ;
  7. 相加之后得到最终的输出结果 z i z_i z i = i = 0 n v i z_i = \sum_{i=0}^n v_i (假设句子长度为n)。

可表示如下:
在这里插入图片描述

实际计算过程中是采用基于矩阵的计算方式,那么论文中的 Q Q V V K K 的计算方式如图:
在这里插入图片描述

最后self-attention 的公式可以写成如下直观表示:
在这里插入图片描述

3.3.Multi-Head Attention

Multi-Head Attention相当于 h 个不同的self-attention的集成(ensemble),该trick提高了模型的效果,主要表现在如下两方面:

  • multi head增强了模型focus on不同位置的能力。在上面的例子中,it可能受这个单词本身主导,但是很明显通过多头的方式,可以pay attention to其他的单词(例如animals),从而推断出it代表的意思。
  • 通过多头,可以帮助attention layer把输入embedding映射到多个表示空间。
    在这里插入图片描述
    在实际操作的时候,只不过把self-attention操作按照相同的方式重复8遍罢了(原文代码中采用的是8 head):
    在这里插入图片描述

但是这里的feed-forward layer不希望处理8个matrics,因此解决方法就是先把 Z 0 Z_0 Z 8 Z_8 concat 起来,然后再project一下,最终得到 Z Z ,如下图:
在这里插入图片描述

综上所述,multi head的操作流程可视化如下:
在这里插入图片描述

按照multi head的方式,我们再来看之前的例子的attention表示:
在这里插入图片描述

As we encode the word “it”, one attention head is focusing most on “the animal”, while another is focusing on “tired” – in a sense, the model’s representation of the word “it” bakes in some of the representation of both “animal” and “tired”.

如果把所有的head都画出来,可能对于人来说,直观上可能已经很难解释了:
在这里插入图片描述

3.4.position embedding

到目前为止,因为是翻译的模型,但是模型缺少了words再句子中的位置信息,所以模型增加了position编码,从而提供位置信息。
假如embedding的维度是4,那么可表示如下:
在这里插入图片描述

那么我们来看一下如果是长度为20的句子,512的hidden size的position embedding是什么样子的:
在这里插入图片描述
再上图中我们可以看到从中间分开了,这是因为左面的value是通过一种函数生成的(sin),而右面的是通过另外一个函数生成的(cos),最后再将他们concat起来,这也是论文code中的实现方案,和论文中的
P E ( p o s , 2 i ) = s i n ( p o s / 1000 0 2 i / d m o d e l ) PE(pos,2i) = sin(pos/10000^{2i/d_{model}})
P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1000 0 2 i / d m o d e l ) PE(pos,2i+1) = cos(pos/10000^{2i/d_{model}})
那作者又为什么要选择这样的函数呢?

  • 作者这么设计的原因是考虑到在NLP任务重,除了单词的绝对位置,单词的相对位置也非常重要。根据公式 s i n ( α + β ) = s i n α c o s β + c o s α s i n β sin(\alpha+\beta) = sin \alpha cos \beta + cos \alpha sin\beta 以及 c o s ( α + β ) = c o s α c o s β s i n α s i n β cos(\alpha + \beta) = cos \alpha cos \beta - sin \alpha sin\beta ,这表明位置 k+p 的位置向量可以表示为位置 k 的特征向量的线性变化,这为模型捕捉单词之间的相对位置关系提供了非常大的便利。
  • 如果是学习到的positional embedding,(个人认为,没看论文)会像词向量一样受限于词典大小。也就是只能学习到“位置2对应的向量是(1,1,1,2)”这样的表示。所以用三角公式明显不受序列长度的限制,也就是可以对 比所遇到序列的更长的序列 进行表示。

3.5.Residuals layer

Transformer中另外一个特点就是在每个sub-layer(self-attention+ffn)之后,都会有一个残差网络,而这个残差是sub-layer前面的一层的输出结果:
在这里插入图片描述

到这里,我们可以详细地描述Transformer的结构了:

在这里插入图片描述
这里Encoder的最终结果(Encoder_outputs)会传播到Decoder中,在Decoder的self-attention之后(得到Decoder_inputs),再做attention,这次Attention的Q=decoder_outputs(上一层decoders输出,或者target sequence编码),K和V=encoder_outputs
(1) A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V = s o f t m a x ( d e c o d e r _ o u t p u t × e n c o d e r o u t p u t s T d k ) e n c o d e r o u t p u t s = a t t e n t i o n ( d e c o d e r _ i n p u t s , e n c o d e r _ o u t p u t s , e n c o d e r _ o u t p u t ) Attention(Q,K,V) = softmax(\frac {QK^T}{\sqrt{d_k}})V \tag 1 = softmax(\frac {decoder\_output \times {encoder_outputs}^T}{\sqrt{d_k}}) {encoder_outputs}= attention(decoder\_inputs,encoder\_outputs,encoder\_output)

3.6. Decoder中的特点

上面所说的多是针对于Encoder端的,虽然在Decoder端很多操作都与Encoder相同,但是还是有如下的几点不同:

  • self-attention:与encoder里面的self-attention略有不同,就是在对output sequence做attention之前只允许看到output sequence的前面位置的信息,具体操作就是在self attention计算之前masking后面的位置。
  • Decoder-encoder-attention:Decoder端在self-attention后,还会将该输出和Encoder的输出进行attention

3.7.Final Linear and Softmax Layer

最终的decoder stack输出的是浮点型的向量,那怎么把它变为一个翻译的目标单词呢?这就需要最后的Linear layer以及后面的Softmax Layer了。
假如模型的输出词表大小为10000,那么通过全连接之后,会得到每个单词的相关分数,最后通过softmax,从而得出当前的分值最大的output word:
在这里插入图片描述

至此,我们的模型已经讲解的比较详细了,我们来整体动态看一下:
在这里插入图片描述

4.源码解读

transformer发布了官方的版本,但是其借助了tensor2tensor的框架,因此其可读性很差,为了增强其扩展性,往往看一个模型,需要深入好多层才能看到真正想看的code,因此这里我详解的是github中tensorflow中的代码,链接:transformer,另外增加了大量注释的小博git

常规trick:

  • layernorm
  • word embedding 和 layer 中dropout

本篇淫巧

  • 对word embedding和position embedding做scale,本文中的具体操作是:
    embeddings *= self.hidden_size ** 0.5
    
    
  • 过dense layer时去除padding的vector,这样可以增大batch size,具体代码详见:详情
  • decode时前项mask(不可见),详情
  • 在ffn-layer时,采用的是双层dense layer,并且第一层是先将维度扩大,且经过激活函数,然后第二层在将维数还原到原来的维数,且无激活函数。

4.总结

4.1.优点

  • 虽然Transformer最终也没有逃脱传统学习的套路,Transformer也只是一个全连接(或者是一维卷积)加Attention的结合体。但是其设计已经足够有创新,因为其抛弃了在NLP中最根本的RNN或者CNN并且取得了非常不错的效果,算法的设计非常精彩,值得每个深度学习的相关人员仔细研究和品位。
  • Transformer的设计最大的带来性能提升的关键是将任意两个单词的距离是1,这对解决NLP中棘手的长期依赖问题是非常有效的。
  • Transformer不仅仅可以应用在NLP的机器翻译领域,甚至可以不局限于NLP领域,是非常有科研潜力的一个方向。
  • 算法的并行性非常好,符合目前的硬件(主要指GPU)环境
  • Attention 虽然跟 CNN 没有直接联系,但事实上充分借鉴了 CNN 的思想,比如 Multi-Head Attention 就是 Attention 做多次然后拼接,这跟 CNN 中的多个卷积核的思想是一致的;还有论文用到了残差结构,这也源于 CNN 网络。

4.2.缺点

  • 粗暴的抛弃RNN和CNN虽然非常炫技,但是它也使模型丧失了捕捉局部特征的能力,RNN + CNN + Transformer的结合可能会带来更好的效果。
  • Transformer失去的位置信息其实在NLP中非常重要,而论文中在特征向量中加入Position Embedding也只是一个权宜之计,并没有改变Transformer结构上的固有缺陷。

参考文献:

猜你喜欢

转载自blog.csdn.net/u014665013/article/details/86184534