Attention is all you need!
一、简介
这篇文章最初是应用于机器翻译的模型,在后来使用中发现作者提出的Transformer模型对于NLP、图片、音频、视频等也有较为不错的效果,可以说该模型是深度学习一个阶段性的成果。在文章中,作者完全摒弃了传统RNN和卷积网络,完全使用自注意力机制进行模型结构的搭建,且允许更高程度的并行化。
二、实验结论
(到后面发现先看结论会让读者对整篇文章的内容有大方向的把握)
- Transformer是第一个完全基于注意力的序列转导模型
- 使用多头注意力取代了常规架构
- 在翻译任务中取得较好成果,且作者在最后预料到了以后模型的发展:我们计划将
Transformer扩展到涉及文本以外的输入和输出模式的问题,并研究局部的、受限的注意力
机制,以有效地处理图像、音频和视频等大型输入和输出。
三、背景
首先讲了传统网络模型的缺点:学习距离较远的位置之间的依赖关系随着位置距离增长变得更加困难。在Transformer中只需要O(1)的时间复杂度即可完成,虽然由于注意力机制的使用,使得在提取特征时感受野收到了一定的影响,作者在后文使用Mutil-Head解决了该问题。
其他段落主要讲自我注意不是自己首先提出的,提了一下端到端记忆网络,最后说Transformer的地位。
四、模型架构
首先简单介绍了转导模型具有的编码器-解码器结构,输入序列(x1,…,xn)经过编码器到连续表示序列z=(z1,…,zn),z经由解码器输出结果序列(y1,…,ym)。在每一步中,模型都是自回归的(自回归即当前时刻的观测值被认为是过去时刻的观测值的线性组合,其中线性关系的权重是模型的参数,即现在的观测值与过去的观测值具有依赖关系)
作者提出的Transformer也遵循了编码器-解码器的架构。
下面具体解释一下编码器和解码器
- 编码器(图左):由一系列的层组成,每个层由两个子层构成,可以注意到编码器左边有Nx,N表示这样的结构堆叠了多少层。
- 首先是Input Embedding,将输入的序列转为向量表示(dim=512);
- 接下来有一个Positional Encoding,这是一个位置信息的编码。作者使用了正弦余弦函数进行编码,输出一个与输入向量维数一致的位置向量后与输入信息相加。
- 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}}) PE(pos,2i)=sin(pos/100002i/dmodel)
- 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}}) PE(pos,2i+1)=cos(pos/100002i/dmodel)
- 其中pos为位置,i是维数,也就是说位置编码的每一个维对应一个正弦波
- 之后是一个多头的注意力层,使用多头注意力机制可以类比卷积的时候我们常提到ASPP模块进行多尺度的特征提取,这里也是一样如果是单注意力机制,对于各个输入向量的特征提取较为单一,无法从多个角度去获取可能得信息。多头的注意力机制实现起来,只需将每个输入向量的Q,K,V使用不同的变换矩阵W进行处理即可,最后算出的值拼接起来使用矩阵W2变换为512维的输出即可。
- 可以注意到后续有个Add&Norm的层,这里是引入残差机制,将当前多头注意力层的输出和原本的输入做一个相加并进行Layer Norm处理。
- 后续是一个Feed Forward,其实就是一个简单的MLP,作者的特殊处理是将权重乘了 d m o d e l d_{model} dmodel
- 解码器大致结构与编码器相同,下面只介绍不同的地方
- 首先看到的是输入的不同,这里的输入为Outputs,因为输出的后续序列需要前面输出作为输入。
- 其次注意到第一个子层使用的是Masked Mutil-Head Attention,这里的mask的理解我们可以以机器翻译为例,在机器翻译中,由于后续的输出是需要前面的输出作为输入的,那么我们在做注意力的时候应该只关注序列左边的部分,不去考虑右边的部分,具体的实现来讲,作者将其设置为了( − ∞ -∞ −∞,即很小的数),这样在经过softmax的时候,对应部分就会变为一个无限为0的数。
- 第二个子层,可以发现它的输入除了上一子层的输出外,还从编码器里取了结果作为输入。左边两根线指的是从编码器结果或得K、V,右边的编码器将上一子层的输出作为Q。这里的注意力机制就不是自注意力机制了,或许可以称为(Cross Attention)。解码器可以自主的从编码器中选择自己“感兴趣”的部分加入自己序列里。
五、为什么使用self-attention
使用self-attention主要考虑了如上图的三个因素:
- 一是每层的总计算复杂度
- 主要衡量每层计算的时间复杂度了,其中n是输入的序列长度,d是向量维数。可以发现当序列长度n小于表示维度d时,自注意层比RNN和CNN快,如果是较长序列的任务时,考虑将自注意限制大小,即相当于选择长序列的一部分进行处理。
- 二是网络中远程依赖关系之间的路径长度
- 表示的是当前元素向前或向后必须穿越的路径长度,简单来理解,只有RNN因为每一个位置的输出都需要前一个位置的输出作为输入,所以第n个位置需要等前n-1个位置全部算出,故为O(n).
- 三是任意两个输入和输出位置之间的最大路径长度
- 简单理解就是一个信息从一个数据点走到另一个数据点要多远
六、模型训练
优化器:使用Adam优化器,
β
1
=
0.9
,
β
2
=
0.98
,
ϵ
=
1
0
−
9
\beta_{1}=0.9,\beta_{2}=0.98,\epsilon=10^{-9}
β1=0.9,β2=0.98,ϵ=10−9,根据公式在学习中改变学习率,
l
r
a
t
e
=
d
m
o
d
e
l
−
0.5
m
i
n
(
s
t
e
p
_
n
u
m
−
0.5
,
s
t
e
p
_
n
u
m
×
w
a
r
m
u
p
_
s
t
e
p
s
−
1.5
)
lrate=d_{model}^{-0.5}min(step\_num^{-0.5},step\_num×warmup\_steps^{-1.5})
lrate=dmodel−0.5min(step_num−0.5,step_num×warmup_steps−1.5)
其中主要是根据训练步骤来改变学习率,前面的d为模型维度,若模型维数大,则学习率会小一些。后面括号里主要是刚开始按照学习次数慢慢增加,后面按照次数的倒数平方根成比例的降低学习率
DropOut:值得一说的是作者在结构图中没有体现比较关键的一点,作者在每个子层都应用了dropout,丢失率Pdrop=0.1
LayerNorm:没有使用常用的batchNorm,而是选择了LayerNorm。
Label Smoothing:使用了标签平滑,降低了模型学习的确定性,但对准确性和BLEU分数有提高
七、实验结果
- (A)中可以发现,单头注意力机制比最佳设置差0.9ELBU,但过多的头也会导致质量下降
- (B)中观察到K的维度选择对模型质量影响较大
- (C、D)进一步展示了使用dropout对避免过拟合非常有帮助