Attention Is All You Need

目录

1 简介

2 背景

3 模型结构

3.1 编码器和解码器

3.2 注意力机制

3.2.1 缩放的点积注意力机制

3.2.2 多头注意力机制

3.2.3 Transformers中的注意力机制

3.3 基于位置的前馈神经网络

3.4 词嵌入和 softmax

3.5 位置编码

4 为什么选择自注意力机制

5 训练

5.1 硬件和时间

5.2 优化器

5.3 正则化

6 结论

7 transformer在机器翻译任务中的使用


Attention Is All You Need

摘要

  主流的序列转换模型都是基于复杂的循环神经网络或卷积神经网络,且都包含一个encoder和一个decoder。表现最好的模型还通过attention机制把encoder和decoder联接起来。我们提出了一个新的、简单的网络架构 — Transformers。 它只基于单独的attention机制,完全避免使用循环和卷积。在两个翻译任务上表明,我们的模型在质量上更好,同时具有更高的并行性,且训练所需要的时间更少。我们的模型在 WMT2014 英语-德语的翻译任务上取得了28.4的BLEU评分。在现有的表现最好模型的基础上,包括整合模型,提高了2个BLEU评分。在WMT2014英语-德语的翻译任务上,我们的模型在8个GPU上训练了3.5天(这个时间只是目前文献中记载的最好的模型训练成本的一小部分),创造了单模型的SOTA结果,BLEU分数为41.8,通过在大量和少量训练数据上所做的英语选区分析工作的成功,表明Transformer能很好的适应于其它任务。

1 简介

       RNN,LSTM,GRU,Gated Recurrent Neural Networks,在序列建模和转换任务上已牢固确立为最先进的方法,比如语言模型和机器翻译。此后,许多努力继续推动循环语言模型和编码器-解码器架构的界限。

       循环模型通常沿输入和输出序列的符号位置考虑计算。将位置与计算时间的步骤对齐,它们生成一系列隐藏状态 ht,作为先前隐藏状态 ht−1 和位置 t 输入的函数。这种固有的顺序性质阻碍了训练样本中的并行化,这在较长的序列长度下变得至关重要,因为内存约束会限制了样本的批处理。最近的工作通过因式分解技巧和条件计算在计算效率方面取得了显着的提高,同时也提高了后者的模型性能。然而顺序计算的基本约束仍然存在。

       在各种任务中,注意力机制已成为引人注目的序列建模和转导模型中必不可少的一个组成部分,它允许对依赖性进行建模,而不考虑它们在输入或输出序列中的距离。然而,在除少数情况外的所有情况下,这种注意力机制会与循环网络结合使用。

       在这项工作中,我们提出了Transformer,这是一种避免使用循环模型的架构,而是完全依靠注意力机制来绘制输入和输出之间的全局依赖关系。Transformer 允许实现更多的并行化,并且在八个 P100 GPU 上训练短短 12 小时后,翻译质量达到了一个新的水平。

2 背景

       减少序列计算的目标也成就了 Extended Neural GPU [16],ByteNet[18],和ConvS2S[9]的基础,它们都使用了卷积神经网络作为基础模块,并行计算所有输入和输出位置的隐藏表示。在这些模型中,将来自两个任意输入或输出位置的信号关联起来所需的操作数,随位置间的距离而增长,ConvS2S为线性增长,ByteNet为对数增长。这使得学习远距离位置之间的依赖性变得更加困难。 在Transformer中,这种情况被减少到了常数次操作,虽然代价是由于平均注意力加权位置信息降低了有效分辨率,如第3.2节所述,我们用多头注意力机制抵消这种影响。

  self-attention,有时也叫做内部注意力,是一种注意力机制,它将一个序列的不同位置联系起来,以计算序列的表示。self-attention 已经成功的运用到了很多任务上,包括阅读理解、抽象摘要、语篇蕴涵和学习任务无关的句子表征等。

  已经被证明,端到端的记忆网络使用循环attention机制替代序列对齐的循环,在简单的语言问答和语言建模任务中表现良好。

  然而,据我们所知,Transformer是第一个完全依赖于self-attetion来计算其输入和输出表示而不使用序列对齐的RNN或卷积的转换模型,在下面的章节中,我们将描述Transformer,motivate ,self-attention,并讨论它相对于[17,18]和[9]等模型的优势。

