本文是一篇非常好的transformer的翻译,此处为 原文链接

preface

我们知道,attention目前已经深度学习中一种普通的方法。在这篇文章中,我们将介绍Transformer,一种在使用attention时能够加速训练的模型,不仅如此,在一些任务上,它的效果还要比 Google Neural Machine Translation model出色,下面我们拆分详细分析下这个模型。

The Transformer是2017年由Google的一篇问题Attention is all you need 提出, 其中此处是tensorflow的实现,其作为Tensor2Tensor的一个子模块,pytorch的一个由Harvard’s NLP groups的实现这里

A High-level Look

当我们做机器翻译的时候,即如下图,存在若干encoders 和decoders

其中encoders和decoders均由几个相同的encoder或decoder层堆叠组成,这些encoder的结构完全相同,只是其参数不同。

每个encoder可分解为两层,其输入分别经过self-attention—该层能够获取输入的各词两两之间的相关信息,具体后面分析,然后经过一个普通的前馈神经网络,每个输入位置对应的网络是独立互不干扰的。

每个decoder同样具有与encoder相同的两层,但其在两层直接又夹了一attention 层,能够帮助decoder集中于输入句子的相关部分(其作用于seq2seq model中的attention相似)

Bring the Tensors into the Picture

从上面我们大致看出翻译的基本机构,下面我们具体从更细的张量角度来看整个流程是怎么运作的。最开始,我们通过embedding algorithm将输入的词转化为向量,即:

在这里插入图片描述

Encoding

对于最底层的encoder, 其输入的是一个句子中所有词向量的list, 如果我们的训练集句子长度不一,我们以句子的最大长度作为list 的容量,其他较短的句子中进行padding(填充)以达到相同的长度,这样对于每个句子,其输入的维度都将保持一致。对于list中每个词的向量,其维度我们事先进行训练设置的参数保持一致。
对于其他层的encoder,其输入为上一层encoder的输出,每层的输入输出的张量维度信息都保持一致。

Self-Attention at a High Level

当我们想将下面的句子翻译时:

”The animal didn't cross the street because it was too tired”

单词‘it’指的是什么?是街道还是动物?对于人类很简单,对于算法并不容易理解;
这里模型处理方式是,对于一个输入句子的每个词,self-attention允许它“看”该句子的所有的其他词,通过这种方式,能够“理解”该句子中其他相关的词。具体可视化关联性,可参考Tensor2Tensor notebook

Self-Attention in Detail

下面我们具体看一下一个词怎么和其他词进行联系,具体的过程是什么样的。

  • 第一步:首先创建三个矩阵 W Q , W K , W V W^Q, W^K,W^V WQWKWV,其维度为512*64(512为词向量维度,64为attention维度),然后对每一次词,将创建的矩阵与词向量相乘得到对应的Query Vector, Key Vector和Value Vector。

  • 第二步:对于每个词,计算一个分数。比如这个例子中,对于第一个词“Thinking”,我们需要分别计算句子中每个词(包括它自己)与该词的关联性分值,如图所示:

  • 第三步:将上述得到的分值再除以一个共同的值 d k \sqrt{d_k} dk ,这里为8,其目的在于有更稳定的梯度,也其他为其他数值。

  • 第四步:计算上述值的softmax值,当然,在原位的分值最高,但有时候也能找到其他更相关的词。

  • 第五步:将softmax的值与values值求积

  • 第六步:将上述得到的值相加,为这个新生成一个向量。

我们然后将为该词新生成的向量传给下一层进行计算。

上述过程可以用矩阵成绩来完成:
如第一步,直接使用一个句子所有词相乘,其中矩阵X中每一行代码输入句子的一个词:

剩下步骤:如图所示,直接得到句子中每个词新向量的表达:

The Beast With Many Heads

论文中进一步优化self-attention, 通过多头(“multi-headed”)机制,它通过两种方式提升attention layer的表现。

  1. 它扩展了模型聚焦不同位置的能力,在上面的例子中,Z包含了每一个其他位置的信息,但是它也可能被它自己主导;但我们想知道“The animal didn’t cross the street because it was too tired””中“it”代表的含义时,多头能提供更多的信息,更可能聚集到正确的位置。
  2. 它给attention layer多个表示"子空间",这种机制使得我们有多套Query/Key/Value 权重矩阵,在使用时每一套被随机初始化,训练后,每一套都能用户将输入向量转化为 一个不同的表示子空间。

如果像上述提到的计算方式,当我们使用 8个heads时,将会得到8个不同的Z矩阵。

