深度学习-详细讲解Transformer

图解Transformer

参考:

Jay Alammar:The Illustrated Transformer

1.关于Transformer

Transformer 是在论文Attention is All You Need 中提出的。在这篇文章中,我们将介绍The Transformer——一种使用注意力来提高这些模型训练速度的模型。Transformers 在特定任务中的表现优于 Google 神经机器翻译模型。然而,最大的好处来自 The Transformer 如何将其自身用于并行化。因此,让我们尝试分解模型并看看它是如何运作的。

2.宏观视角分析

让我们首先将模型视为单个黑匣子。在机器翻译应用程序中,它会用一种语言输入一个句子,然后用另一种语言输出它的翻译。

深度学习-详细讲解Transformer
打开黑匣子我们会看到一个编码组件、一个解码组件以及它们之间的连接。
深度学习-详细讲解Transformer
编码组件是一堆编码器(下图将其中的六个堆叠在一起——数字 6 没有什么神奇之处,人们绝对可以尝试其他安排)。解码组件是一堆相同数量的解码器。
深度学习-详细讲解Transformer
编码器在结构上都是相同的(但它们不共享权重)。每一层又分为两个子层——自注意力模块和前馈神经网络:
深度学习-详细讲解Transformer
编码器的输入首先流经自注意力层——该层帮助编码器在编码特定单词时关注输入句子中的其他单词。我们将在后面的文章中仔细研究 self-attention。
自注意力层的输出被馈送到前馈神经网络。完全相同的前馈网络独立应用于每个位置。
解码器具有这两层,但它们之间是一个注意力层,帮助解码器专注于输入句子的相关部分(类似于seq2seq 模型中的注意力)。
深度学习-详细讲解Transformer

; 3.将张量带入图片

现在我们已经看到了模型的主要组件,让我们开始看看各种向量/张量,以及它们如何在这些组件之间流动以将训练模型的输入转换为输出。
与 NLP 应用的一般情况一样,我们首先使用嵌入算法将每个输入词转换为向量。

深度学习-详细讲解Transformer
嵌入仅发生在最底层的编码器中。所有编码器都有一个相同的特点:它们接收一个向量列表,每个向量的大小为 512。 在底部编码器中,这将是词嵌入,但在其他编码器中,它将是 直接位于下方的编码器的输出. 这个列表的大小是我们可以设置的超参数—— 基本上它是我们训练数据集中最长句子的长度。
在我们的输入序列中嵌入单词后,它们中的每一个都流经编码器的两层中的每一层。
深度学习-详细讲解Transformer
在这里,我们开始看到 Transformer 的一个关键属性,即每个位置的单词在编码器中都流经自己的路径。self-attention 层中这些路径之间存在依赖关系。然而,前馈层没有这些依赖关系,因此各种路径可以在流经前馈层时并行执行。
接下来,我们将示例切换为更短的句子,并查看编码器的每个子层中发生的情况。

4.开始”编码”

正如我们已经提到的,编码器接收一个向量列表作为输入。它通过将这些向量传递到一个”自我注意”层,然后传递到一个前馈神经网络,然后将输出向上发送到下一个编码器来处理这个列表。

深度学习-详细讲解Transformer
每个位置的单词都经过一个自注意力过程。然后,它们每个都通过一个前馈神经网络——完全相同的网络,每个向量都会流过它。

; 5.宏观角度的Self-Attention

通过《Attention is All You Need》一文,让我们提炼它是如何工作的。
假设以下句子是我们要翻译的输入句子:
” The animal didn’t cross the street because it was too tired”
这句话中的”it “指的是什么?它指的是街道还是动物?这对人类来说是一个简单的问题,但对算法来说并不那么简单。
当模型处理*”it” 这个词时,self-attention 允许它把“it” “animal” _联系起来。
当模型处理每个单词(输入序列中的每个位置)时,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。
如果您熟悉 RNN,请考虑维护隐藏层的。RNN会将它已经处理过的前面的所有单词/向量的表示与它正在处理的当前单词/向量结合起来。自注意力是 Transformer 用来将其他相关词的”理解”融入我们当前正在处理的词中的方法。

深度学习-详细讲解Transformer
请务必查看Tensor2Tensor 笔记本,您可以在其中加载 Transformer 模型,并使用此交互式可视化对其进行检查。

6.详细讲解Self-Attention