3 模型结构

       大多数有竞争力的序列转换模型都有encoder-decoder结构。这里,encoder将符号表示的输入序列( x 1 , . . . , x n ) (x_1,...,x_n)(x1​,...,xn​)映射成一个连续表示的序列z = ( z 1 , . . . , z n ) z = (z_1,...,z_n)z=(z1​,...,zn​)。给定z zz,解码器以一次生成一个字符的方式生成输出序列( y 1 , . . . , y m ) (y_1,...,y_m)(y1​,...,ym​) 。在每一步,模型都是自回归的,在生成下一个字符时,将先前生成的符号作为附加输入。

  Transformer遵循这个总体架构,使用堆叠的self-attention层、point-wise和全连接层,分别用于encoder和decoder,如图1的左半部分和右半部分所示。

3.1 编码器和解码器

       Encoder:encoder由N(N=6)个完全相同的layer堆叠而成,每层有两个子层。第一层是multi-head self-attention机制,第二层是一个简单的、位置全连接的前馈神经网络。我们在两个子层的每一层后采用残差连接,接着进行layer normalization。也就是说,每个子层的输出是LayerNorm(x + Sublayer(x)),其中Sublayer(x) 是由子层本身实现的函数。为了方便这些残差连接,模型中的所有子层以及embedding层产生的输出维度都为d_{model}=512。

       Decoder: decoder也由N(N=6)个完全相同的layer堆叠而成.除了每个编码器层中的两个子层之外,解码器还插入第三个子层,该子层对编码器的输出执行multi-head attention操作,与encoder相似,我们在每个子层的后面使用了残差连接,之后采用了layer normalization。我们也修改了decoder 中的 self-attention 子层,以防止当前位置信息中被添加进后续的位置信息。这种掩码与偏移一个位置的输出embedding相结合, 确保对第 i 个位置的预测 只能依赖小于 i 的已知输出。

       Add操作:做了个类似残差的操作,但与残差不同的是,不是用输入减去输出,而是用输入加上输出。(指Multi-Head Attention模块的输入和输出),具体操作就是将多头注意力算法中的的输入矩阵与输出矩阵的对应位置做加法运算。

       layer normalization操作:不论是layer normalization还是batch normalization,其实做的都是一件事情,都是根据 x = a * \frac{x-\bar{x}}{std+eps} + bx的分布进行调整。不同的是 \bar{x} 和 std的计算方式不同。在下图中,batch normalization的\bar{x} 和 std是延粉色方向计算的,而layer normalization是延蓝色方向计算的。这里之所以使用layer normalization而没有使用batch normalization是如果将BN应用到Transformers中会出现一些问题,由于任务中句子的长度是不固定的,如果使用BN,会导致每个位置的统计量不同。可能某个位置,某个句子没有输入了;更糟糕的是,BN无法适应于在线学习(每个批次只有一个样本)和批次数量过小的情况。BN是针对整个批次计算的,那么LN就是针对一个样本所有特征计算的,沿着d_{model}就是一个词的所有特征。

3.2 注意力机制

       Attention机制可以描述为将一个query和一组key-value对映射到一个输出,其中query,keys,values和输出均是向量。输出是values的加权求和,其中每个value的权重 通过query与相应key的兼容函数来计算。

Figure 2: (left) Scaled Dot-Product Attention. (right) Multi-Head Attention consists of several attention layers running in parallel.