此时有些问题,就是下一层的输入要求的是一个矩阵,而我们现在有8个,因此我们需要将其压缩为一个。怎样做呢,如下图所示:

  1. 首先将所得到的z矩阵拼接在一起
  2. 将拼接好的矩阵乘以一个权重矩阵 W 0 W^0 W0
  3. 将结果作为encoder层的最终输出层进入下一层。

小结

在整个过程中有很多矩阵,让我们在一起看整个流程

经过“multi-head”学习后,让我们重新修正上述中的例子,看句子中“it”表示的含义

看一看出其中一个head聚集在“tired”上,一个聚集在“the animal”上。某种意义上,在这个模型中,“it”含有同时含有“animal”和“tired”的表示。 然而,当我们把所有的head加上后,结果有点难以解释:

Representing The Order of The Sequence Using Positional Encoding

在上述模型中,还有词的顺序信息没有被利用,被模型丢弃,为了解决上述方法,the transform对于每个词增加 了一个位置向量,这个向量能够通过学习表征到一些特定的模式,帮助决定每个词的位置,或者不同词之间的距离。

如果向量的维度是4,那个真实的位置向量看起来是这样的:

那么特定的模式是什么样子呢:
在下面图中,每一行代表一个位置编码,其中共有20个词,每个词的词向量维度为512。为什么看起来是中间分裂的,是因为左半部是由于sine函数产生,右半部分由cose函数产生,他们然后拼接形成每个词的位置编码。

位置编码的具体公式见原论文,虽然它并不是仅有的位置编码方式,但也能够对未知长度的序列进行编码,比如当我们进行翻译比我们训练集更长的句子时。

residuals

值得注意的是,在每一个encoder层,都有一个残差连接,然后接一个lay-normalization层:

具体来看,即是

该残差结构同样对decoder有效,当我们考虑到两层的encoders和decoders时,结果如下:

The Decoder Side

通过对encoder部分的分析,我们已了解大部分概念,下面详细了解decoder层是如何工作的。首先值得encoder层初始的输入为句子中词的向量;顶层的encoder输出为一套attention 向量 K和V;它能够被每一个decoder的encoder-decoder attention 层来使用,以帮助decoder集中在输入句子中合适的位置,如图所示:

decoder部分中每一步的输出用于底层decoder层的输入,正如encoder所做的,decoder中我们也将位置向量作为输入来表示每个词的位置,如图所示

在解码器中的self attention 层与编码器中的稍有不同,在解码器中,self-attention 层仅仅允许关注早于当前输出的位置。在softmax之前,通过遮挡未来位置(将它们设置为-inf)来实现。

"Encoder-Decoder Attention "层工作方式跟multi-headed self-attention是一样的,除了它从前层获取输出转成query矩阵,接收最后encoder层的key和value矩阵做key和value矩阵作为相应矩阵。

Final Linear and softmax layer

最后decoder层输入一个浮点型的向量,怎么把它转成一个词呢,这就是最后线性层和softmax层的作用。
线性层是一个简单的全连接层,通过将decorders的输出投射到一个更加大的向量,称为“logits vector”,其大小和词汇保持一致,然后通过softmax输出一个概率分值,并选择概率最高的作为下一个词。

The Loss Function

当我们进行训练的时候,需要表征预测的词和真实词的差异,怎么比较这两概率分布呢,我们简单地将两个分布相减。也可参考交叉熵KL散度的计算。

上述仅考虑一个词,当我们对一个句子进行训练时,比如
输入:“je suis étudiant”
输出: “i am a student”

此时我们的目标输出为:

在一个大的训练集上训练足够多的次数后,我们希望模型输出的结果:

现在,因为模型每步只产生一组输出,假设模型选择最高概率的,去除其他的部分,这种产生的预测结果的方法,称为greedy解码。
另一种是每一步保留头部高概率的两个输出,根据这两个输出在预测下一步,再保留头部高概率的两个输出,重复直到结束,即beam-search,该过程只在预测阶段需要。

Go Forth And Transform

如果想了解更深,下面是一些步骤:

  1. 阅读Attention Is All You Need 原文,the transform 博客,以及Tensor2Tensor announcement
  2. 查看Łukasz Kaiser’s talk 模型以及它的细节
  3. play with Jupyter Notebook provided as part of the Tensor2Tensor repo
  4. explore the Tensor2Tensor repo

后续工作:

Logo

尧米是由西云算力与CSDN联合运营的AI算力和模型开源社区品牌,为基于DaModel智算平台的AI应用企业和泛AI开发者提供技术交流与成果转化平台。

更多推荐