这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能

前言

本文将深入剖析Transformer的内部工作原理,详细研究其运作细节。

我们将通过实际的矩阵表示和形状,观察数据如何在系统中流动,并理解每个阶段进行的计算。

本文目标不仅是理解Transformer是如何工作的,更要探究它为何如此工作。

架构概览

正如我们在第一部分中看到的,Transformer架构的主要组件包括:

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_transformer_02

编码器和解码器的数据输入包括:

  • 嵌入层
  • 位置编码层

编码器堆栈由多个编码器组成,每个编码器内部包含:

  • 多头注意力层
  • 前馈神经网络层

解码器堆栈则由多个解码器组成,每个解码器内部包含:

  • 两个多头注意力层
  • 前馈神经网络层

输出(右上角)——生成最终输出,包含:

  • 线性层
  • Softmax层

为了理解每个组件的作用,让我们以训练Transformer解决翻译问题为例,来逐步了解它的工作原理。

我们将使用训练数据中的一个样本,该样本由输入序列(英文“You are welcome”)和目标序列(西班牙文“De nada”)组成。

嵌入与位置编码

与任何自然语言处理(NLP)模型一样,Transformer需要了解每个单词的两方面信息——单词的含义及其在序列中的位置。

  • 嵌入层:负责编码单词的含义。
  • 位置编码层:负责表示单词在序列中的位置。

Transformer通过将这两个编码相加来结合这两方面的信息。

嵌入处理

Transformer具有两个嵌入层,输入序列被送入第一个嵌入层,即输入嵌入层。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_03

目标序列在向右移动一个位置并在第一个位置插入一个开始标记后,被送入第二个嵌入层。

请注意,在推理过程中,我们没有目标序列,而是将输出序列循环地送入这个第二层,因此,它被称为输出嵌入。

文本序列通过词汇表被映射为数字形式的单词ID,然后,嵌入层将每个输入单词映射到一个嵌入向量中,这个向量是该单词含义的更丰富表示。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_transformer_04

位置编码

由于循环神经网络(RNN)通过顺序输入每个单词来实现循环,因此它隐式地知道每个单词的位置。

然而,Transformer不使用RNN,且序列中的所有单词都是并行输入的。

这是它相对于RNN架构的主要优势,但也意味着位置信息丢失了,需要单独添加回来。

与两个嵌入层类似,也有两个位置编码层。位置编码是根据输入序列独立计算的。这些值是固定的,仅取决于序列的最大长度。

例如:

  • 第一个元素是一个表示第一个位置的常量编码
  • 第二个元素是一个表示第二个位置的常量编码
  • 以此类推

这些常量通过使用以下公式计算得出,其中:

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_深度学习_05

  • pos 是单词在序列中的位置
  • d_model 是编码向量的长度(与嵌入向量相同)
  • i 是该向量的索引值

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_ai_06

换句话说,它通过正弦曲线和余弦曲线的交错来编码,偶数索引使用正弦值,奇数索引使用余弦值。

例如,如果我们编码一个40个单词的序列,我们可以看到下面几个(单词位置,编码索引)组合的编码值。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_语言模型_07

蓝色曲线显示了所有40个单词位置的第0个索引的编码,橙色曲线显示了所有40个单词位置的第1个索引的编码,剩余的索引值也会有类似的曲线。

矩阵维度

我们知道,深度学习模型一次处理一批训练样本。嵌入层和位置编码层在代表一批序列样本的矩阵上操作。

嵌入层接受一个形状为(样本数,序列长度)的单词ID矩阵,将每个单词ID编码为一个长度等于嵌入大小的词向量,从而生成一个形状为(样本数,序列长度,嵌入大小)的输出矩阵。

位置编码使用与嵌入大小相等的编码大小,因此它产生一个形状相似的矩阵,该矩阵可以与嵌入矩阵相加。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_深度学习_08

嵌入层和位置编码层产生的(样本数,序列长度,嵌入大小)形状在Transformer中一直保持不变,直到数据流经编码器和解码器堆栈,最后被最终输出层重新塑形。

这给出了Transformer中3D矩阵维度的概念,然而,为了简化可视化,从现在起我们将省略第一维(对于样本),并使用单个样本的2D表示。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_09

输入嵌入将其输出发送到编码器。类似地,输出嵌入将其输出送入解码器。

编码器

编码器和解码器堆栈分别由几个(通常是六个)编码器和解码器顺序连接而成。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_10

堆栈中的第一个编码器从嵌入层和位置编码接收输入。堆栈中的其他编码器从前一个编码器接收输入。

编码器将其输入传递给多头自注意力层。自注意力层的输出被传递到前馈神经网络层,然后将其输出向上传递到下一个编码器。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_transformer_11

自注意力层和前馈神经网络子层都围绕它们有一个残差跳跃连接,之后是层归一化。

如下所述,最后一个编码器的输出被送入解码器堆栈中的每个解码器。

解码器

解码器的结构与编码器非常相似,但有一些不同。

与编码器一样,堆栈中的第一个解码器从输出嵌入和位置编码接收输入。堆栈中的其他解码器从前一个解码器接收输入。

解码器将其输入传递给多头自注意力层。但这与编码器中的自注意力层工作方式略有不同。