3.2.1 缩放的点积注意力机制

     我们称我们的特殊attention为Scaled Dot-Product Attention(Figure 2)。输入由query、d_{k}​的key和​d_{v}的value组成。我们计算query和所有key的点积,再除以\frac{1}{\sqrt{d_{k}}}​​,然后再通过softmax函数来获取values的权重。

  在实际应用中,我们把一组query转换成一个矩阵Q,同时应用attention函数。key和valuue也同样被转换成矩阵K和矩阵V。我们按照如下方式计算输出矩阵:

       additive attention和dot-product(multi-plicative) attention是最常用的两个attention 函数。dot-product attention除了没有使用缩放因子 \frac{1}{\sqrt{d_{k}}} 外,与我们的算法相同。Additive attention使用一个具有单隐层的前馈神经网络来计算兼容性函数。尽管在理论上两者的复杂度相似,但是在实践中dot-product attention要快得多,而且空间效率更高,这是因为它可以使用高度优化的矩阵乘法代码来实现。

     当dk​的值较小时,这两种方法性能表现的相近,当dk​比较大时,addtitive attention表现优于 dot-product attention。我们认为对于大的dk​,点积在数量级上增长的幅度大,将softmax函数推向具有极小梯度的区域^{4}。为了抵消这种影响,我们对点积扩展 \frac{1}{\sqrt{d_{k}}}​倍。

      (1)、 Q,K,V,在transformer的encoder中,输入只有一个,即输入向量与位置向量的和(经过位置编码层得到的结果,位置编码层中将文本嵌入层的结果向量与位置向量进行相加),我们暂且叫做input_sum。Q,K,V就是这个input_sum通过三个linear层映射而来。  由于linear的输入和输出维度均为d_{model},所以Q,K,V的大小和input_sum的大小是一致的。如下图

       (2)、 MatMul: 这步实际是计算的 Q * K^{T}, 如下图:

       从上图可以看出Q * K^{T}的结果 scores 是一个 L * L 的矩阵(L为句字长度),其中scores中的[i,j]位置表示的是Q中的第 i 行的字和 K^{T}中第 j 列的相似度(也可以说是重要度,我们可以这么理解,在机器翻译任务中,当我们翻译一句话的第 i 个字的的时候,我们要考虑原文中哪个位置的字对我们现在要翻译的这个位置的字的影响最大)。

      (3)、 Scale :这部分就是对上面的 scores 进行了个类似正则化的操作。
       scores = \frac{scores}{\sqrt{d_{k}}}(这里要说一下d_{q},论文中给出的是 d_{h},也即 d_{model} / h,因为论文中做了multi-head,所以 d_{q} =  d_{h}),这里解释下除以 \sqrt{d_{q}}的原因,原文中是这样描述的“ 对于大的dk​,点积在数量级上增长的幅度大,将softmax函数推向具有极小梯度的区域^{4}。为了抵消这种影响,我们对点积扩展 \frac{1}{\sqrt{d_{k}}}​倍 ”

      (4)、 Mask: 这步使用一个很小的值,对指定位置进行覆盖填充。这样,在之后计算softmax时,由于我们填充的值很小,所以计算出的概率也会很小,基本就忽略了。(从另一个角度来看:softmax计算公式:\frac{e^{x_{i}}}{\sum_{i=1}^{k}e^{x_{i}}},当 x = 0 时(padding的值),分子 e^{0} = 1, 这可不是一个很小的值。所以为了降低padding位置的影响,我们也要把padding位置的数值替换成更小的值,如 -e^{9}),mask操作在encoder和decoder过程中都存在,在encoder中我们是对padding的值进行mask,在decoder中我们主要是为了不让前面的词在翻译时看到未来的词,所以对当前词之后的词的信息进行mask。encoder中关于padding的mask做法:输入中有两个pad字符,scores中的x都是pad参与计算产生的,为了排除pad产生的影响,提供了如图的mask,把 scores 与mask的位置一一对应,如果mask的值为0,则scores的对应位置填充一个非常小的负数(例如:-e^{9} ),最终得到的是下图中的最后一个矩阵。使用下面的伪代码实现:

if mask is not None:
        scores = torch.masked_fill(scores,mask == 0,-1e9) 


       ​但是需要注意的是上图中的mask只有后两列为0,并没有把下两行也都设置成0,并没有完全覆盖scores矩阵中所有的“x”。

      (5)、 SoftMax: 对scores中的数据按行做softmax。这样就把权得转换成了概率。

       (6)、 ​MatMul: 这步就是使用softmax后的概率值与V VV矩阵做矩阵乘法。

点击超链接,注意力机制代码实现