让我们首先看看如何使用向量计算自注意力,然后继续看看它是如何实际实现的——使用矩阵。

  • 第一步骤:Self-Attention从每个编码器的输入向量出发,创建三个矢量(每个字的词向量)。
    因此,对于每个单词,我们创建一个 Query 向量、一个 Key 向量和一个 Value 向量。这些向量是通过词嵌入与三个权重矩阵后相乘创建的。。
    请注意,这些新向量的维度比嵌入向量要小。它们的维数是 64,而嵌入和编码器输入/输出向量的维数是 512。它们不必更小,这是一种架构选择,可以使多头注意力的计算(大部分)保持不变。
    深度学习-详细讲解Transformer
    X1乘以WQ权重矩阵产生Q1,与该字相关联的”查询”载体。我们最终为输入句子中的每个单词创建了一个”查询”、一个”键”和一个”值”投影。
    什么是”查询”、”键”和”值”向量?
    它们都是有助于计算和理解注意力机制的抽象概念。
  • 第二个步骤是计算得分。
    假设我们正在计算此示例中第一个单词”Thinking”的自注意力。我们需要拿输入句子中的每个单词对”Thinking”打分。分数决定了编码”Thinking”时将多少注意力放在输入句子的其他部分上。
    得分是通过将查询向量与我们正在评分的各个单词的关键向量进行点积来计算的。因此,如果我们正在处理位置#1 中单词的自注意力,第一个分数将是q1和k1的点积。第二个分数是q1和k2的点积。
    深度学习-详细讲解Transformer
  • 第三和第四步骤是将分数除以8(8是论文中使用的键向量的维数64的平方根,这会让梯度更稳定。这里也可以使用其它值,8只是默认值),然后通过 softmax 操作传递结果。Softmax 对分数进行归一化,因此它们都是正数,加起来为 1。
    深度学习-详细讲解Transformer
    这个 softmax 分数决定了每个单词对编码当下位置(”Thinking”)的贡献。很明显,这个位置的词将具有最高的 softmax 分数,但有时关注与当前词相关的另一个词是有用的。
  • 第五步骤是由SOFTMAX得分乘以每个值向量(准备中总结起来)。这里的策略是保持我们想要关注的单词的值不变,并降低不相关的单词的影响(例如,通过将它们乘以像 0.001 这样的小数字)。
  • 第六步是对加权值向量求和,然后即得到自注意力层在该位置的输出(在我们的例子中是对于第一个单词)。
    深度学习-详细讲解Transformer
    自注意力计算到此结束。结果向量是我们可以发送到前馈神经网络的向量。然而,在实际的实现中,为了更快的处理,这个计算是以矩阵形式完成的。既然我们已经看到了单词级别计算的直觉,那么让我们来看看。

; 7.Self-Attention 的矩阵计算

第一步是计算查询、键和值矩阵。我们通过将我们的嵌入打包到一个矩阵X 中,并将其乘以我们训练过的权重矩阵(WQ、WK、WV)来做到这一点。

深度学习-详细讲解Transformer
X矩阵 中的每一行对应于输入句子中的一个词。我们再次看到嵌入向量(512或图中的 4 个框)和 q/k/v 向量(64或图中的 3 个框)的大小差异
最后,由于我们正在处理矩阵,我们可以将第二到第六步浓缩在一个公式中来计算自注意力层的输出。
深度学习-详细讲解Transformer

8.多头注意力机制