它只允许关注序列中较早的位置,这是通过屏蔽未来位置来实现的,稍后将详细介绍。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_ai_12

与编码器不同,解码器包含第二层多头注意力机制,即编码器-解码器注意力层。

编码器-解码器注意力层的工作原理类似于自注意力机制,但其特殊之处在于它结合了两种输入源:其下方的自注意力层输出以及编码器堆叠的输出。

自注意力层的输出会传递给一个前馈神经网络层,该层随后将其输出向上传递至下一个解码器。

这三个子层——自注意力层、编码器-解码器注意力层以及前馈神经网络层——都围绕残差连接进行,之后进行层归一化。

注意力机制

在第一部分中,我们讨论了为什么在处理序列时注意力机制如此重要。

在Transformer模型中,注意力机制在三个地方被使用:

  • 编码器的自注意力:输入序列关注自身
  • 解码器的自注意力:目标序列关注自身
  • 解码器的编码器-解码器注意力:目标序列关注输入序列

注意力层通过三个参数接收输入,分别称为查询(Query)、键(Key)和值(Value)。

  • 在编码器的自注意力中,编码器的输入被传递给这三个参数。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_ai_13

  • 在解码器的自注意力中,解码器的输入同样被传递给这三个参数。
  • 在解码器的编码器-解码器注意力中,编码器堆叠的最终输出被传递给值(Value)和键(Key)参数,而其下方的自注意力(及层归一化)模块的输出被传递给查询(Query)参数。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_深度学习_14

多头注意力

Transformer将每个注意力处理单元称为一个注意力头,并并行重复多次,这称为多头注意力。

它通过组合多个类似的注意力计算结果,增强了注意力机制的区分能力。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_15

查询(Query)、键(Key)和值(Value)各自通过独立的线性层(各层具有自己的权重)传递,产生三个结果分别称为Q、K、V。

然后,使用下面的注意力公式将这些结果组合起来,生成注意力分数。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_transformer_16

重要的是要认识到,Q、K、V值携带了序列中每个单词的编码表示。

注意力计算随后将序列中的每个单词与其他单词相结合,使得注意力分数为序列中的每个单词编码了一个分数。

之前在讨论解码器时,我们简要提到了掩码。

掩码也显示在上面的注意力图中。让我们看看它是如何工作的。

注意力掩码

在计算注意力分数时,注意力模块执行一个掩码步骤,掩码有两个目的:

在编码器的自注意力和编码器-解码器注意力中:掩码用于将输入句子中填充部分的注意力输出置为零,以确保填充不参与自注意力计算。(注意:由于输入序列长度可能不同,它们通常会被扩展为固定长度的向量,以便输入到Transformer中)

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_17

同样地,对于编码器-解码器注意力机制也是如此。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_transformer_18

在解码器的自注意力中:掩码用于防止解码器在预测下一个单词时“偷看”目标句子的其余部分。

解码器处理源序列中的单词,并使用它们来预测目标序列中的单词。

在训练期间,这通过Teacher Forcing实现,即将完整的目标序列作为解码器输入。

因此,在预测某个位置的单词时,解码器可以使用该单词之前的目标单词以及该单词之后的目标单词。这允许解码器通过使用未来“时间步”中的目标单词来“作弊”。

例如,在预测“单词3”时,解码器应仅参考目标中的前3个输入单词,而不应参考第四个单词“Ketan”。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_语言模型_19

因此,解码器会屏蔽掉序列中后续出现的输入单词。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_深度学习_20

在计算注意力分数时(参考之前显示计算的图片),掩码被应用于Softmax之前的分子部分。

被屏蔽的元素(白色方块)被设置为负无穷大,以便Softmax将这些值转换为零。

生成输出

堆叠中的最后一个解码器将其输出传递给输出组件,该组件将其转换为最终输出句子。

线性层将解码器向量投影为单词分数,每个分数对应目标词汇表中每个唯一单词在句子中每个位置的出现概率。例如,如果我们的最终输出句子有7个单词,目标西班牙语词汇表有10000个唯一单词,我们将为这7个单词中的每一个生成10000个分数值。分数值表示词汇表中每个单词在该句子位置出现的可能性。

然后,Softmax层将这些分数转换为概率(这些概率加起来等于1.0)。

在每个位置,我们找到概率最高的单词的索引,然后将该索引映射到词汇表中对应的单词。这些单词随后形成Transformer的输出序列。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_人工智能_21

训练与损失函数

在训练期间,我们使用如交叉熵损失这样的损失函数来比较生成的输出概率分布与目标序列。

概率分布给出了词汇表中每个单词在该位置出现的概率。

这样图解Transformer应该没人看不懂了吧——Transformer工作原理_深度学习_22

假设我们的目标词汇表仅包含四个单词,我们的目标是生成一个与目标序列“De nada END”相匹配的概率分布。

这意味着第一个单词位置的概率分布中,“De”的概率为1,而词汇表中其他所有单词的概率均为0。

类似地,“nada”和“END”应分别在第二个和第三个单词位置具有概率为1。

通常,我们使用损失来计算梯度,以通过反向传播训练Transformer。

结论

希望这能让你对Transformer在训练过程中的内部工作机制有所了解。正如我们在上一篇文章中讨论的那样,它在推理过程中会循环运行,但大部分处理过程保持不变。