Bootstrap

基于MindSpore实现Transformer机器翻译(上)

因本文内容较长,故分为上下两部分

前言

Transformer是一种神经网络结构,由Vaswani等人在2017年的论文“Attention Is All You Need”中提出,用于处理机器翻译、语言建模和文本生成等自然语言处理任务。

Transformer与传统NLP特征提取类模型的区别主要在以下两点:

  • Transformer是一个纯基于注意力机制的结构,并将自注意力机制和多头注意力机制的概念运用到模型中;
  • 由于缺少RNN模型的时序性,Transformer引入了位置编码,在数据上而非模型中添加位置信息;

以上的处理带来了几个优点:

  • 更容易并行化,训练更加高效;
  • 在处理长序列的任务中表现优秀,可以快速捕捉长距离中的关联信息。

注意力机制

如同阅读时,视线只会集中在正在阅读的部分;自然语言处理中,根据任务内容的不同,句子中需要更加关注的部分也会不同。

attention-in-tasks

注意力机制便是在判断词在句子中的重要性,我们通过注意力分数来表达某个词在句子中的重要性,分数越高,说明该词对完成该任务的重要性越大。

计算注意力分数时,我们主要参考三个因素:querykeyvalue

  • query:任务内容
  • key:索引/标签(帮助定位到答案)
  • value:答案

在上面的例子中,如“情感分类”、“电影名字”、“中译英”等为query,每次对于任务内容的回答即为value。至于什么是key, 用一个比较直观的举例来说,每次登录视频网站搜索视频时,搜索的内容为query,搜索结果中显示的视频名称为key,它与任务内容相关,并可以引导我们至具体的视频内容(value)。

query-key-value

一般在文本翻译中,我们希望翻译后的句子的意思和原始句子相似,所以进行注意力分数计算时,query一般和目标序列,即翻译后的句子有关,key则与源序列,即翻译前的原始句子有关。
计算注意力分数,即为计算querykey的相似度。常用的计算注意力分数的方式有两种:additive attentionscaled dot-product attention,在这里我们主要介绍第二种方法。

在几何角度,点积(dot product)表示一个向量在另一个向量方向上的投影。换句话说,从几何角度上解读,点积代表了某个向量中的多少是和另一个向量相似的。

图片来源: Understanding the Dot Product from BetterExplained

将这个概念运用到当前的情境中,我们想要求querykey之间有多少是相似的,则需要计算querykey的点积。
同时,为了避免query Q ∈ R n × d m o d e l Q \in R^{n\times d_{model}} QRn×dmodel)和key( K ∈ R m × d m o d e l K \in R^{m\times d_{model}} KRm×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)=dmodel QKT

我们将该相似度的区间限制与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(dmodel QKT)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, keyvalue都变成了句子本身点乘各自权重。

给定序列 X ∈ R n × d m o d e l X \in \mathbb{R}^{n \times d_{model}} XRn×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(dmodel QKT)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(dmodel QiKkT)exp(dmodel QiKjT)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(dk QiKiT)Vi

W i Q ∈ R d m o d e l × d k W^Q_i \in \mathbb{R}^{d_{model}\times d_{k}} WiQRdmodel×dk W i K ∈ R d m o d e l × d k W^K_i \in \mathbb{R}^{d_{model}\times d_{k}} WiKRdmodel×dk W i V ∈ R d m o d e l × d v W^V_i \in \mathbb{R}^{d_{model}\times d_{v}} WiVRdmodel×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前,源序列和目标序列需要经过一些“加工”。

  1. word embedding: 将序列转换为模型所能理解的词向量表示,其中包含了序列的内容信息
  2. 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

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;