3.2.2 多头注意力机制

     相比于使 d_{model} ​维度的queries,keys,values执行一个attention函数,我们发现使用不同的学习到的线性映射把queries, keys 和 values线性映射到d_{k}d_{k}​ 和 d_{v}​维度h次是有益的。在queries,keys和values的每个映射版本上,我们并行的执行attention函数,生成d_{v}维输出值。它们被拼接起来再次映射,生成一个最终值,如 Figure 2 中所示。

   Multi-head attention允许模型把不同位置子序列的表示都整合到一个信息中。如果只有一个attention head,它的平均值会削弱这个信息。

        在这项工作中,我们采用 h=8 个并行attention层或head。 对每个head,我们使用 d_{k} = d_{v} = d_{model} / h = 64。 由于每个head尺寸上的减小,总的计算成本与具有全部维度的单个head attention相似。

       multi-head attention中的 multi-head的意思解释如下:假设 d_{model} = 512,h = 8,也即为8个头,QKV三个矩阵是encoder的输入经过三个linear映射而成,它们的大小均是\left ( b,n,d \right ),(其中b是批量处理长度,n是一个句子的长度,也就是句子中单词的数量,d是词嵌入维度)。由于QKV的维度都为\left ( n,d \right ),multi-head就是在词嵌入的维度d_{model}上进行切割,把数据切成等长的8段(h=8),这样QKV三个矩阵都被切割成了8段,然后对应的QKV子段分成一组,每个组都通过前面3.2.1的注意力机制算法计算得到结果,这样的结果我们会得到8个,然后把这8个结果再拼成一个结果,就multi-head的结果。

       Masked Multi-Head Attention:Scaled Dot-Product Attention 中也有mask机制,但是这里的区别在于maked的策略不同,在encoder中我们是把padding给masked掉,在这里我们除了要考虑padding,还要考虑预测时的未来变量问题,换句话说,我们是用一句话中的前 N-1个字预测第N个字,那么我们在预测第N个字时,就不能让模型看到第N个字之后的信息,所以这里们把预测第N个字时,第N(包括)个字之后的字都masked掉。我们假设预测序列为’i like this apple’,则我们要做如下的mask(粉色的0实际上是没有的,这里表示对应的位置为pad的值)。

点击超链接,多头注意力机制代码实现

       编码器和解码器中的Multi-Head Attention多头注意力机制的实现区别:代码实现上完全相同,区别在编码器只有一个输入,编码器把此输入经过三个linear映射成QKV , 而解码器的输入有两个,一个是decoder的输入经过位置编码层传过来的值(为了方便,我们叫它input_x),一个是encoder最终结果(我们暂叫它input_memory), 编码器把input_x通过一个linear映射成了Q,然后通过两个linear把input_memory映射成 KV ,其它的与编码器完全一致。

3.2.3 Transformers中的注意力机制

multi-head attention在Transformer中有三种不同的使用方式:

  • 在encoder-decoder attention层中,queries来自前面的decoder层,而keys和values来自encoder的输出。这使得decoder中的每个位置都能关注到输入序列中的所有位置。 这是模仿序列到序列模型中典型的编码器—解码器的attention机制。
  • encoder包含self-attention层。 在self-attention层中,所有的key、value和query来自同一个地方,在这里是encoder中前一层的输出。 encoder中的每个位置都可以关注到encoder上一层的所有位置。
  • 类似地,decoder中的self-attention层允许decoder中的每个位置都关注decoder层中当前位置之前的所有位置(包括当前位置)。 为了保持解码器的自回归特性,需要防止解码器中的信息向左流动。我们在scaled dot-product attention的内部 ,通过屏蔽softmax输入中所有的非法连接值(设置为 −∞)实现了这一点。

3.3 基于位置的前馈神经网络

       除了encoder子层之外,我们的encder和decoder中的每个层还包含一个全连接的前馈网络,该网络分别单独应用于每一个位置。这包括两个线性转换,中间有一个ReLU激活。

  尽管线性变换在不同位置上是相同的,但它们在层与层之间使用不同的参数。 它的另一种描述方式是两个内核大小为1的卷积。 输入和输出的维度为 d_{model} = 512 ,内部层的维度为d_{ff}​ = 2048。

       在Transformers中要实现前馈神经网络要先把输入向量从d_{model} = 512映射到2048维,然后再映射到512维。实现时,就是使用两个linear层,第一个linear的输入是512维,输出是2048维,第二个linear的输入是2048,输出是512。

3.4 词嵌入和 softmax

       与其他序列转换模型类似,我们使用学习到的嵌入词向量 将输入字符和输出字符转换为维度为d_{model}的向量。我们还使用普通的线性变换和softmax函数将decoder输出转换为预测的下一个词符的概率。在我们的模型中,两个嵌入层之间和pre-softmax线性变换共享相同的权重矩阵,类似于。 在嵌入层中,我们将这些权重乘以\sqrt{d_{model}}。​​

点击超链接,文本嵌入层代码实现

3.5 位置编码

       由于我们的模型不包含循环或卷积,为了让模型利用序列的顺序信息,我们必须加入序列中关于字符相对或者绝对位置的一些信息。 为此,我们在encoder和decoder堆栈底部的输入嵌入中添加“位置编码”。 位置编码和嵌入的维度d_{model}相同,所以它们两个可以相加。有多种位置编码可以选择,例如通过学习得到的位置编码和固定的位置编码。