论文通过添加一种称为”多头”注意力的机制进一步细化了自注意力层。这通过两种方式提高了注意力层的性能:

  • 它扩展了模型专注于不同位置的能力。在上面的例子中, z1体现了其他单词对当前单词编码的贡献,但是它主要被实际的单词本身所支配。如果我们翻译一个句子,比如”The animal didn’t cross the street because it was too tired”,我们会想知道”it”指的是哪个词,这时模型的”多头”注意机制会起到作用。
  • 它为注意力层提供了多个”表示子空间”。对于多头注意力,我们不仅有一个,而且还有多组查询/键/值权重矩阵(转换器使用八个注意力头,所以我们最终为每个编码器/解码器提供了八组) . 这些集合中的每一个都是随机初始化的。然后,在训练之后,每组用于将输入嵌入(或来自较低编码器/解码器的向量)投影到不同的表示子空间中。
    深度学习-详细讲解Transformer
    通过多头注意力,我们为每个头维护单独的 Q/K/V 权重矩阵,从而产生不同的 Q/K/V 矩阵。正如我们之前所做的那样,我们将 X 乘以 WQ/WK/WV 矩阵以生成 Q/K/V 矩阵。
    如果我们进行上面概述的相同自注意力计算,只需使用不同的权重矩阵进行 8 次不同的计算,我们最终会得到 8 个不同的 Z 矩阵
    深度学习-详细讲解Transformer
    这给我们留下了一些挑战。前馈层不需要八个矩阵——它需要一个矩阵(每个单词一个向量)。所以我们需要一种方法将这八个压缩成一个矩阵。
    我们怎么做?我们将矩阵连接起来,然后通过一个额外的权重矩阵 WO 将它们相乘。
    深度学习-详细讲解Transformer
    这几乎就是多头自注意力的全部内容,这是相当多的矩阵。让我尝试将它们全部放在一个视觉效果中,以便我们可以在一个地方查看它们
    深度学习-详细讲解Transformer
    现在我们已经接触到了注意力头,让我们重新审视之前的例子,看看在我们对例句中的单词”it”进行编码时,不同的注意力头集中在哪里:
    深度学习-详细讲解Transformer
    当我们编码”it”一词时,一个注意力头集中在”animal”上,而另一个则集中在”tired”上,从某种意义上说,模型对”it”一词的表达在某种程度上是”animal”和”tired”的代表。
    然而,如果我们将所有注意力都添加到图片中,事情可能更难解释:
    深度学习-详细讲解Transformer

; 9.使用位置编码表示序列的顺序

正如我们迄今为止所描述的那样,模型中缺少的一件事是一种解释输入序列中单词顺序的方法。
为了解决这个问题,转换器为每个输入嵌入添加了一个向量。这些向量遵循模型学习的特定模式,这有助于确定每个单词的位置,或序列中不同单词之间的距离。这里的直觉是,将这些值添加到嵌入中后,一旦将它们投影到 Q/K/V 向量中并在点积注意期间,嵌入向量之间就会提供有意义的距离。

深度学习-详细讲解Transformer
为了让模型了解单词的顺序,我们添加了位置编码向量——其值遵循特定模式。
如果我们假设词嵌入的维数为4,则实际的位置编码如下:
深度学习-详细讲解Transformer
嵌入大小为 4 的位置编码的真实示例
这种模式可能是什么样子?
在下图中,每一行对应一个向量的一个位置编码。所以第一行将是我们添加到输入序列中第一个词的嵌入的向量。每行包含 512 个值——每个值都在 1 到 -1 之间。我们对它们进行了颜色编码,因此图案是可见的。
深度学习-详细讲解Transformer
20 个词(行)位置编码的真实示例,嵌入大小为 512(列)。你可以看到它看起来在中心分成两半。这是因为左半部分的值由一个函数(使用正弦)生成,右半部分由另一个函数(使用余弦)生成。然后将它们连接起来形成每个位置编码向量。
它的优势在于能够扩展到看不见的序列长度(例如,如果我们训练的模型被要求翻译一个比我们训练集中的任何一个都长的句子)。

10.残差模块

每个编码器中的每个子层(self-attention,feed forward)周围都有一个残差连接,然后是层归一化步骤。

深度学习-详细讲解Transformer
如果我们去可视化这些向量以及这个和自注意力相关联的层-归一化操作,那么看起来就像下面这张图描述一样:
深度学习-详细讲解Transformer
这也适用于解码器的子层。如果我们考虑一个由 2 个堆叠编码器和解码器组成的 Transformer,它看起来像这样:
深度学习-详细讲解Transformer

; 11.解码器

看看编码器和解码器是如何协同工作的
编码器首先处理输入序列。然后将顶级编码器的输出转换为一组注意力向量 K 和 V。 这些将由每个解码器在其”编码器-解码器注意力”层中使用,帮助解码器专注于输入序列中的适当位置:

深度学习-详细讲解Transformer
下面的步骤重复这个过程,直到一个特殊的 符号到达表示转换器解码器已完成其输出。每一步的输出在下一个时间步被馈送到底部解码器,解码器就像编码器一样冒泡他们的解码结果。就像我们对编码器输入所做的一样,我们将位置编码嵌入并添加到这些解码器输入中,以指示每个单词的位置。
深度学习-详细讲解Transformer
而那些解码器中的自注意力层表现的模式与编码器不同:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置。在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。
这个”编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵。

11.最终的线性变换和Softmax层

