因本文内容较长,故分为上下两部分
前言
Transformer是一种神经网络结构,由Vaswani等人在2017年的论文“Attention Is All You Need”中提出,用于处理机器翻译、语言建模和文本生成等自然语言处理任务。
Transformer与传统NLP特征提取类模型的区别主要在以下两点:
- Transformer是一个纯基于注意力机制的结构,并将自注意力机制和多头注意力机制的概念运用到模型中;
- 由于缺少RNN模型的时序性,Transformer引入了位置编码,在数据上而非模型中添加位置信息;
以上的处理带来了几个优点:
- 更容易并行化,训练更加高效;
- 在处理长序列的任务中表现优秀,可以快速捕捉长距离中的关联信息。
注意力机制
如同阅读时,视线只会集中在正在阅读的部分;自然语言处理中,根据任务内容的不同,句子中需要更加关注的部分也会不同。
注意力机制便是在判断词在句子中的重要性,我们通过注意力分数来表达某个词在句子中的重要性,分数越高,说明该词对完成该任务的重要性越大。
计算注意力分数时,我们主要参考三个因素:query、key和value。
query
:任务内容key
:索引/标签(帮助定位到答案)value
:答案
在上面的例子中,如“情感分类”、“电影名字”、“中译英”等为query
,每次对于任务内容的回答即为value
。至于什么是key
, 用一个比较直观的举例来说,每次登录视频网站搜索视频时,搜索的内容为query
,搜索结果中显示的视频名称为key
,它与任务内容相关,并可以引导我们至具体的视频内容(value
)。
一般在文本翻译中,我们希望翻译后的句子的意思和原始句子相似,所以进行注意力分数计算时,query
一般和目标序列,即翻译后的句子有关,key
则与源序列,即翻译前的原始句子有关。
计算注意力分数,即为计算query
与key
的相似度。常用的计算注意力分数的方式有两种:additive attention
和scaled dot-product attention
,在这里我们主要介绍第二种方法。
在几何角度,点积(dot product)表示一个向量在另一个向量方向上的投影。换句话说,从几何角度上解读,点积代表了某个向量中的多少是和另一个向量相似的。
图片来源: Understanding the Dot Product from BetterExplained
将这个概念运用到当前的情境中,我们想要求query
和key
之间有多少是相似的,则需要计算query
和key
的点积。
同时,为了避免query
(
Q
∈
R
n
×
d
m
o
d
e
l
Q \in R^{n\times d_{model}}
Q∈Rn×dmodel)和key
(
K
∈
R
m
×
d
m
o
d
e
l
K \in R^{m\times d_{model}}
K∈Rm×dmodel)本身的“大小”影响到相似度的计算,我们需要在点乘后除以
d
m
o
d
e
l
\sqrt{d_{model}}
dmodel。
Attention Score ( Q , K ) = Q K T d m o d e l \text{Attention Score}(Q, K)=\frac{QK^T}{\sqrt{d_{model}}} Attention Score(Q,K)=dmodelQKT
我们将该相似度的区间限制与0到1之间,并令其作用在value
上。
Attention ( Q , K , V ) = softmax ( Q K T d m o d e l ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_{model}}}\right)V Attention(Q,K,V)=softmax(dmodelQKT)V
在如下代码中,我们实现了scaled dot-product attention的计算, 调用类后,返回的是加权后的value(output)以及注意力权重(attn)。
在处理数据时,我们为了统一长度,会使用 <pad> 占位符补齐了一些稍短的文本。
“Hello world!” --> <bos> hello world ! <eos> <pad> <pad>
这些 <pad> 占位符没有任何意义,不应该参与注意力分数计算中。为此我们在注意力中加入了 padding 掩码,即识别输入序列中的 <pad> 占位符,保证计算时这些位置对应的注意力分数为0。
自注意力机制(Self-Attention)
自注意力机制中,我们关注句子本身,查看每个单词对于周边单词的重要性。这样可以很好地理清句子中的逻辑关系,如代词指代。
举个例子,在’The animal
didn’t cross the street because it
was too tired’这句话中,‘it’指代句中的’The animal’,所以自注意力会赋予’The’、'animal’更高的注意力分值。
图片来源: The Illustrated Transformer by Jay Alammer
自注意力分数的计算还是遵循着上述的公式,只不过这里的query
, key
和value
都变成了句子本身点乘各自权重。
给定序列 X ∈ R n × d m o d e l X \in \mathbb{R}^{n \times d_{model}} X∈Rn×dmodel,序列长度为 n n n,维度为 d m o d e l d_{model} dmodel。在计算自注意力时, Q = W Q X , K = W K X , V = W V X Q = W^QX, K = W^KX, V = W^VX Q=WQX,K=WKX,V=WVX。
Attention ( Q , K , V ) = softmax ( Q K T d m o d e l ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_{model}}}\right)V Attention(Q,K,V)=softmax(dmodelQKT)V
其中,序列中位置为 i i i的词与位置为 j j j的词之间的自注意力分数为:
Attention ( Q , K , V ) i , j = exp ( Q i K j T d m o d e l ) ∑ k = 1 n exp ( Q i K k T d m o d e l ) V j \text{Attention}(Q, K, V)_{i,j} = \frac{\text{exp}\left(\frac{Q_iK_j^T}{\sqrt{d_{model}}}\right)}{\sum_{k=1}^{n}\text{exp}\left(\frac{Q_iK_k^T}{\sqrt{d_{model}}}\right)}V_j Attention(Q,K,V)i,j=∑k=1nexp(dmodelQiKkT)exp(dmodelQiKjT)Vj
多头注意力(Multi-Head Attention)
图片来源:Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, and Illia Polosukhin. Attention is all you need, 2017.
多头注意力是注意力机制的扩展,它可以使模型通过不同的方式关注输入序列的不同部分,从而提升模型的训练效果。
不同于之前一次计算整体输入的注意力分数,多头注意力是多次计算,每次计算输入序列中某一部分的注意力分数,最后再将结果进行整合。
多头注意力通过对输入的embedding乘以不同的权重参数 W Q W^{Q} WQ、 W K W^{K} WK和 W V W^{V} WV,将其映射到多个小维度空间中,我们称之为“头”(head),每个头部会并行计算自己的自注意力分数。
head i = Attention ( Q W i Q , K W i K , V W i V ) = softmax ( Q i K i T d k ) V i \text{head}_i = \text{Attention}(QW^Q_i, KW^K_i, VW^V_i) = \text{softmax}\left(\frac{Q_iK_i^T}{\sqrt{d_{k}}}\right)V_i headi=Attention(QWiQ,KWiK,VWiV)=softmax(dkQiKiT)Vi
W i Q ∈ R d m o d e l × d k W^Q_i \in \mathbb{R}^{d_{model}\times d_{k}} WiQ∈Rdmodel×dk、 W i K ∈ R d m o d e l × d k W^K_i \in \mathbb{R}^{d_{model}\times d_{k}} WiK∈Rdmodel×dk和 W i V ∈ R d m o d e l × d v W^V_i \in \mathbb{R}^{d_{model}\times d_{v}} WiV∈Rdmodel×dv为可学习的权重参数。一般为了平衡计算成本,我们会取 d k = d v = d m o d e l / n h e a d d_k = d_v = d_{model} / n_{head} dk=dv=dmodel/nhead。
在获得多组自注意力分数后,我们将结果拼接到一起,得到多头注意力的最终输出。 W O W^O WO为可学习的权重参数,用于将拼接后的多头注意力输出映射回原来的维度。
MultiHead ( Q , K , V ) = Concat ( head 1 , . . . , head h ) W O \text{MultiHead}(Q, K, V)=\text{Concat}(\text{head}_1, ..., \text{head}_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
简单来说,在多头注意力中,每个头部可以’解读’输入内容的不同方面,比如:捕捉全局依赖关系、关注特定语境下的词元、识别词和词之间的语法关系等。
Transformer 结构
Transformer同样是encoder-decoder的结构,只不过这里的“encoder”和“decoder”是由无数个同样结构的encoder层和decoder层堆叠组成。
在进行机器翻译时,encoder解读源语句(被翻译的句子)的信息,并传输给decoder。decoder接收源语句信息后,结合当前输入(目前翻译的情况),预测下一个单词,直到生成完整的句子。
Transformer 结构
Transformer的具体结构如下图所示,在进入encoder或decoder前,源序列和目标序列需要经过一些“加工”。
- word embedding: 将序列转换为模型所能理解的词向量表示,其中包含了序列的内容信息。
- positional encoding:在内容信息的基础上添加位置信息。
位置编码(Positional Encoding)
Transformer模型不包含RNN,所以无法在模型中记录时序信息,这样会导致模型无法识别由顺序改变而产生的句子含义的改变,如“我爱我的小猫”和“我的小猫爱我”。
为了弥补这个缺陷,我们选择在输入数据中额外添加表示位置信息的位置编码。
位置编码 P E PE PE的形状与经过word embedding后的输出 X X X相同,对于索引为[pos, 2i]的元素,以及索引为[pos, 2i+1]的元素,位置编码的计算如下:
P E ( p o s , 2 i ) = sin ( p o s 1000 0 2 i / d model ) PE_{(pos,2i)} = \sin\Bigg(\frac{pos}{10000^{2i/d_{\text{model}}}}\Bigg) PE(pos,2i)=sin(100002i/dmodelpos)
P E ( p o s , 2 i + 1 ) = cos ( p o s 1000 0 2 i / d model ) PE_{(pos,2i+1)} = \cos\Bigg(\frac{pos}{10000^{2i/d_{\text{model}}}}\Bigg) PE(pos,2i+1)=cos(100002i/dmodelpos)
在下面的代码中,我们实现了位置编码,输入经过word embedding后的结果 X X X,输出添加位置信息后的结果 X + P E X + PE X+PE。