Table1:Maximum path lengths, per-layer complexity and minimum number of sequential operations for different layer types. n is the sequence length, d is the representation dimension, k is the kernel size of convolutions and r the size of the neighborhood in restricted self-attention.

       在这项工作中,我们使用不同频率的正弦和余弦函数:

       PE 模块的主要做用是把位置信息加入到输入向量中,使模型知道每个字的位置信息。对于每个位置的 PE 是固定的,不会因为输入的句子不同而不同,且每个位置的PE大小为1*n(n为word embedding 的dim size),transformer中使用正余弦波来计算PE。 

       其中pos代表的是一个字在句子中的位置,从0到句子长度减1,是下图中红色的序号。 i代表的维度,即dim的序号,是下图中蓝色的序号。当 i 为偶数时,这个位置使用前面的sin函数填充;当 i 为奇数时,这个位置使用前面的 cos 函数来填充。

       也就是说,位置编码的每个维度对应于一个正弦曲线。波长形成了从2π到10000·2π的几何数列。我们之所以选择这个函数,是因为我们假设它可以让模型很容易地通过相对位置来学习,因为对任意确定的偏移k,  PE_{pos+k}可以表示为PE_{pos}的线性函数。

  我们还尝试使用预先学习的positional embeddings来代替正弦波,发现这两个版本产生了几乎相同的结果 (see Table 3 row (E))。我们之所以选择正弦曲线,是因为它允许模型扩展到比训练中遇到的序列长度更长的序列。

点击超链接,位置编码代码实现


4 为什么选择自注意力机制

        self-attention层比recurrent layer和convolutional layer具有更小的总计算复杂度、可以并行化的计算量和更短的最大路径长度。此外,self-attention层还可以产生更多可解释的模型,每个attention head可以清楚地学习执行不同的任务,并表现出与句子的句法和语义结构相关的行为。

5 训练

5.1 硬件和时间

       在一台具有8个 NVIDIA P100 gpu的机器上训练我们的模型。对于paper中描述的使用超参数的基础模型,每个训练步骤大约需要0.4秒。

5.2 优化器

        使用Adam优化器,其中β1 = 0.9, β2 = 0.98及ϵ= 10-9。我们根据以下公式在训练过程中改变学习率:

这对应于在第一次warmup_steps 步骤中线性地增加学习速率,并且随后将其与步骤数的平方根成比例地减小。 我们使用 warmup_steps = 4000。

5.3 正则化

       训练中采用三种正则化:

       Residual Dropout 我们在对每个子层的输出上执行dropout操作,这个操作在additive操作(子层的输出加上子层的输入)和 normalized操作之前。 此外,在编码器和解码器堆栈中,我们将丢弃应用到嵌入和位置编码的和。 对于基础模型,我们使用P_{drop} = 0.1​ 丢弃率。

       Label Smoothing 在训练过程中,我们采用了值 \varepsilon _{ls} = 0.1的标签平滑。这会影响ppl,因为模型学习到了更多的不确定性,但提高了准确率和BLEU评分。

6 结论

       本文介绍了Transformer模型,它是第一个完全基于attention的序列转换模型,用multi-headed self-attention取代了encoder-decoder架构中最常用的recurrent layers。对于翻译任务,Transformer比基于循环或卷积层的体系结构训练更快,并在WMT 2014英语-德语和WMT 2014英语-法语翻译任务中取得了最好的结果。未来,我们计划将Transformer扩展到涉及输入和输出模式的其他任务,并研究局部的、受限的attention机制,以有效地处理图像、音频和视频等大型输入和输出。同时,我们的另一个研究目标是让生成具有更少的顺序性。

7 transformer在机器翻译任务中的使用

     把transformer做为一个特征提取器放在一个Encoder-Decoder(下文用Encoder-Stack和Decoder-Stack,用以和transformer的encoder, decoder区分)架构中的,具体细节见下图:

       训练时的数据走向及流程:

     (1)、数据 X 输入到编码器中得到输出 encoderOutput

     (2)、encoderOutput 作为 key 和 value 的原始输入,输入到解码器中,解码器的query作为上一轮解码器的输出

       decoder stack的输入(上图中的query),前面说过了,在transformer中,decoder的核心思想是用一个句子中的前 N-1个字,预测第 N个字,但在预测第一个字的时候,前面没有字,这时我们可以在每句话前面加上一个固定的开始标志(bos), 这样相当于把整个句子右移了一位。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值