《Attention Is All You Need》
目录
- 摘要(Abstract)
- 1、介绍(Introduction)
- 2、背景(Background)
- 2.1 WMT翻译数据集
- 2.2 编码器-解码器(seq2seq)
- 2.2.1 编码器
- 2.2.2 解码器
- 2.2.3 训练seq2seq模型
- 2.3 注意力机制
- 2.3.1 计算背景变量
- 2.3.2 矢量化计算
- 2.3.3 更新隐藏状态
- 3、模型体系结构(Model Architecture)
- 3.1 编码器和解码器堆叠(Encoder and Decoder Stacks)
- 3.2 注意力(Attention)
- 3.2.1 缩放点乘注意力机制(Scaled Dot-Product Attention)
- 3.2.2 多头注意力机制(Multi-Head Attention)
- 3.2.3 注意力模型在我们模型中的应用(Applications of Attention in our Model)
- 3.3 基于位置的前馈神经网络(Position-wise Feed-Forward Networks)
- 3.4 嵌入和softmax(Embeddings and Softmax)
- 3.5 位置编码
- 3.6 Mask机制
- 3.6.1 Sequence Mask
- 3.6.2 Padding Mask
- 4、为什么选择自注意力机制(Why Self-Attention)
- 5、笔记
- 5.1 计算Attention权值的公式
- 5.2 Encoder Self-Attention
- 5.3 Decoder Self-Atention
- 5.4 self-attention和attention的区别
- 5.5 self-attention和卷积神经网络的区别
- 5.6 positional encoding位置编码
- 5.7 为什么要残差连接
- 5.8 为什么选择自注意力机制
- 5.9 Mask机制
- 5.10 Label Smoothing
- 6、历史意义
摘要(Abstract)
\space \space \space \space \space \space \space主流的序列变换模型都是基于包括编码器和解码器的复杂循环神经网络或者卷积神经网络建立的。性能最好的模型还通过注意力机制连接编码器和解码器。我们提出了一种新的简单的网络体系结构Transformer,它完全基于注意力机制,不需要循环神经网络和卷积神经网络。
\space \space \space \space \space \space \space在两个机器翻译任务上的实验表明,我们提出的模型在质量上更优越,同时更具并行性,需要的训练时间明显减少。
\space \space \space \space \space \space \space我们的模型在WMT2014英语到德语翻译任务中达到了28.4%的BLEU,比现有的最好结果(包括系综)提高了2个多BLEU[1]^{[1]}[1]。(评价机器翻译结果通常使用BLEU(Bilingual Evaluation Understudy))。
\space \space \space \space \space \space \space在WMT2014英法翻译任务上,我们的模型在8个GPU上训练3.5天,创造了新的单模(single-model)最先进的BLEU得分41.8%,这只是历史文献中最好的模型训练成本的一小部分。
\space \space \space \space \space \space \space通过将其成功地应用于大量和有限训练数据的英语选区分析中,我们发现表明Transformer对其他任务具有很好的通用性。将位置与计算时间中的步骤对齐,它们根据前一隐藏状态ht−1h_{t−1}ht−1和位置ttt的输入来生成隐藏状态hth_tht的序列。
1、介绍(Introduction)
\space \space \space \space \space \space \space循环神经网络,特别是长短期记忆神经网络(LSTM)和门控循环神经网络(GRU)已被牢固地确立为序列建模和翻译问题(例如语言建模和机器翻译)中的最新方法。此后,人们一直在努力扩大循环语言模型和编码器-解码器体系结构的界限。
\space \space \space \space \space \space \space循环模型通常沿输入和输出序列的符号位置考虑计算。这种固有的顺序性质阻止了训练数据的并行化,这在较长的序列长度上变得至关重要,因为内存限制限制了示例之间的批处理。最近的工作通过分解技巧和条件计算在计算效率上取得了显着提高,同时在后者的情况下还提高了模型性能。 但是,顺序计算的基本约束仍然存在。
\space \space \space \space \space \space \space注意机制已经成为各种任务中令人信服的序列建模和翻译模型的一个组成部分,允许对相关性进行建模,而不考虑它们在输入或输出序列中的距离。然而,除了少数情况外,这种注意机制都是与循环网络结合使用的。
\space \space \space \space \space \space \space在本文中,我们提出了Transformer,这是一个避免重复的模型体系结构,完全依赖于一种注意力机制来描述输入和输出之间的全局依赖关系。Transformer允许更多的并行化,在8个P100 GPU上进行短短12个小时的训练后,翻译质量就可以达到新的艺术水平。
2、背景(Background)
\space \space \space \space \space \space \space减少顺序计算的目标也构成了扩展神经GPU、ByteNet和ConvS2S的基础,它们都使用卷积神经网络作为基本构件,并行计算所有输入和输出位置的隐藏表示。在这些模型中,关联来自两个任意输入或输出位置的信号所需的操作数量随着位置之间的距离增长,对于ConvS2S是线性的,对于ByteNet是对数的。这使得学习相距较远的位置之间的依赖关系变得更加困难。在Transformer中,这可以减少到恒定的操作次数,尽管会因平均注意力加权位置而导致有效分辨率降低的代价,这是我们用3.2中所述的多头注意力抵消的效果。
\space \space \space \space \space \space \space自我注意力机制(self-attention),有时被称为内部注意力,是一种将单个序列的不同位置联系起来以计算该序列的表示的注意力机制。自我注意已成功用于各种任务中,包括阅读理解,抽象性摘要,文本蕴涵和学习与任务无关的句子表示。
\space \space \space \space \space \space \space基于循环注意力机制的端到端记忆网络,而不是按顺序排列的循环神经网络,并且已经被证明在简单语言问题回答和语言建模任务上表现良好[34]。
\space \space \space \space \space \space \space据我们所知,Transformer是第一个完全依靠自我注意力来计算其输入和输出表示的转导模型,而无需使用序列对齐的RNN或卷积。在以下各节中,我们将描述Transformer,描述自我注意力机制,并讨论其相对于某些模型等模型的优势。
2.1 WMT翻译数据集
WMT数据集包括德语翻译成英语、法语翻译成英语等数据集,数据集量级在百万级别。我们可以在该网站上看WMT翻译数据集的各大模型的实验效果,可以看到第一名为Transformer Big + BT。
2.2 编码器-解码器(seq2seq)
在自然语言处理的很多应用中,输入和输出都可以是不定长序列,以机器翻译为例,输入可以是一段不定长的英语文本序列,输出可以是一段不定长的法语文本序列,例如:
英语输入:“They are watching.”
法语输出:“Ils regardent.”
当输入和输出都是不定长序列时,我们可以使用编码器-解码器或者seq2seq模型。这两个模型本质上都用到了两个循环神经网络,分别叫做编码器和解码器。编码器用来分析输入序列,解码器用来生成输出序列。
上图描述了使用编码器-解码器将上述英语句子翻译成法语句子的一种方法,在训练数据集中,我们可以在每个句子后面附上特殊符号“”(end of sequence)以表示序列的终止。
编码器每个时间步的输入依次为英语句子中的单词、标点和特殊符号“”。上图使用了编码器在最终时间步的隐藏状态作为输入句子的表征或编码信息。解码器在各个时间步中使用输入句子的编码信息和上个时间步的输出以及隐藏状态作为输入。我们希望解码器在各个时间步能正确依次输出翻译后的法语单词、标点和特殊符号“”。
需要注意的是,解码器在最初时间步的输入用到了一个表示序列开始的特殊符号“”(begining of sequence)。
2.2.1 编码器
编码器的作用是把一个不定长的输入序列变换成一个定长的背景变量c,并在该背景变量中编码输入序列信息。编码器可以使用循环神经网络。
让我们仅考虑批量大小为1的时序数据样本。假设输入序列是x1,x2,...,xTx_1,x_2,...,x_Tx1,x2,...,xT,例如xix_ixi是输入句子中的第i个词。在时间步t,循环神经网络将输入xtx_txt的特征向量xtx_txt和上个时间步的隐藏状态ht−1h_{t-1}ht−1变换为当前时间步的隐藏状态hth_tht。我们可以使用函数f表达循环神经网络隐藏层的变换:
ht=f(xt,ht−1)h_t=f(x_t,h_{t-1})ht=f(xt,ht−1)
接下来,编码器通过自定义函数q将各个时间步的隐藏状态变换为背景变量:
c=q(h1,...,hT)c=q(h_1,...,h_T)c=q(h1,...,hT)
例如,当选择q(h1,...,hT)=hTq(h_1,...,h_T)=h_Tq(h1,...,hT)=hT时,背景向量是输入序列最终时间步的隐藏状态hTh_ThT。
以上描述的编码器是一个单向的循环神经网络,每个时间步的隐藏状态只取决于该时间步及之前的输入子序列。我们也可以使用双向循环神经网络构造编码器。在这种情况下,编码器每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入),并编码了整个序列的信息。
2.2.2 解码器
上面已经介绍,编码器输出的背景变量c编码了整个输入序列x1,...,xTx_1,...,x_Tx1,...,xT的信息。给定训练样本中的输出序列y1,y2,...,yT′y_1,y_2,...,y_{T'}y1,y2,...,yT′,对每个时间步t′t't′(符号与输入序列或编码器的时间步t有区别),解码器输出yt′y_{t'}yt′的条件概率将基于之前的输出序列y1,...,yt′−1y_1,...,y_{t^{'}-1}y1,...,yt′−1和背景向量c,即P(yt′∣y1,...,yt′−1,c)P(y_{t^{'}}|y_1,...,y_{t^{'}-1},c)P(yt′∣y1,...,yt′−1,c)。
为此,我们可以使用另一个循环神经网络作为解码器。在输出序列的时间步t′t^{'}t′,解码器将上一时间步的输出yt′−1y_{t^{'}-1}yt′−1以及背景变量c作为输入,并将它们与上一时间步的隐藏状态st′−1s_{t^{'}-1}st′−1变换为当前时间步的隐藏状态st′s_{t^{'}}st′。因此,我们可以用函数g表达解码器隐藏从的变换:
st′=g(yt′−1,c,st′−1)s_{t^{'}}=g(y_{t^{'}-1},c,s_{t^{'}-1})st′=g(yt′−1,c,st′−1)
有了解码器的隐藏状态后,我们可以使用自定义的输出层和softmax运算来计算P(yt′∣y1,...,yt′−1,c)P(y_{t^{'}}|y_1,...,y_{t^{'}-1},c)P(yt′∣y1,...,yt′−1,c)。例如基于当前时间步的解码器隐藏状态st′s_{t^{'}}st′、上一时间步的输出yt′−1y_{t^{'}-1}yt′−1以及背景变量c来计算当前时间步输出yt′y_{t^{'}}yt′的概率分布。
2.2.3 训练seq2seq模型
根据最大似然估计,我们可以最大化输出序列基于输入序列的条件概率:
P(y1,⋯,yT′∣x1,⋯,xT)=∏t′=1T′P(yt′∣y1,⋯,yt′−1,x1,⋯,xT)P\left(y_{1}, \cdots, y_{T^{\prime}} \mid x_{1}, \cdots, x_{T}\right)=\prod_{t^{\prime}=1}^{T^{\prime}} P\left(y_{t^{\prime}} \mid y_{1}, \cdots, y_{t^{\prime}-1}, x_{1}, \cdots, x_{T}\right)P(y1,⋯,yT′∣x1,⋯,xT)=t′=1∏T′P(yt′∣y1,⋯,yt′−1,x1,⋯,xT)
=∏t′=1T′P(yt′∣y1,⋯,yt′−1,c)=\prod_{t^{\prime}=1}^{T^{\prime}} P\left(y_{t^{\prime}} \mid y_{1}, \cdots, y_{t^{\prime}-1}, c\right)=t′=1∏T′P(yt′∣y1,⋯,yt′−1,c)
并得到该输出序列的损失:
−logP(y1,⋯,yT′∣x1,⋯,xT)=−∑i=1T′logP(yt′∣y1,⋯,yt′−1,c)-\log P\left(y_{1}, \cdots, y_{T^{\prime}} \mid x_{1}, \cdots, x_{T}\right)=-\sum_{i=1}^{T^{\prime}} \log P\left(y_{t^{\prime}} \mid y_{1}, \cdots, y_{t^{\prime}-1}, c\right)−logP(y1,⋯,yT′∣x1,⋯,xT)=−i=1∑T′logP(yt′∣y1,⋯,yt′−1,c)
在模型训练中,所有输出序列损失的均值通常作为需要最小化的损失函数。在seq2seq的模型预测中,我们需要将解码器在上一个时间步的输出作为当前时间步的输入。
与此不同,在训练中我们可以将标签序列(训练集的真实输出序列)在上一个时间步的标签作为解码器在当前时间步的输入。这叫做强制教学(teacher forcing)。
2.3 注意力机制
在上面介绍seq2seq模型的解码器在各个时间步依赖相同的背景变量来获取输入序列信息。当编码器为循环神经网络时,背景变量来自它最终时间步的隐藏状态。
现在我们再次考虑上面提到的翻译例子:
英语输入:“They are watching.”
法语输出:“Ils regardent.”
不难想象,解码器在生成输出序列中的每一个词时可能只需要利用输入序列某一部分的信息。例如在输出序列的时间步1,解码器可以主要依赖“they”“are”的信息来生成“Ils”,在时间步2则主要使用来自“watching”的编码信息生成“regardent”,最后在时间步3则直接映射句号“.”。这看上去就像是在解码器的每一时间步对输入序列中不同时间步的表征或者编码信息分配不同的注意力一样。这也是注意力机制的由来。
仍然以循环神经网络为例,注意力机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景向量。解码器在每一时间步调整这些权重,即注意力权重,从而能够在不同时间步分别关注序列中的不同部分并编码进相应时间步的背景向量。这里我们将讨论注意力机制是怎么工作的。
在seq2seq中我们区分了输入序列或编码器的索引t与输出序列或解码器的索引t′t't′。这里,解码器在时间步t′t't′的隐藏状态st′=g(yt′−1,c,st′−1)s_{t'}=g(y_{t'-1},c,s_{t'-1})st′=g(yt′−1,c,st′−1),其中yt′−1y_{t'-1}yt′−1是上一时间步t′−1t'-1t′−1的输出yt′−1y_{t'-1}yt′−1的表征,且任一时间步t′t't′使用相同的背景变量c。但是在注意力机制中,解码器的每一时间步将使用可变的背景变量。记ct′c_{t'}ct′是解码器在时间步t′t't′的背景向量,那么解码器在该时间步的隐藏状态可以改写为:
st′=g(yt′−1,ct′,st′−1)s_{t'}=g(y_{t'-1},c_{t'},s_{t'-1})st′=g(yt′−1,ct′,st′−1)
这里关键是如何计算背景变量ct′c_{t'}ct′和如何利用它来更新隐藏状态st′s_{t'}st′,下面将分别描述这两个关键点。
2.3.1 计算背景变量
我们先来描述第一个关键点,即计算背景变量。下图描绘了注意力机制如何为解码器在时间步2计算背景向量。
首先,函数a根据解码器在时间步1的隐藏状态和编码器在各个时间步的隐藏状态计算softmax运算的输入。softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从而得到背景变量。
具体来说,令编码器在时间步t的隐藏状态为hth_tht,且总时间步数为T。那么解码器在时间步t′t't′的背景变量为所有编码器隐藏状态的加权平均:
ct′=∑t=1Tαt′thtc_{t^{\prime}}=\sum_{t=1}^{T} \alpha_{t' t} \boldsymbol{h}_{t}ct′=t=1∑Tαt′tht
其中t′t't′给定时,权重at′ta_{t't}at′t在t=1,...,Tt=1,...,Tt=1,...,T时的值是一个概率分布,为了得到概率分布,我们可以使用softmax运算:
αt′t=exp(et′t)∑k=1Texp(et′k),t=1,⋯,T\alpha_{t^{\prime} t}=\frac{\exp \left(e_{t^{\prime} t}\right)}{\sum_{k=1}^{T} \exp \left(e_{t^{\prime} k}\right)}, \quad t=1, \cdots, Tαt′t=∑k=1Texp(et′k)exp(et′t),t=1,⋯,T
现在我们需要定义如何计算上式中softmax运算的输入et′te_{t't}et′t。由于et′te^{t't}et′t同时取决于解码器的时间步t′t't′和编码器的时间步t,我们不妨以解码器在时间步t′−1t'-1t′−1的隐藏状态st′−1s_{t'-1}st′−1与编码器在时间步t的隐藏状态hth_tht为输入,并通过函数a计算et′te_{t't}et′t:
et′t=a(st′−1,ht)e_{t^{\prime} t}=a\left(\boldsymbol{s}_{t^{\prime}-1}, \boldsymbol{h}_{t}\right)et′t=a(st′−1,ht)
这里函数有多种选择,如果两个输入向量长度相同,一个简单的选择是计算他们的內积a(s,h)=sTha(s,h)=s^Tha(s,h)=sTh。而最早提出注意力机制的论文则将输入连结后通过含单隐层的多层感知机变换:
a(s,h)=v⊤tanh(Wss+Whh)a(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{v}^{\top} \tanh \left(\boldsymbol{W}_{s} \boldsymbol{s}+\boldsymbol{W}_{h} \boldsymbol{h}\right)a(s,h)=v⊤tanh(Wss+Whh)
其中v、WsW_sWs、WhW_hWh都是可以学习的模型参数。
2.3.2 矢量化计算
我们可以对注意力机制采用更高效的矢量化计算。广义上,注意力机制的输入包括查询项以及一一对应的键项和值项,其中值项是需要加权平均的一组项。在加权平均中,值项的权重来自查询项以及该值项对应的键项的计算。
在上面的例子中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。让我们考虑一个常见的简单情形,即编码器和解码器的隐藏单元个数均为h,且函数a(s,h)=sTha(s,h)=s^Tha(s,h)=sTh。假设我们希望根据解码器单个隐藏状态st′−1∈Rhs_{t'-1}\in R^hst′−1∈Rh和编码器所有隐藏状态ht∈Rh,t=1,...,Th_t\in R^h,t=1,...,Tht∈Rh,t=1,...,T来计算背景向量ct′∈Rhc_{t'}\in R^hct′∈Rh。我们可以将查询项矩阵Q∈R1∗hQ\in R^{1* h}Q∈R1∗h设为st′−1Ts^T_{t'-1}st′−1T,并令键项矩阵K∈RT∗hK\in R^{T*h}K∈RT∗h和值项矩阵V∈RT∗hV\in R^{T*h}V∈RT∗h相同且第t行均为htTh^T_thtT。此时,我们只需要通过计算矢量化计算:
softmax(QKT)Vsoftmax(QK^T)Vsoftmax(QKT)V
即可算出转置后的背景向量ct′Tc^T_{t'}ct′T。当查询项矩阵Q的行数为n时,上式将得到n行的输出矩阵。输出矩阵与查询项矩阵在向同行上一一对应。
2.3.3 更新隐藏状态
现在我们描述第二个关键点,即更新隐藏状态。以门控循环单元为例,在解码器中我们可以对门控循环单元的设计稍作修改,从而改变上一时间步t′−1t'-1t′−1的输出yt′−1y_{t'-1}yt′−1、隐藏状态st′−1s_{t'-1}st′−1和当前时间步t′t't′的含注意力机制的背景变量ct′[1]c^{[1]}_{t'}ct′[1]。解码器在时间步t′t't′的隐藏状态为:
st′=zt′⊙st′−1+(1−zt′)⊙st′~s_{t'}=z_{t'}\odot s_{t^{ \prime }-1}+(1-z_{t^{ \prime }}) \odot \tilde{s_{t'}} st′=zt′⊙st′−1+(1−zt′)⊙st′~
其中重置门、更新门和候选隐藏状态分别为:
rt′=σ(Wyryt′−1+Wsrst′−1+Wcrct′+br)r_{t'}=\sigma (W_{yr}y_{t'-1}+W_{sr}s_{t'-1}+W_{cr}c_{t'}+b_r)rt′=σ(Wyryt′−1+Wsrst′−1+Wcrct′+br)
zt′=σ(Wyzyt′−1+Wszst′−1+Wczct′+bz)z_{t'}=\sigma(W_{yz}y_{t'-1}+W_{sz}s_{t'-1}+W_{cz}c_{t'}+b_z)zt′=σ(Wyzyt′−1+Wszst′−1+Wczct′+bz)
st′~=tanh(Wysyt′−1+Wss(st′−1⊙rt′)+Wcsct′+bs)\tilde{s_{t'}} = tanh(W_{ys}y_{t'-1}+W_{ss}(s_{t'-1}\odot r_{t'})+W_{cs}c_{t'}+b_s)st′~=tanh(Wysyt′−1+Wss(st′−1⊙rt′)+Wcsct′+bs)
3、模型体系结构(Model Architecture)
\space \space \space \space \space \space \space大多数有竞争性的神经序列转换模型都具有编码器-解码器结构。编码器将输入序列(x1,...,xn)(x_1,...,x_n)(x1,...,xn)映射到连续表示序列z=(z1,...,zn)z=(z_1,...,z_n)z=(z1,...,zn)。给定z,解码器一次生成一个元素符号的输出序列(y1,...,ym)(y_1,...,y_m)(y1,...,ym)。在每一步,模型都是自回归的,在生成下一步时使用先前生成的符号作为附加输入。
\space \space \space \space \space \space \spaceTransformer遵循这个整体架构,对编码器和解码器使用堆叠的自注意力层和逐点的全连接层,分别显示在下图的左半部分和右半部分。
3.1 编码器和解码器堆叠(Encoder and Decoder Stacks)
\space \space \space \space \space \space \space编码器:编码器由N=6个(注意图中的左边和右边都有一个N,表示相同的结构有N个)相同层的堆叠组成。每层都有两个子层。第一层是多头自注意力机制层(multi-head self-attention),第二层是简单的全连接前馈网络。我们在两个子层的每一个周围采用残差连接,随后是层归一化(layer normalization:LN)。也就是说,每个子层的输出是LayerNorm(x+sublayer(X))LayerNorm(x+sublayer(X))LayerNorm(x+sublayer(X)),其中sublayer(X)sublayer(X)sublayer(X)是子层本身实现的功能。为了便于残差连接,模型中的所有子层以及嵌入层输入和输出的向量维度设置为512维。
\space \space \space \space \space \space \space解码器:解码器由N=6个相同层堆叠组成。除了编码器中的两个子层之外,解码器还插入第三个子层,该第三子层对编码器的输出执行多头注意力机制,即捕获编码器输出和解码器输出之间的attention。与编码器类似,我们在每个子层周围使用残差连接,然后进行层归一化(layer normalization:LN)。我们还修改了解码器中的自注意力子层,以防止当前位置关注后续位置。这种掩蔽与输出嵌入偏移一个位置的事实相结合,确保对位置i的预测只能依赖于小于i的位置处的已知输出。也就是说,在计算当前位置的 self-attention 时屏蔽掉了当前位置之后的序列值,这意味着:当前位置的 attention 只能依赖于它之前的结果,不能依赖它之后的结果。
3.2 注意力(Attention)
\space \space \space \space \space \space \space注意力(attention)函数可以描述为将查询(query)和一组键(key)-值(val)对映射到输出,其中查询(query)、键(key)、值(value)和输出都是向量。输出被计算为值的加权和,其中分配给每个值的权重是由查询与相应键的兼容性函数计算的。
3.2.1 缩放点乘注意力机制(Scaled Dot-Product Attention)
\space \space \space \space \space \space \space我们把这种特殊的注意力机制称为“缩放点乘注意力机制”,输入包括维度为dkd_kdk的查询和键,以及维度为dvd_vdv的值。我们计算所有键(key)和查询(query)的点积,将每个点积除以dk\sqrt{d_k}dk
\space \space \space \space \space \space \space在实践中,我们同时计算一组查询(query)的注意力函数,这些查询(query)被打包到一个矩阵Q中。键(key)和值(value)也被打包到矩阵K和V中。我们将输出矩阵计算为:Attention (Q,K,V)=softmax(QKTdk)V\text { Attention }(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) VAttention(Q,K,V)=softmax(dk
a(s,h)=vTtanh(Wss+Whh)a(s,h)=v^Ttanh(W_ss+W_hh)a(s,h)=vTtanh(Wss+Whh)
\space \space \space \space \space \space \space虽然两者在理论复杂性上相似,但点积注意力在实践中要快得多,空间效率更高,因为它可以使用高度优化的矩阵乘法代码来实现。
\space \space \space \space \space \space \space对于较小的维度为dkd_kdk的值(value)而言,这两种机制的表现类似,对于较大的维度为dkd_kdk值(value)而言,在没有进行缩放的情况下,加性注意力的效果优于点积的注意力。我们怀疑,对于较大的维度为dkd_kdk的值(value),点积的幅度会变大,从而将Softmax函数推入其梯度极小的区域。为了抵消这种影响,我们将点积缩放1dk\frac{1}{\sqrt{d_k}}dk
通过一个例子简单演示一下缩放点乘注意力机制,对于上图中的单词Thinking,通过Embedding获得对应的嵌入向量表示,通过线性变换得到对应的q1q_1q1,k1k_1k1,v1v_1v1。然后通过缩放点乘注意力公式和softmax得到对应的权重,最后将该权重和v1v_1v1进行相乘,最后累加得到最终的结果。
我们也可以从下面的图进行理解,给定一个句子输入[x1,x2,x3,x4][x_1,x_2,x_3,x_4][x1,x2,x3,x4],对于每个单词,都可以获得其对应的qqq,kkk,vvv。通过qqq和kkk得到归一化的权重a^\hat{a}a^,将权重a^\hat{a}a^和vvv进行相乘得到累加得到当前词的整体信息。
3.2.2 多头注意力机制(Multi-Head Attention)
我们发现,通过使用不同的线性投影分别将dqd_qdq,dkd_kdk,dvd_vdv维度的query,key和value进行h次线性投影,而不是使用dmodeld_{model}dmodel维度的query,key和value来执行单一注意力,能获得更好的结果。然后,在这些查询(query)、键(key)和值(value)的每个线性投影上,我们并行执行注意功能,从而产生dvd_vdv维输出值。这些值被连接起来并再次映射,产生最终的输出值,结构如下图所示。
多头注意力允许模型共同关注来自不同位置的不同表示子空间的信息:MultiHead(Q,K,V)=Concat (head 1,…,head h)WOwhere head i=Attention (QWiQ,KWiK,VWiV)\begin{aligned} \operatorname{MultiHead}(Q, K, V) &=\text { Concat }\left(\text { head }_{1}, \ldots, \text { head }_{\mathrm{h}}\right) W^{O} \\ \text { where head }_{\mathrm{i}} &=\text { Attention }\left(Q W_{i}^{Q}, K W_{i}^{K}, V W_{i}^{V}\right) \end{aligned}MultiHead(Q,K,V)where headi=Concat(head1,…,headh)WO=Attention(QWiQ,KWiK,VWiV)WiQ∈Rdmodel ×dk,WiK∈Rdmodel ×dk,WiV∈Rdmodel ×dv,WO∈Rhdv×dmodel W_{i}^{Q} \in \mathbb{R}^{d_{\text {model }} \times d_{k}}, W_{i}^{K} \in \mathbb{R}^{d_{\text {model }} \times d_{k}}, W_{i}^{V} \in \mathbb{R}^{d_{\text {model }} \times d_{v}},W^{O} \in \mathbb{R}^{h d_{v} \times d_{\text {model }}}WiQ∈Rdmodel×dk,WiK∈Rdmodel×dk,WiV∈Rdmodel×dv,WO∈Rhdv×dmodel在这项工作中,我们使用h=8个平行的注意力层或头。对于其中的每一个,我们使用dk=dv=dmodel/h=64d{k}=d{v}=d_{model}/h=64dk=dv=dmodel/h=64。由于降低了每个头的维数,所以总的计算量与全维的单头注意相似。
简单理解一下多头注意力机制,在介绍缩放点乘注意力机制的时候,介绍了Q、K、V,多头注意力机制中只是将Q、K、V拆分成多个,然后分别进行注意力的计算,最后将输出拼接到一起。简单来说,基于embedding得到对应的单词X后,使用不同的WqW_qWq、WkW_kWk、WvW_vWv可以得到不同的QiQ_iQi、KiK_iKi、ViV_iVi。对于每个单独的QiQ_iQi、KiK_iKi、ViV_iVi都可以得到一个输出,将所有输出进行拼接得到最后的结果。
3.2.3 注意力模型在我们模型中的应用(Applications of Attention in our Model)
Transformer以三种不同的方式使用多头注意力:
- 在“编码器-解码器注意力”的层中,查询来自先前的解码器层,键和值来自编码器的输出。这允许编码器中的每个位置关注输入序列中的所有位置。这模拟了序列到序列模型中的典型的编码器解码器机制;
- 编码器包含自注意力层,在自注意力层中,所有的键、值和查询来自相同的位置,这种情况下,编码器中包含上一层的输出。编码器的每个位置都可以参加编码器上一层的所有位置的编码;
- 类似的,解码器中的自注意力层允许解码器中的每个位置关注解码器中的所有位置,直到并包括该位置。模型需要防止解码器中的向左信息流保留自回归属性。通过屏蔽(设置为负无穷大)对应于非法连接的softmax输入中的所有值来实现缩放点乘注意力。
下面看一下Transformer中编码器自注意力层、编码器-解码器注意力层、解码器自注意力层中的Q、K、V的来源:
Quries | Keys | Values | |
---|---|---|---|
encoder-encoder | encoder-inputs | encoder-inputs | encoder-inputs |
encoder-decoder | decoder-inputs | encoder-inputs | encoder-inputs |
decoder-decoder | decoder-inputs | decoder-inputs | decoder-inputs |
3.3 基于位置的前馈神经网络(Position-wise Feed-Forward Networks)
除了注意力子层外,Transformer模型的编码器和解码器中的每个层都包含一个完全连接的前馈网络,它分别应用于每个位置。这由两个线性变换组成,其间具有ReLU激活:FFN(x)=max(0,xW1+b1)W2+b2\operatorname{FFN}(x)=\max \left(0, x W_{1}+b_{1}\right) W_{2}+b_{2}FFN(x)=max(0,xW1+b1)W2+b2虽然线性变换在不同位置上是相同的,但它们在不同的层之间使用不同的参数。另一种描述方式是将其描述为核大小为1的两个卷积。输入和输出的维数是dmodeld_{model}dmodel=512,并且隐藏层的维数为dfd_fdf=2048。
简单来说,前馈层有两层,这两层前馈层可以是线性结构,也可以是卷积结构,第一层前馈层的输入-输出维度为(512,2048),第二层前馈层的输入-输出维度为(2048.512),经过两层变换之后数据的输出维度仍然为512维。
公式中的W1W_1W1,W2W_2W2,b1b_1b1,b2b_2b2都是模型需要学习的参数。
3.4 嵌入和softmax(Embeddings and Softmax)
与其他序列转换模型类似,我们使用学习嵌入(embedding)将输入标记(tokens)和输出标记(tokens)转换为维度为dmodeld_{model}dmodel的向量。我们还使用常用的线性变换和Softmax函数将解码器输出转换为预测的下一令牌(token)概率。在我们的模型中,我们在两个嵌入层和Softmax前的线性变换之间共享相同的权重矩阵。在嵌入层中,我们将这些权重乘以√dmodel来放大每个权重。
3.5 位置编码
由于我们的模型不包含循环神经网络和卷积神经网络,因此为了使模型能够利用序列的顺序,我们必须加入一些有关令牌在序列中的相对或绝对位置的信息。 为此,我们在编码器和解码器底部的输入嵌入中添加“位置编码”。 位置编码的维数dmodeld_{model}dmodel与嵌入的维数相同,因此可以将两者相加。 位置编码有很多选择,有学习的和固定的。
在这项工作中,我们使用不同频率的正弦和余弦函数:PE(pos,2i)=sin(pos/100002i/dmodel )P E_{(p o s, 2 i)}=\sin \left(p o s / 10000^{2 i / d_{\text {model }}}\right)PE(pos,2i)=sin(pos/100002i/dmodel)PE(pos,2i+1)=cos(pos/100002i/dmodel )P E_{(p o s, 2 i+1)}=\cos \left(p o s / 10000^{2 i / d_{\text {model }}}\right)PE(pos,2i+1)=cos(pos/100002i/dmodel)其中pospospos是位置,iii是维度。也就是说,位置编码的每个维度对应于一个正弦。波长形成从2π2π2π到10000⋅2π10000·2π10000⋅2π的几何级数。我们选择这个函数是因为不同位置之间的embedding 可以简单的相互表示,因为对于任何固定的偏移量kkk,PEpos+kP E_{pos+k}PEpos+k可以表示为PEposPE_{pos}PEpos的线性函数。
我们还试验了使用学习得到的位置嵌入,发现两个版本产生的结果几乎相同。我们选择正弦版本是因为它可以允许模型外推到比训练期间遇到的序列长度更长的序列长度。
具体理解位置编码可以看一下这篇知乎的解答!
3.6 Mask机制
3.6.1 Sequence Mask
sequence mask的作用是防止decoder的时候看到“未来的信息”。在encoder的时候可以使用当前单词前后的信息,但是在Decoder的时候不能获取当前单词之后的信息,因此需要在进行注意力模型操作的时候需要将当前单词之后的注意力权重进行mask操作。
3.6.2 Padding Mask
attention的时候处理padding时为0的值,这里的padding是将不同长度的句子进行padding,统一整理为相同长度的句子,长的句子进行截取,短的句子进行padding,因此padding的部分需要进行裁剪。
4、为什么选择自注意力机制(Why Self-Attention)
假设输入序列长度为nnn,每个元素的维度为d:{x→1,⋯,x→n},x→i∈Rdd:\left\{\overrightarrow{\mathbf{x}}_{1}, \cdots, \overrightarrow{\mathbf{x}}_{n}\right\}, \overrightarrow{\mathbf{x}}_{i} \in \mathbb{R}^{d}d:{x
我们从三个方面比较 Transformer、CNN、RNN 三个特征提取器的性能。
一个是每层的总计算复杂度。另一个是可以并行化的计算量,以所需的最小顺序操作数来衡量。
第三个是网络中远程依赖之间的路径长度。在许多序列转换任务中,学习长距离依赖关系是一个关键挑战。影响学习这种依赖性的能力的一个关键因素是前向和后向信号必须在网络中穿越的路径的长度。输入和输出序列中任意位置组合之间的这些路径越短,就越容易了解长期依赖关系。因此,我们还比较了由不同层类型组成的网络中任意两个输入和输出位置之间的最大路径长度。
5、笔记
5.1 计算Attention权值的公式
Attention (Q,K,V)=softmax(QKTdk)V\text { Attention }(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) VAttention(Q,K,V)=softmax(dk
5.2 Encoder Self-Attention
图中,对e2e_2e2执行self-attention,需要计算e2e_2e2与e1e_1e1,e3e_3e3,e4e_4e4进行缩放点乘之后再softmax,然后将各自的权重与对应的隐藏输出相乘再求和得到e2e_2e2的隐藏状态。
5.3 Decoder Self-Atention
在Decoder部分需要对当前词后面的词进行mask,不能泄露其信息,因此在执行self-attention的时候只能使用其前面的信息。
5.4 self-attention和attention的区别
attention的query是来自Decoder解码部分,而key和calue是来自Encoder编码部分;而self-attention的query,key,value都是自身的信息,Encoder有自己的self-attention,Decoder有自己的self-attention。
5.5 self-attention和卷积神经网络的区别
self-attention是利用自身的信息进行加权,这和卷积神经网络的卷积类似。那么self-attention和卷积的区别是什么呢?
通过图片可以发现,卷积受限于卷积核的大小,只能学习到局部的依赖,self-attention能够直接学习到当前序列的所有信息,两者的视野是不同的,CNN卷积比较局限。
CNN有自己的优势,能够学习多通道的信息,通过设置多个卷积核实现多通道信息获取。CNN在提取图像信息的时候,不同的特征层提取的特征是不同的。self-attention能不能像CNN一样学习到不同通道的特征呢?self-attention基于这个想法提出了多头注意力multi-head attention。
CNN可以通过多个卷积核实现不同通道的信息获取,Transformer通过多个自注意力学习到不同的信息。
下面简单分析一下多头注意力公式的思想:
多头注意力允许模型共同关注来自不同位置的不同表示子空间的信息:MultiHead(Q,K,V)=Concat (head 1,…,head h)WOwhere head i=Attention (QWiQ,KWiK,VWiV)\begin{aligned} \operatorname{MultiHead}(Q, K, V) &=\text { Concat }\left(\text { head }_{1}, \ldots, \text { head }_{\mathrm{h}}\right) W^{O} \\ \text { where head }_{\mathrm{i}} &=\text { Attention }\left(Q W_{i}^{Q}, K W_{i}^{K}, V W_{i}^{V}\right) \end{aligned}MultiHead(Q,K,V)where headi=Concat(head1,…,headh)WO=Attention(QWiQ,KWiK,VWiV)WiQ∈Rdmodel ×dk,WiK∈Rdmodel ×dk,WiV∈Rdmodel ×dv,WO∈Rhdv×dmodel W_{i}^{Q} \in \mathbb{R}^{d_{\text {model }} \times d_{k}}, W_{i}^{K} \in \mathbb{R}^{d_{\text {model }} \times d_{k}}, W_{i}^{V} \in \mathbb{R}^{d_{\text {model }} \times d_{v}},W^{O} \in \mathbb{R}^{h d_{v} \times d_{\text {model }}}WiQ∈Rdmodel×dk,WiK∈Rdmodel×dk,WiV∈Rdmodel×dv,WO∈Rhdv×dmodel从多头自注意力的图可以看到,每一个头都有query、key、value,query、key、value在执行缩放点乘之前会先进行线性映射,不同头的线性映射是不同的,这些线性映射可以理解为CNN中不同的卷积核,CNN中的卷积核都有不同的参数,这里的多头注意力中每一头的W都是不同的,具有不同的参数,这样每一头就能学习到不同的信息。self-attention能够实现多头就是基于不同的W线性变换得到的。不同的参数能够让transformer向CNN一样学习到不同的特征。
multi-head attention得到多个输出会进行拼接,并经过一个线性映射得到多头attention的结果,这就是我们上面得到的多头注意力的计算公式。
例如多头注意力机制中某一头更关注I与其它信息的关系,某一头更关注kicked与其它信息的关系等等。
5.6 positional encoding位置编码
attention的计算公式是一个权重乘于一个向量并累加,可以发现,调整句子的顺序对最后得到的attention值是没有影响的,这说明attention的输出中是不包含任何顺序信息的。
事实上输入的顺序对很多任务是非常重要的,因此论文将位置编码添加到encoder和decoder底部的输入embedding来解决问题。
位置编码有两种选择:
- 可以作为参数来学习,即:将 encoder 的每个输入的位置embedding 、decoder 的每个输入的位置embedding 作为网络的参数,这些参数都从训练中学得。
- 也可以人工设定固定值。论文中使用:PE(pos,2i)=sin(pos/100002i/dmodel )P E_{(p o s, 2 i)}=\sin \left(p o s / 10000^{2 i / d_{\text {model }}}\right)PE(pos,2i)=sin(pos/100002i/dmodel)PE(pos,2i+1)=cos(pos/100002i/dmodel )P E_{(p o s, 2 i+1)}=\cos \left(p o s / 10000^{2 i / d_{\text {model }}}\right)PE(pos,2i+1)=cos(pos/100002i/dmodel)
5.7 为什么要残差连接
加上残差可以使得位置信息可以保留。
5.8 为什么选择自注意力机制
自注意力模型相比循环神经网络,卷积神经网络和限制范围的自注意力模型相比,其计算复杂度小,可以并行,最大的信息检索长度很小。
5.9 Mask机制
- Sequence Mask:为了防止decoder的时候看到“未来的信息”;
- Padding Mask:attention的时候处理输入数据的padding值为0的值;
5.10 Label Smoothing
在数据增强中,我们可以给样本特征加入随机噪声来避免过拟合。同样,我们也可以给样本的标签引入一定的噪声。假设训练数据集中有一些样本的标签是被错误标注的,那么最小化这些样本上的损失函数会导致过拟合,一种改善的正则化方法是标签平滑(label smoothing),即在输出标签中添加噪声来避免模型过拟合。
一个样本x的标签可以用one-hot向量表示,即:y=[0,...,0,1,0,...,0]Ty=[0,...,0,1,0,...,0]^Ty=[0,...,0,1,0,...,0]T这种标签可以看做硬目标,如果使用softmax分类器并使用交叉熵损失函数,最小化损失函数会使得正确类和其它类的权重差异变得很大。根据softmax函数的性质可知,如果要使得某一类的输出概率接近于1,其未归一化的得分需要远大于其它类的得分,可能会导致其权重越来越大,并导致过拟合。此外,如果样本标签是错误的,会导致更严重的过拟合现象。为了改善这种情况,我们可以引入一个噪声对标签进行平滑,即假设样本以α\alphaα的概率为其它类,平滑后的标签为:y^=[αK−1,...,αK−1,1−α,αK−1,...,αK−1]\hat{y}=[\frac{\alpha}{K-1},...,\frac{\alpha}{K-1},1-\alpha,\frac{\alpha}{K-1},...,\frac{\alpha}{K-1}]y^=[K−1α,...,K−1α,1−α,K−1α,...,K−1α]其中K为标签数量,这种标签可以看做是软目标,标签平滑可以避免模型的输出过拟合到硬目标上,并且通常不会损害其分类能力;
上面的标签平滑方法是给其它K-1个标签相同的概率αK−1\frac{\alpha}{K-1}K−1α,没有考虑标签之间的相关性,一种更好的做法是按照类别相关性来赋予其它标签不同的概率。比如先训练另外一个更复杂(一般为多个网络的集成)的教师网络。并使用大网络的输出作为软目标来训练学生网络,这种方法也称为知识蒸馏。
6、历史意义
- Transformer提出了self-attention,拉开了非序列化模型的序幕;
- 为预训练模型的到来打下了坚实的基础(BERT采用的是transformer的encoder部分,GPT采用的是transformer的decoder部分);
《Attention Is All You Need》相关推荐
- 《Attention is All You Need》浅读(简介+代码)
2017年中,有两篇类似同时也是笔者非常欣赏的论文,分别是FaceBook的<Convolutional Sequence to Sequence Learning>和Google的< ...
- 论文《Attention Is All You Need》及Transformer模型
目录 1. Introduction 2. 模型结构 2.1 Transformer模型 2.2 输入层 2.3 位置向量:给单词赋予上下文语境 2. ...
- 庖丁解牛式读《Attention is all your need》
我的观点废话 弄清楚Transformer模型内部的每一个细节尤为重要 attention机制首次被应用在nlp领域是在 2015年的一篇论文中:<Neural Machinie Transla ...
- 《Attention Is All You Need》注意力机制公式中Q,K,V的理解
一.概述 <Attention Is All You Need>是一篇关于注意力机制里程碑的文章,从2017年发表至今2020年7月已经获得了上万的引用.该文的两大亮点一是提出了一个几乎仅 ...
- 《Attention is all you need》源码解析+算法详解
Attention is all you need 源码解析 最近学习Transformer模型的时候,并且好好读了一下Google的<Attention is all you need> ...
- 【论文阅读笔记】《Attention is All You Need》——Attention机制和Transformer
Self-Attention 原理 计算两个向量之间的相关性α 输入的向量分别乘矩阵Wq和Wk得到q(query)和k(key)输入的向量分别乘矩阵W^q和W^k得到q(query)和k(key) 输 ...
- Transformer:《Attention is all you need》(论文精读/原理解析/模型架构解读/源码解析/相关知识点解析/相关资源提供)
本文解读Transformer较为详细,是一篇两万字的长文,如果想看简短版的,请参考这篇文章 目录 1 相关背景 1.1 Transformer 1.2<Attention is all you ...
- 经典重温:《Attention Is All You Need》详解
关注公众号,发现CV技术之美 本文位52CV粉丝投稿. 原博客地址:https://blog.csdn.net/michaelshare/article/details/124178685 该篇文章由 ...
- 《The Annotated Transformer》翻译——注释和代码实现《Attention Is All You Need》
文章目录 预备工作 背景 模型架构 Encoder and Decoder 堆栈 Encoder Decoder Attention 模型中Attention的应用 基于位置的前馈网络 Embeddi ...
- 《Attention Is All You Need》算法详解
该篇文章右谷歌大脑团队在17年提出,目的是解决对于NLP中使用RNN不能并行计算(详情参考<[译]理解LSTM(通俗易懂版)>),从而导致算法效率低的问题.该篇文章中的模型就是近几年大家到 ...
最新文章
- php路由器怎么登录认证,PHP用户身份验证,如路由器登录
- 真相!没项目经验高薪就无望?
- 利用ajax技术 实现用户注册。
- java的开源项目哪里找,我想参加开源项目的开发,请问在网上去哪找这样的项目? 纯C语言的(非C++或JAVA)...
- 利用Struts拦截器限制上传图片的格式和大小
- .NET开发框架(二)-框架功能简述
- Android自定义控件入门实践之雷达扫描控件
- linkerd mysql_Linkerd和k8s无法正常工作
- webgis从基础到开发实践_webgis@基础GIS 开源资源汇总
- php如何写代码禁用广告,不再显示广告案例(php操作cookie)
- 如何在前端中使用protobuf(vue篇)
- 为什么世界是由数学构成的
- python背单词游戏,python背单词小程序
- BZOJ 5109 [CodePlus 2017]大吉大利,晚上吃鸡!
- 计算机控制实验总结电机调速,控制步进电机调速系统实验报告
- 如何在C ++ 中分割PDF档案?试试Aspose
- 前端将后端返回的文件流转为excel并下载
- Verilog 代码编写 DDS信号发生器(幅频相可调正弦波、方波、三角波、锯齿波)纯VIVADO编写仿真
- 计算机方面经典书籍一
- 计算机课玩手机检讨500,上学带手机检讨书500字范文(精选6篇)
热门文章
- centOS 6.0无法运行dump指令的解决方法
- [转载] 羽毛球——学打羽毛球 08 接发球 发球
- Ubuntu 中的编程语言(中)
- 面试精讲之面试考点及大厂真题 - 分布式专栏 20 降级组件Hystrix的功能特性
- 如何在CentOS 7上安装和配置MySQL Cluster
- mysql索引的增删_mysql索引的增删改查怎么实现?
- Android BGradualProgress 多种渐变、直角or弧角、进度条、加载条
- vue项目创建步骤 和 路由router知识点
- 自动/持续部署Docker 的tomcat web项目(一)
- android如何兴起_情感设计的必要兴起