论文略读 | Attention is all you need
2017年Google发表在NIPS的一篇文章,到现在已经1200+的引用量了,可以看到现在多火了吧。还是要来看看的,粗略读一下吧。
后续,从阅读理解的Encoder-Decoder方面改一下看看会不会有改进点。还有Mem2seq的代码看一下。相似度概率计算的公式可以改一下试试。
主要序列转导模型基于包括编码器和解码器的复杂RNN或者CNN网络,性能最佳的模型是通过注意力机制链接编码器和解码器。本文提出了一种新的简单的网络架构Transformer,它完全基于注意力机制,免除了RNN的重复和CNN的卷积。在两个机翻任务的实验上验证表明,该架构质量优越,同时可以更加并行化,并且需要更少的时间进行训练。
RNN用于序列建模和转换问题,它们产生一系列隐藏状态ht,作为先前隐藏状态ht-1和位置t的输入函数,这种固有的顺序性使得训练样本难以并行化(在较长序列样本中至关重要),因为内存约束限制了跨例子的批处理(batching)。最近有工作通过分解技巧和条件计算显著提高了计算效率,后者也改善了模型的性能,但顺序计算的基本约束仍然存在。基于此背景,本文提出了Transformer模型,完全依赖注意力机制来绘制输入和输出之间的全局依赖关系。
本着减少顺序计算的目的,之前已经提出了扩展神经GRU,ByteNet和ConvS2S,所有这些都使用CNN作为基本模块,为输入和输出并行计算隐含层表示。在这些模型中,关联两个来自任意输入或输入位置的信号所需要的操作数随着位置间的距离增长,对于ConvS2S来说是呈线性增长,对于ByteNet来说呈对数增长,这使得学习远程位置之间的依赖性时越来越复杂。在Transformer模型中,这被减少为恒定额操作次数,尽管由于平均注意力加权位置而导致有效分辨率降低,受3.2中描述的的Multi-Head Attention
的影响。Self-attention
,又被称作intra-attention
是通过关联同一个句子不同位置之间的关系来计算该句子表示的注意力机制。Self-attention
机制已经被用于很多的任务上,例如阅读理解,抽象概括文本蕴涵和任务独立的句子表示中。
端到端内存网络基于循环注意机制而不是序列重复对齐,并且已经被证明在简单语言问答和语言建模任务中表现良好。然而据我们所知,Transformer模型是第一个完全依靠self-attention
来计算其输入和输出的表示,没有使用序列对齐的RNN或者卷积。
3.模型结构
大多数有竞争力的神经序列转导模型具有编解码器结构,这里编码器将符号表示的输入序列 (x1; :::; xn) 映射为连续表示序列z=(z1,…zn).给定z,解码器逐字地生成符号表示的输出序列(y1;…ym)。在每一步,模型都是自回归auto-egressive
的,在下一个符号表示生成时将先前生成的符号作为附加输入。Transformer用堆叠的self-attention
、point-wise
和全连接层遵循了这种结构,结构如下图所示。
3.1 编码器和解码器堆叠结构
(1)编码器:
编码器由N=6个相同的层组成,每层有两个子层。第一种是Multi-Head self-attention
机制,第二个是一个简单的position-wise
的全连接前馈网络。我们在两个子层中每一个的周围添加了一个残差连接,然后进行层归一化。也就是说,每个子层的输出是 LayerNorm(x + Sublayer(x))
,其中Sublayer(x)
是由子层本身实现的功能。为了促进这些残差连接,模型中的所有子层以及嵌入层,都产生维度为512的输出。
(2)解码器
解码器也是由N=6个相同层的堆叠组成,除了每个编码器层中的两个子层外,解码器还插入了第三个子层,它对编码器堆栈的输出执行Multi-Head attention
。与编码器类似,在每个子层周围使用残差连接,然后进行层规范化。我们还修改了解码器堆栈中的selft-attention
子层以防止位置出现在后续位置。(???)这种masking,与输入嵌入会向后偏移一个位置的事实相结合,确保了位置i的预测仅依赖于位置小于i的已知输出。
3.2 Attention
一个注意力方程可以描述为将query
和一组key-value
映射到输出,其中query
、key-value
、和output
都是向量。输出被计算为value
的加权和,赋予每个value
的权重是通过计算key
和query
的匹配性得出的。
(1)Scaled (缩放)Dot-Product Attention
输入包含queries
和维度为dk的keys
以及维度为dv的values
。计算query和所有key的点成,每个除以根号dk,然后用一个softmax方程来得到values
上的权重。
在实际操作中,我们同时计算一系列queries
的attention funciton,然后将它们打包成一个矩阵Q
。keys和values被打包在矩阵K和V中,然后按照如下的公式计算输出(putputs)矩阵。
最常用的两个注意力方程式 additive attention(加)
和dot-product(multiplicative)(乘法) attention
。点乘注意力就是上面那个式子去掉除以根号dk(即去掉scaled缩放的步骤)。 additive attention(加)
通过一个单隐层的前馈网络来计算匹配性。尽管这两个注意力计算方式在理论上复杂性相同,实际使用时可以发现点乘注意力更快并且更节省空间,因为它可以通过高度优化的矩阵相乘代码来实现。
尽管当dk较小时两种机制表现相当,additive attention
在dk取很大的值时比没有缩放的dot product attention
性能更好。我们猜测是因为当dk取很大的值时,点成在数量上增长很快,将softmax方程压入具有很小的梯度的范围内。为了抵消这个影响,我们将点成缩小到了根号dk分之一(就是加了上面式子那个缩放值)。
(2)Multi-Head Attention(是不是其实就是为了并行计算?)
我们发现将keys,queries和values分别线性投影h次,投影成维度dk,dk和dv而不是用dmodel维的keys,values和queries单独执行注意力方程效果更好。在这些投影后的keys,values和queries上,我们并行的执行注意力方程,最后生成dv维的输出值。将这些输出值结合起来再进行一次映射,得到最终的outputs,如下图所示。Multi-head attention
允许模型共同关注来自不同表示空间,不同位置的信息。(??)用一个单注意力头,做平均就可以抑制这种情况。(是不是好像CNN啊)
这几个W是预测(或者翻译成映射??)的参数矩阵。
在我们的工作中应用了h=8个并行注意力层,或者可以称为8个头。采用的维度遵循dk=dv=dmodel/h=64。由于每个头部的尺寸减小,总计算成本与具有全维度的单头注意力相似。
(3)我们模型中attention的应用。
Transformer在三个不同的方面使用了multi-attention
机制。
- 在
Encoder-decoder attention
层中,queries
来自于之前的decoder层,记忆keys
和values
来自encoder的输出。这使得解码器中的每个位置都可以参与到编码器的任意位置中。这模仿了出传统的编解码结构中的seq2seq模型中的注意力机制。 - encoder包含了
self-attention
层,在自注意层中,所有的keys
,values
和queries
来自相同的位置。在这种情况下,是encoder中前一层的输出。encoder中每个位置可以参加到它之前所有层的位置中。 - 相似地,decoder中的自注意力机制允许decoder中的每个位置在可以参与到它之前包括当前层的位置中。我们需要防止decoder中的信息流左流以保持自回归性。我们在
scaled dot-product attention
中通过设置屏蔽,即将softmax中所有input的值(即对应非法连接的部分)设置为负无穷来实现。
3.3 Position-wise Feed-Forward Networks
除了注意力子层,编解码器的每一层中还包含一个全连接前馈网络,该网络分别用于每个位置,并且每个位置都相同。它包含两个线性变化,其间有一个ReLU的**函数。
尽管这个线性变换在不同的位置(position
)是相同的,它们在不同的层(layer
)之间用了不同的参数。另一种解释可以说是相当于两个kernel size=1的军基层,输入和输出的维度为512,内层的维度是2048。
3.4 Embedding and softmax
与其他序列转换模型类似,我们使用学到的嵌入将输入标记和输出标记转换为维度dmodel的向量。我们也用了通常用的线性转换和softmax 方程来讲解码器的输出转换为预测下一个标签的概率。在我们的模型中,我们在两个嵌入层和pre-softmax线性转换层用了相同的权重矩阵,在嵌入层,我们将权重乘以根号dmodel(??)
3.5 位置编码
由于我们的模型不包含递归和卷积,为了使模型能够利用序列的顺序,我们必须在序列中注入关于标签相对或绝对位置的一些信息。为此,我们将“位置编码”添加到编码器和解码器堆栈底部的输入嵌入中。位置编码具有与嵌入相同的维度dmodel,因此可以将两者相加。有许多位置编码选择,通过学习的或者是固定位置编码。
在本文工作中,我们用了不同频率的sin和cos方程。
其中,pos是位置,i是维度。也就是说,位置编码的每个维度对应于正弦曲线。波长形成从2π到10000·2π的几何级数。我们选择了这个函数,因为我们假设它允许模型容易地学习相对位置,因为对于任何固定偏移k,PEpos + k可以表示为PE pos的线性函数。(??)
4. 为什么要self-attention
将自我关注和用编码器将一个表示序列转换成一个隐含层序列的方式作对比,考虑以下三个需求:
- 每层的总计算复杂度
- 可并行化的计算量,通过所需的最小顺序操作数来衡量
- 网络中远程依赖之间的路径长度。学习远程依赖性是许多写转导任务中的关键挑战,影响学习这种依赖性的能力的一个关键因素是前向和后向信号必须在网络中传播的长度。输入和输出序列中,任意位置组合之间的路径越短,学习远程依赖就越容易。因此我们还比较了由不同层类型组成的网络中任意两个输入输出位置间的最大路径长度。
如表1所示,自我关注层使用恒定数量的顺序执行的操作连接所有位置,而复发层需要O(n)个顺序操作。
在计算复杂度方面,当序列长度n小于表示维度d时,自注意层比循环层快。
为了考虑涉及非常长序列的任务的计算性能,可以将self-attention 限制为仅考虑以相应输出位置为中心的输入序列中大小为r的邻域,此时最大长度为O(n/r),我们计划在未来的工作中进一步研究这种方法。
kernel宽度k<n的单个卷积层不能连接输入到输出的任意位置。因此这样做需要在连续kernel的情况下堆叠O(n/k)个卷积层,或者在扩张卷积的情况下需要O(logk(n))个,这样会增加任意两个位置之间的路径长度。通常卷积层要比循环层计算代价更大,虽然分离卷积的方式减小了复杂度。尽管如此,分离卷积层的复杂度仍然和我们模型中采取的自注意力层和point-wise feed-forward layer
组合的复杂度之和相等。
另外,自我关注可以产生更多可解释的模型。我们检查模型中的注意力分布,并在附录中展示和讨论。注意头不仅清楚地学会执行不同的任务,许多似乎还表现出与句子的句法和语义结构相关的行为。
5. 训练
5.1 Training Data and Batching
- 数据集:
standard WMT 2014 English-German dataset
- 大小:4.5 million sentence pairs
- 句子用byte-pair encoding,其中有37000 个tokens
5.2 Hardware and Schedule
8个 NVIDIA P100 GPU,最大的模型训练了12个小时
5.3 Optimizer
optimizier : adam
lr
5.4 Regularization
训练时采用了三种正则化