解码器堆栈输出浮点数向量。我们如何把它变成一个词?这是最后一个 Linear 层的工作,其后是一个 Softmax 层。
线性层是一个简单的全连接神经网络,它将解码器堆栈产生的向量投影到一个更大的向量中,称为 logits 向量。
假设我们的模型知道 10,000 个独特的英语单词(我们模型的”输出词汇”),这些单词是从训练数据集中学习的。这将使 logits 向量有 10,000 个单元格宽——每个单元格对应一个唯一单词的分数。这就是我们如何解释模型的输出,然后是线性层。
softmax 层然后将这些分数转换为概率(全部为正,加起来为 1.0)。选择概率最高的单元格,并生成与之关联的单词作为该时间步的输出。

深度学习-详细讲解Transformer
该图从底部开始,生成的向量作为解码器堆栈的输出。然后将其转换为输出字。

; 12.训练总结

在训练期间,未经训练的模型将经历完全相同的前向传递。但是由于我们是在一个带标签的训练数据集上训练它,我们可以将它的输出与实际的正确输出进行比较。
为了可视化这一点,假设我们的输出词汇表仅包含六个单词(”a”、”am”、”i”、”thanks”、”student”和””(”end of sentence”的缩写)) .

深度学习-详细讲解Transformer
模型的输出词汇表是在我们开始训练之前的预处理阶段创建的。
一旦我们定义了输出词汇表,我们就可以使用相同宽度的向量来表示词汇表中的每个单词。这也称为独热编码。例如,我们可以使用以下向量表示单词”am”:
深度学习-详细讲解Transformer
讨论模型的损失函数——我们在训练阶段优化的指标,以形成一个训练有素的、希望非常准确的模型。
假设我们正在训练我们的模型。假设这是我们在训练阶段的第一步,我们正在用一个简单的例子来训练它——将”merci”翻译成”thanks”。
这意味着,我们希望输出是一个概率分布,表示”thanks”这个词。但由于该模型尚未经过训练,因此目前不太可能发生。
深度学习-详细讲解Transformer
由于模型的参数(权重)都是随机初始化的,(未经训练的)模型会为每个单元格/单词生成具有任意值的概率分布。我们可以将其与实际输出进行比较,然后使用反向传播调整所有模型的权重,使输出更接近所需的输出。
你会如何比较两个概率分布呢?我们可以简单地用其中一个减去另一个。更多细节请参考交叉熵和KL散度。
但注意到这是一个过于简化的例子。更现实的情况是处理一个句子。例如,输入”je suis étudiant”并期望输出是”i am a student”。那我们就希望我们的模型能够成功地在这些情况下输出概率分布:
  • 每个概率分布被一个以vocab_size (我们的例子里是6,但现实情况通常是3000或10000)为宽度的向量所代表。
  • 第一个概率分布在与”i”关联的单元格有最高的概率
  • 第二个概率分布在与”am”关联的单元格有最高的概率
  • 以此类推第五个输出的分布表示””关联的单元格有最高的概率
    深度学习-详细讲解Transformer
    在足够大的数据集上训练模型足够长的时间后,我们希望生成的概率分布如下所示:
    深度学习-详细讲解Transformer
    我们期望训练过后,模型会输出正确的翻译。当然如果这段话完全来自训练集,它并不是一个很好的评估指标(参考:交叉验证,链接https://www.youtube.com/watch?v=TIgfjmp-4BA)。注意到每个位置(词)都得到了一点概率,即使它不太可能成为那个时间步的输出——这是softmax的一个很有用的性质,它可以帮助模型训练。
    因为这个模型一次只产生一个输出,不妨假设这个模型只选择概率最高的单词,并把剩下的词抛弃。这是其中一种方法(叫贪心解码)。另一个完成这个任务的方法是留住概率最靠高的两个单词(例如I和a),那么在下一步里,跑模型两次:其中一次假设第一个位置输出是单词”I”,而另一次假设第一个位置输出是单词”me”,并且无论哪个版本产生更少的误差,都保留概率最高的两个翻译结果。然后我们为第二和第三个位置重复这一步骤。这个方法被称作集束搜索(beam search)。在我们的例子中,集束宽度是2(因为保留了2个集束的结果,如第一和第二个位置),并且最终也返回两个集束的结果(top_beams也是2)。这些都是可以提前设定的参数。

13.进阶学习

关于深入学习可以进行以下学习工作:

Original: https://blog.csdn.net/ssshyeong/article/details/120758986
Author: HheeFish
Title: 深度学习-详细讲解Transformer

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/542602/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球