Ketan Doshi | 作者 罗伯特
在第一篇文章中,我们了解了Transformer的功能、使用方式、其高级架构以及优势。 前一篇文章,移步:Transformers图解(第1部分):功能概述 在这篇文章中,我们将深入了解它的内部运作,详细研究它是如何工作的。我们将看到数据如何通过系统流动,以及它们的实际矩阵表示和形状,理解每个阶段执行的计算。 以下是本系列中之前和接下来文章的快速摘要。整个系列中的目标是不仅了解某物是如何运作的,而且为什么它以这种方式运作。
功能概述(Transformer的使用方式以及为什么它们比RNN更好。架构的组成部分,以及在训练和推理期间的行为)。
工作原理 — 本文(内部操作端到端。数据如何流动以及在每个阶段执行的计算,包括矩阵表示)。
多头注意力(Transformer中注意力模块的内部工作)。
为什么注意力提升性能(注意力不仅做什么,还为什么它如此有效。注意力如何捕捉句子中单词之间的关系)。
1. 架构概述 正如我们在第一部分中看到的,架构的主要组件包括:
(作者提供的图像)
编码器和解码器的数据输入,其中包括:
嵌入层(Embedding layer)
位置编码层(Position Encoding layer)
解码器堆栈包含多个解码器。每个解码器包含:
两个多头注意力层(Multi-Head Attention layer)
前馈层(Feed-forward layer)
输出(右上方)—生成最终输出,并包含:
线性层(Linear layer)
Softmax层(Softmax layer)
为了理解每个组件的作用,让我们通过训练Transformer解决翻译问题的过程,逐步了解Transformer的工作原理。我们将使用训练数据的一个样本,其中包含输入序列(英语中的'You are welcome')和目标序列(西班牙语中的'De nada')。
2. 嵌入和位置编码
与任何自然语言处理模型一样,Transformer需要了解有关每个单词的两个方面:单词的含义以及它在序列中的位置。 嵌入层编码单词的含义。位置编码层表示单词的位置。Transformer通过将这两种编码相加来组合它们。
2.1 嵌入(embedding)
Transformer有两个嵌入层。输入序列被送入第一个嵌入层,称为输入嵌入。
(作者提供的图像) 目标序列在将目标向右移一个位置并在第一个位置插入起始标记后,被送入第二个嵌入层。请注意,在推理期间,我们没有目标序列,我们将输出序列循环馈送到这第二层,正如我们在第一部分中学到的。这就是为什么它被称为输出嵌入。 文本序列使用我们的词汇表映射为数值单词ID。然后,嵌入层将每个输入单词映射到一个嵌入向量,这是该单词含义的更丰富表示。
(作者提供的图像)
2.2 位置编码
由于RNN实现了一个循环,每个单词都按顺序输入,它隐式地知道每个单词的位置。 然而,Transformer不使用RNN,序列中的所有单词都是并行输入的。这是它相对于RNN架构的主要优势,但这意味着位置信息丢失了,必须单独添加。 就像有两个嵌入层一样,有两个位置编码层。位置编码是独立于输入序列计算的。这些是仅依赖于序列的最大长度的固定值。例如,
第一项是指示第一个位置的常数代码,
第二项是指示第二个位置的常数代码,
以此类推。
这些常数是使用下面的公式计算的,其中:
pos是单词在序列中的位置
d_model是编码向量的长度(与嵌入向量相同)
是该向量中的索引值。
(作者提供的图像) 换句话说,它交替使用正弦曲线和余弦曲线,对于所有偶数索引使用正弦值,对于所有奇数索引使用余弦值。例如,如果我们对一个包含40个单词的序列进行编码,我们可以看到下面是一些(单词位置,编码索引)组合的编码数值。
(作者提供的图像) 蓝色曲线显示了所有40个单词位置的第0个索引的编码,橙色曲线显示了所有40个单词位置的第1个索引的编码。对于其余的索引值,将会有类似的曲线。
3. 矩阵维度
正如我们所知,深度学习模型一次处理一个批次的训练样本。嵌入层和位置编码层操作的是表示一批序列样本的矩阵。嵌入层接收一个形状为(样本数,序列长度)的单词ID矩阵。它将每个单词ID编码成一个长度为嵌入大小的单词向量,从而产生一个形状为(样本数,序列长度,嵌入大小)的输出矩阵。位置编码使用与嵌入大小相等的编码大小。因此,它产生一个形状类似的矩阵,可以添加到嵌入矩阵中。
(作者提供的图像) 由嵌入层和位置编码层产生的形状为(样本数,序列长度,嵌入大小)的矩阵在整个Transformer中得以保留,因为数据通过编码器和解码器堆栈流动,直到被最终的输出层重新整形。 这给出了Transformer中3D矩阵维度的概念。然而,为了简化可视化,从这里开始我们将放弃第一个维度(样本数),并使用单个样本的2D表示。
(作者提供的图像) 输入嵌入将其输出发送到编码器。类似地,输出嵌入馈入解码器。
4. 编码器(Encoder)
编码器和解码器堆栈由若干(通常为六个)编码器和解码器连接而成。
(作者提供的图像) 堆栈中的第一个编码器从嵌入和位置编码接收其输入。堆栈中的其他编码器从前一个编码器接收其输入。 编码器将其输入传递到多头自注意力层。自注意力输出传递到前馈层,然后将其输出向上传递到下一个编码器。
(作者提供的图像) 自注意力和前馈子层都有绕过它们的残差跳连接,然后是一层归一化。 最后一个编码器的输出被馈送到解码器堆栈中的每个解码器,如下所述。
5. 解码器(Decoder)
解码器的结构与编码器非常相似,但有一些区别。 与编码器一样,堆栈中的第一个解码器从输出嵌入和位置编码接收其输入。堆栈中的其他解码器从前一个解码器接收其输入。 解码器将其输入传递到多头自注意力层。这个自注意力层的运作方式略有不同于编码器中的自注意力层。它只允许关注序列中较早的位置。这是通过屏蔽未来位置来实现的,我们将很快讨论。
(作者提供的图像) 与编码器不同,解码器有第二个多头注意力层,称为编码器-解码器注意力层。编码器-解码器注意力层的工作方式类似于自注意力,只是它结合了两个输入源 —— 在它下面的自注意力层以及编码器堆栈的输出。 自注意力输出传递到前馈层,然后将其输出向上传递到下一个解码器。 这些子层,自注意力、编码器-解码器注意力和前馈,都有绕过它们的残差跳连接,然后是一层归一化。
6. 注意力
在第一部分中,我们谈到了在处理序列时为什么注意力非常重要。在Transformer中,注意力在三个地方使用:
编码器的自注意力 — 输入序列关注自身
解码器的自注意力 — 目标序列关注自身
解码器的编码器-解码器注意力 — 目标序列关注输入序列
注意力层以三个参数的形式接收其输入,称为Query(查询)、Key(键)和Value(值)。
在编码器的自注意力中,编码器的输入传递给所有三个参数:Query、Key 和 Value。
(作者提供的图像) 在解码器的自注意力中,解码器的输入传递给所有三个参数:Query、Key 和 Value。在解码器的编码器-解码器注意力中,堆栈中最后一个编码器的输出传递给 Value 和 Key 参数。下面的自注意力(和层归一化)模块的输出传递给 Query 参数。
(作者提供的图像)
7. 多头注意力
Transformer将每个注意力处理器称为一个注意力头,并并行地重复多次。这被称为多头注意力。它通过组合多个类似的注意力计算,使得注意力具有更强的判别力。
(作者提供的图像) Query、Key 和 Value 分别通过单独的线性层传递,每个层都有自己的权重,产生三个结果分别称为 Q、K 和 V。然后,它们使用如下所示的注意力公式结合在一起,产生注意力分数。
(作者提供的图像)
这里需要意识到的重要一点是,Q、K 和 V 值携带了序列中每个单词的编码表示。注意力计算然后将每个单词与序列中的每个其他单词结合在一起,使得注意力分数为序列中的每个单词编码了一个分数。 在稍早前讨论解码器时,我们简要提到了掩码。上述注意力图中也显示了掩码。让我们看看它是如何工作的。
8. 注意力掩码
在计算注意力分数时,注意力模块实施了一个掩码步骤。掩码有两个目的: 在编码器自注意力和编码器-解码器注意力中:掩码用于将输入句子中的填充位置的注意力输出置零,以确保填充不会影响自注意力。(注意:由于输入序列的长度可能不同,它们被扩展为带有填充标记的固定长度向量,就像大多数NLP应用程序一样。)
(作者提供的图像) 编码器-解码器注意力同样如此。
(作者提供的图像) 在解码器的自注意力中:掩码用于防止解码器在预测下一个单词时偷看目标句子的其余部分。 解码器处理源序列中的单词,并使用它们来预测目标序列中的单词。在训练期间,通过教师强制(teacher forcing),完整的目标序列被作为解码器的输入传递。因此,在预测某个位置的单词时,解码器可以使用该单词之前以及之后的目标单词。这使得解码器可以通过使用未来‘时间步’中的目标单词来‘作弊’。 例如,在预测‘Word 3’时,解码器应该只参考目标中的前3个输入单词,而不是第4个单词‘Ketan’。
(作者提供的图像) 因此,解码器屏蔽了序列中稍后出现的输入单词。
(作者提供的图像) 在计算注意力分数时(参考前面显示计算的图片),掩码应用于 Softmax 之前的分子部分。被屏蔽的元素(白色方块)被设置为负无穷,以便 Softmax 将这些值转换为零。
9. 生成输出
堆栈中的最后一个解码器将其输出传递给输出组件,将其转换为最终的输出句子。 线性层将解码器向量投影为单词分数,每个位置的句子中目标词汇表中的每个唯一单词都有一个分数值。例如,如果我们的最终输出句子有7个单词,而目标西班牙语词汇表中有10000个唯一单词,我们将为这7个单词生成10000个分数值。分数值指示了每个单词在该句子位置的出现概率。 然后,Softmax层将这些分数转换为概率(总和为1.0)。在每个位置,我们找到具有最高概率的单词的索引,然后将该索引映射到词汇表中相应的单词。这些单词然后形成Transformer的输出序列。
(作者提供的图像)
10. 训练和损失函数
在训练过程中,我们使用交叉熵损失等损失函数来比较生成的输出概率分布与目标序列。概率分布给出了每个单词在该位置出现的概率。
(作者提供的图像) 假设我们的目标词汇表只包含四个单词。我们的目标是生成一个概率分布,与我们期望的目标序列“De nada END”相匹配。 这意味着第一个单词位置的概率分布应该对“De”有一个概率为1,而对词汇表中所有其他单词的概率为0。同样,“nada”和“END”在第二和第三个单词位置的概率应分别为1。 与往常一样,损失用于计算梯度,通过反向传播来训练Transformer。
11. 结论
希望这能让你对Transformer在训练过程中的内部运作有所了解。正如我们在前一篇文章中讨论的那样,在推理过程中,它运行在一个循环中,但大部分处理方式保持不变。 多头注意力模块是赋予Transformer强大能力的关键。
审核编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !