2.2 Transformer模型结构
2017年6月,Transformer模型横空出世,当时谷歌在发表的一篇论文Attention Is All You Need中参考了注意力机制,提出了自注意力(Self-Attention)机制及新的神经网络结构——Transformer。该模型具有以下优点:
·传统的Seq2Seq模型以RNN为主,制约了GPU的训练速度,Transformer模型是一个完全不用RNN和CNN的可并行机制计算注意力的模型。
·Transformer改进了RNN最被人诟病的训练慢的缺点,利用自注意力机制实现快速并行计算,并且Transformer可以增加到非常深的深度,充分发掘模型的特性,提升模型的准确率。
下面我们深入解析Transformer模型架构。
1.Transformer模型架构
Transformer模型本质上也是一个Seq2Seq模型,由编码器、解码器和它们之间的连接层组成,如图2-2所示。在原始论文Attention Is All You Need中介绍的The Transformer编码器Encoder由N=6个完全相同的编码层(Encoder Layer)堆叠而成,每一层都有两个子层。第一个子层是一个多头注意力(Multi-Head Attention)层,第二个子层是一个简单的、位置完全连接的前馈神经网络(Feed-Forward Network,FFN)。我们对每个子层再采用一个残差连接(Residual Connection),接着进行层归一化(Layer Normalization)。每个子层的输出是LayerNorm(x+Sublayer(x)),其中Sublayer(x)是由子层本身实现的函数。
The Transformer解码器:解码器Decoder同样由N=6个完全相同的解码层(Decoder Layer)堆叠而成。除与每个编码器层中的两个子层相同外,解码器还插入了第三个子层——Encoder-Decoder Attention层,该层对编码器的输出执行多头注意力操作。与编码器类似,我们在每个子层再采用残差连接,然后进行层归一化。
Transformer模型计算注意力的方式有三种:
·编码器自注意力,每一个Encoder都有多头注意力层。
·解码器自注意力,每一个Decoder都有掩码多头注意力层。
·编码器-解码器注意力,每一个Decoder都有一个Encoder-Decoder Attention,过程和Seq2Seq+Attention的模型相似。
图2-2 Transformer网络结构
2.自注意力机制
Transformer模型的核心思想就是自注意力(Self-Attention)机制,能注意输入序列的不同位置以计算该序列的表示的能力。自注意力机制顾名思义指的不是源语句和目标语句之间的注意力机制,而是同一个语句内部元素之间发生的注意力机制。而在计算一般Seq2Seq模型中的注意力时,以Decoder的输出作为查询向量q,Encoder的输出序列作为键向量k、值向量v,注意力机制发生在目标语句的元素和源语句中的所有元素之间。
自注意力机制的计算过程是将Encoder或Decoder的输入序列的每个位置的向量通过3个线性转换分别变成3个向量:查询向量q、键向量k和值向量v,并将每个位置的q拿去跟序列中其他位置的k进行匹配,计算出匹配程度后,利用Softmax层取得介于0~1的权重值,并以此权重跟每个位置的v作加权平均,最后取得该位置的输出向量z。下面介绍自注意力的计算方法。
(1)可缩放的点积注意力。可缩放的点积注意力即如何使用向量来计算自注意力,通过4个步骤来计算自注意力,如图2-3所示。
图2-3 可缩放的点积注意力
从每个编码器的输入向量(每个单词的词向量)中生成三个向量:查询向量q、键向量k和值向量v,矩阵运算中这三个向量是通过编解码器输入X与三个权重矩阵Wq、Wk、Wv相乘创建的。
计算得分:如图2-3所示的例子输入一个句子Thinking Machines,第一个词Thinking计算自注意力向量,需将输入句子中的每个单词对Thinking打分。分数决定了在编码单词Thinking的过程中有多重视句子的其他部分。分数是通过打分单词(所有输入句子的单词)的键向量k与Thinking的查询向量q的点积来计算的。比如,第一个分数是q1和k1的点积,第二个分数是q1和k2的点积。
缩放求和:将分数乘以缩放因子(dk)(dk是键向量的维数,dk=64),让梯度更稳定,然后通过Softmax传递结果。Softmax的作用是使所有单词的分数归一化,得到的分数都是正值且和为1。Softmax分数决定了每个单词对编码当下位置(Thinking)的贡献。
将每个值向量v乘以Softmax分数,希望关注语义上相关的单词,并弱化不相关的单词。对加权值向量求和,即可得到自注意力层在该位置的输出zi。
因此,可缩放的点积注意力可通过下面的公式计算:
在实际应用中,注意力计算是以矩阵形式完成的,以便计算得更快。我们接下来看看如何通过矩阵运算实现自注意力机制,如图2-4所示。
图2-4 自注意力机制的实现
首先求取查询向量矩阵Q、键向量矩阵K和值向量矩阵V,通过权重矩阵Wq、Wk、Wv与输入矩阵X相乘得到;同样求取任意一个单词的得分是通过它的键向量k与所有单词的查询向量q的点积来计算的,我们可以把所有单词的键向量k的转置组成一个键向量矩阵KT,把所有单词的查询向量q组合在一起成为查询向量矩阵Q,这两个矩阵相乘得到注意力得分矩阵A=QKT;然后,对注意力得分矩阵A求Softmax得到归一化的得分矩阵,这个矩阵再左乘,以值向量矩阵V得到输出矩阵Z。
(2)多头注意力机制。如果只计算一个注意力,很难捕捉输入句中所有空间的信息,为了优化模型的效果,原论文中提出了一个新颖的做法——多头注意力机制,如图2-5所示。
图2-5 多头自注意力机制的实现
多头注意力是不能只用嵌入向量维度dmodel的K、Q、V进行单一注意力操作的,而是把K、Q、V线性投射到不同空间h次,分别变成维度dq、dk和dv,再各自进行注意力操作,其中,dq=dk=dv=dmodel/h=64就是投射到h个头上。多头注意力允许模型的不同表示子空间联合关注不同位置的信息,如果只有一个注意力头,则它的平均值会削弱这个信息。
多头注意力为每个头保持独立的查询/键/值权重矩阵、、,从而产生不同的查询/键/值矩阵(Qi、Ki、Vi)。用X乘以、、矩阵来产生查询/键/值矩阵Qi、Ki、Vi,与上述相同的自注意力计算,只需8次不同的权重矩阵运算即可得到8个不同的Zi矩阵,每一组都代表将输入文字的隐向量投射到不同空间。最后把这8个矩阵拼在一起,通过乘上一个权重矩阵WO,还原成一个输出矩阵Z。
多头注意力的每个头到底关注句子中什么信息呢?不同注意力的头集中在哪里?以下面这两句话为例,The animal didn’t cross the street because it was too tired和The animal didn't cross the street because it was too wide,这两个句子中的it指的是什么呢?it指的是street还是animal?当我们编码it一词时,it的注意力集中在animal和street上,从某种意义上说,模型对it一词的表达在某种程度上是animal和street的代表,但是在不同语义下,第一句的it更强烈地指向animal,第二句的it更强烈地指向street。
3.Transformer模型其他结构
1)残差连接与归一化
编解码器有一种特别的结构:多头注意力的输出和前馈层(Feed-Forward Layer)之间有一个子层:残差连接(Residual Connection)和层归一化(Layer Normalization,LN)。残差连接是构建一种新的残差结构,将输出改写为和输入的残差,使得模型在训练时微小的变化可以被注意到,该方法在计算机视觉中经常使用。
在把数据送入激活函数之前需要进行归一化,因为我们不希望输入数据落在激活函数的饱和区。层归一化是深度学习中的一种正规化方法,一般和批量归一化(Batch Normalization,BN)进行比较。批量归一化的主要思想是在每一层的每一批数据上进行归一化,层归一化是在每一个样本上计算均值和方差,层归一化的优点在于独立计算并针对单一样本进行正规化,而不是批量归一化那种在批方向计算均值和方差。
2)前馈神经网络
编解码层中的注意力子层输出都会接到一个全连接网络——前馈神经网络,包含两个线性转换和一个ReLU激活函数,根据各个位置(输入句中的每个文字)分别进行FFN操作,因此称为Pointwise的FFN。计算公式如下:
FFN=max(0,xW1+b1)W2+b2
3)线性变换和Softmax层
解码器最后会输出一个实数向量。如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是Softmax层。线性变换层是一个简单的全连接神经网络,它可以把解码器产生的向量投射到一个比它大得多的、被称作对数概率(Logits)的向量中。
不妨假设我们的模型从训练集中学习10 000个不同的英语单词(我们模型的“输出词表”),因此对数概率向量为10 000个单元格长度的向量——每个单元格对应某一个单词的分数。接下来的Softmax层便会把那些分数变成概率(都为正数,上限为1.0),概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出。
4)位置编码
Seq2Seq模型的输入仅仅是词向量,但是Transformer模型摒弃了循环和卷积,无法提取序列顺序的信息,如果缺失了序列顺序信息,可能会导致所有词语都对了,但是无法组成有意义的语句。作者是怎么解决这个问题的呢?为了让模型利用序列的顺序,必须注入序列中关于词语相对或者绝对位置的信息,在论文中作者引入了位置编码(Positional Encoding),对序列中的词语出现的位置进行编码,图2-6是20个词在词嵌入维度512的位置编码可视化,其中纵坐标是词,横坐标是词嵌入维度。
图2-6 位置编码可视化
在编码器和解码器堆栈的底部,将句子中每个词的位置编码添加到输入嵌入中,位置编码和词嵌入的维度dmodel相同,所以它俩可以相加。使用不同频率的正弦和余弦函数获取位置信息:
其中pos是位置,i是维度,在偶数位置使用正弦编码,在奇数位置使用余弦编码。位置编码的每个维度对应一个正弦曲线。