25个公式解读Transformer数学原理

详解Transformer架构背后的数学原理,拆解25个核心公式,助你深度理解大模型。

原文标题:25 个公式深度解读 Transformer 数学原理

原文作者:图灵编辑部

冷月清谈:

本文深入剖析了Transformer架构的数学基础,通过25个核心公式,详细阐述了Transformer的编解码器框架、注意力机制以及前馈网络等关键组件的工作原理。文章从编码器和解码器的结构入手,深入探讨了多头注意力机制、位置编码、残差连接以及层归一化等重要概念。此外,还详细解释了自注意力、交叉注意力的计算方式,以及前馈网络中的ReLU激活函数的作用。最后,通过对编码器和解码器的数学原理进行总结,帮助读者全面理解Transformer的内部机制,为后续的开源代码阅读和模型构建打下坚实的基础。

怜星夜思:

1、Transformer中的位置编码为什么选择正弦和余弦函数,而不是直接使用位置的数值?
2、文章提到了残差连接和层归一化能加速训练,但具体是怎么起作用的?除了加速训练外,还有别的作用吗?
3、Transformer中Query、Key和Value矩阵有什么物理含义?

原文内容

收到图灵寄来的两本书《大模型应用开发极简入门》和《从零构建大模型》,重新点燃了自己深入理解大模型内部机制的热情,不能只知其然而不知其所以然,于是重温大模型核心的 Transformer 架构, 尝试用 25 个公式进行解读,遂成此文。


Transformer 是一种用于处理序列数据的深度学习模型,特别适用于自然语言处理任务。其独特之处在于它们的自我注意力机制。这种机制允许模型确定不同序列部件的重要性,关注输入序列中最相关部分的能力导致了各种自然语言处理任务的显著进步。

01

Transformer 的编解码器框架


Transformer 建立在一个编解码器框架的基础上,该框架旨在有效地处理序列数据,并通过一种称为自注意力机制来捕获长期依赖关系。编码器和解码器是 Transformer 的两个主要部件。可以将编码器想象成一个团队,处理所有来宾信息并将其组织成有意义的类别。它获取输入序列并创建编码,突出显示输入中有哪些部分彼此相关。另一方面,解码器就像是负责生成最终事件计划的团队,使用来自编码器的信息,并利用先前做出的决定,逐步生成输出序列。

每个编码器和解码器由多个相同的层组成,通常为十二层。每个编码器层有两个主要的子层: 一个多头自注意力机制和一个全连接的前馈网络。每个子层都有剩余的连接和层标准化,这有助于稳定和加快训练过程。解码器层是相似的,但有一个额外的多头注意力子层,允许参与编码器的输出。
1.1 编码器


编码器的核心是多头注意力机制。把它想象成一组专家,每个专家都关注输入序列的不同方面。多头注意力不再是单一的专家,而是将输入分成多个较小的注意头。每个头独立地将输入投影到查询、键和值向量中,计算注意力分数,并组合结果。然后将所有头的输出连接起来并进行转换以产生最终结果。这个过程允许模型捕获输入序列中的各种关系。

编码器遵循多头注意力机制,包括位置全连通的前馈神经网络。这个部分就像一个分析师,他接受专家提供的信息并对其进行改进。它由两个线性变换组成,中间有一个 ReLU 激活函数,对序列中的每个位置独立操作。这有助于将与会者信息转换为更丰富的表示形式,向模型添加非线性,并允许它学习复杂的模式。

编码器中的每个子层,包括多头注意力和前馈网络,随后是剩余连接和层归一化。剩余连接,也称为跳跃连接,通过允许梯度直接通过网络,有助于缓解渐变问题。这是通过将子层的输入添加到其输出来完成的。然后,层规范化通过规范化子层的输出来稳定并加快训练过程,从而确保值的分布保持一致。


1.2 解码器


解码器与编码器有一些相似之处,但也引入了一些关键的差异,以促进其在产生输出序列中的作用。就像编码器,解码器有多个相同的层,每一层都包含一个子层,其中包括多头注意力和一个前馈神经网络。编码器和解码器都使用剩余连接和层归一化来增强学习和保持稳定的梯度。

然而,在编码器和解码器之间存在着关键的区别。主要的区别是在每个解码器层中加入第三个子层,称为掩蔽多头注意力机制。这个额外的子层允许解码器专注于先前生成的 token,同时保持序列生成的自回归特性。此外,解码器的多头注意力机制被设计用于处理两个信息源: 输入序列(来自编码器)和部分生成的输出序列。

掩蔽多头注意力机制是解码器所特有的。它的工作方式类似于编码器中使用的标准多头注意力,但包括一个额外的掩蔽步骤。这种屏蔽确保了解码器在训练期间不能在序列中查看未来的令牌,从而保留了模型的自回归特性。在注意力计算过程中,对输入序列应用一个掩模,将未来标记的注意力分数设置为负无穷大。这有效地防止了模型在生成当前令牌时考虑未来令牌,确保每个令牌仅基于过去令牌和编码的输入序列生成。

解码器的多头注意力子层,包括掩蔽的多头注意力和标准的多头注意力(注意编码器的输出) ,共同生成输出序列。掩蔽多头注意力允许模型一次产生一个 token,而标准的多头注意力集成了来自编码器的信息,使得解码器能够产生连贯和上下文准确的输出。
1.3 注意力机制


注意力机制是 Transformer 高效运行的核心创新。它允许模型动态地关注输入序列的不同部分,使它能够捕获依赖关系,而不管依赖关系在序列中的距离如何。Transformer 的注意力机制主要有两种: 自我注意力交叉注意力

自我注意,也称为内注意,用于编码器和解码器层。在自我注意中,序列中的每个元素都关注所有其他元素,包括它自己。这意味着,例如,一个句子中的每个单词都可以考虑其他每个单词,以构建更丰富的上下文表示。
交叉注意在解码器处理编码器输出时使用。这种机制允许解码器集中于输入序列的相关部分,同时生成输出序列中的每个令牌。在交叉注意力中,解码器序列的每个元素都注意到编码器输出的元素,整合来自输入序列的信息以产生最终输出。
自我注意和交叉注意的核心计算是缩放的点积。首先,将每个输入元素投影到三个向量中: Query (Q)、 Key (K)和 Value (V)。然后,在Query 向量上点积key向量,以计算注意力得分,这表明要在输入的不同部分放置多少注意力。这些点积按 key 向量维数的平方根进行缩放,以稳定训练过程中的梯度。按比例缩放的分数然后通过一个 softmax 函数将它们转换成概率,强调输入中最相关的部分。最后,value 向量根据这些注意力得分加权,并相加得出每个输入元素的最终输出。
想象一下,你正在试图理解一个有多个人物和事件同时发生的故事。自注意力可以帮助你考虑每一个角色和每一个其他角色和事件,让你对故事有一个全面的理解。另一方面,交叉注意力专注于故事的具体细节,以确保随着你的进步,能将最相关的信息融入到你的理解中。


02
注意力机制的数学公式

注意力机制决定了一个词在一个序列中应该给每个其他词多少注意力。这从注意力分数的计算开始。对于输入中的每个单词,我们需要确定它应该对其他每个单词给予多少关注。这是使用三个矩阵完成的: Query (Q)、 Key (K) 和 Value (V)。

输入序列中的每个单词首先使用 W_Q、 W_K 和 W_V 的学习权重矩阵投影到这三个矩阵中:



这里,X 是输入序列矩阵,其中每一行对应一个单词嵌入。例如,如果你有一个包含 10 个单词的句子,并且每个单词都由一个 512 维向量表示,那么 X 就是一个 10x512 的矩阵。将输入序列 X 乘以这些权矩阵,将嵌入的每个单词投影到三个新的空间(Q、K和V)中,为注意力机制设置了阶段。

接下来,我们用查询向量 Q 和键向量 K 的点乘来计算注意力得分。这衡量了查询和关键向量之间的相似性:


图片


这个操作生成一个原始注意力得分矩阵,其中每个元素代表一对单词之间的注意力得分。

  • Q 是从 XW_Q 获得的查询矩阵。Q 中的每一行表示序列中每个单词的查询向量。

  • K 是从 XW_K 得到的键矩阵。K 中的每一行表示序列中每个单词的关键向量。

  • K ^ T 是键矩阵的转置。转置 K 会交换它的行和列,这样我们就可以用 Q 来计算点乘。

因此,上述公式的结果是注意力得分矩阵。此矩阵中的每个元素表示输入序列中一对单词之间的注意力得分,指示一个单词应该给另一个单词多少关注。

然而,随着向量维数的增加,点积的值可能会变得非常大,导致在 softmax 操作期间出现较小的梯度。为了抵消这个影响,可以用键向量 d_k 的平方根来衡量注意力得分:


图片


因此,如果每个键向量有 64 个维度,那么关键向量维度的平方根就是 sqrt {64} = 8。这个比例因子有助于稳定梯度,使 softmax 更加有效。Softmax 激活函数将得分转换为概率,确保得分总和为 1,这突出了单词之间最重要的关系:

图片

Softmax 操作使缩放后的分数归一化了。Softmax 对每个缩放得分进行指数化,并将其除以指数化分数之和,将得分转换为概率。这强调了最相关的单词,同时确保所有概率的总和为 1。


图片


注意力机制的最后一步是使用这些注意力权重来计算值向量 V 的加权:


图片


在这里,注意力权重是从 softmax 激活函数中获得的注意力权重矩阵。每个元素代表注意到一个特定单词的概率。V 是从 XW_V 得到的值矩阵。V 中的每一行表示序列中每个单词的值向量。将注意力权重乘以 V 得到值向量的加权和。这个输出是每个单词的新表示形式,包含了整个输入序列的上下文。

Transformer 不使用单一的注意力分数,而是使用多头注意力分数。这意味着输入序列被分成多个较小的部分,每个部分通过上述注意力机制独立处理, 每一部分都叫做头。对于每个头,我们有不同的权矩阵 W_ Q^i,W_K^i 和 W_V^i。在处理每个头之后,我们将它们的输出连接起来,并使用另一组权重 W_O 将它们投影回单个向量空间:


图片


这种多头注意力允许模型同时关注序列的不同部分,捕获广泛的依赖关系。


03
FFN 的数学原理

在多头注意力之后,每个词的表示数据通过位置逐元素前馈网络进一步处理。这个网络独立操作每个单词的表示,并对每个单词应用相同的转换。前馈网络由两个线性变换组成,中间有一个 ReLU 激活函数:


图片


这里 x 是注意力机制的输入,W _ 1和 W _ 2是权矩阵,b _ 1 和 b _ 2 是偏差。这种激活函数引入了非线性,使网络能够学习更复杂的模式。实际上,ReLU 就像一个看门人,不变地传递正值,但阻止负值,把它们变成零。
3.1 层归一化和残差连接


为了稳定和加速训练,编码器中的每个子层(多头注意力和前馈网络)后面都有一个残差连接和层归一化。

残差连接有助于缓解逐渐消失的梯度问题,并允许对更深的网络进行训练。基本思想是将子层的输入添加到其输出中。在数学上,它可以表示为:


图片


这里:
  • X 是子层的输入(子层可以是多头注意力机制或前馈网络)。

  • Sublayer(x) 是处理 X 后面的子层输出。这可能是多头注意力机制或前馈网络的输出。

  • X + Sublayer(x) 是剩余连接,它将原始输入 x 添加到子层的输出。这个增加帮助更容易地通过网络,防止他们变得太小(消失的梯度问题)或太大(爆炸的梯度问题)。

通过将输入 x 添加到子层的输出中,即使子层转换引入了重大更改,模型也可以确保原始信息得到保留。

将层归一化应用于剩余连接的组合输出,以标准化值。这个过程通过确保每一层的输入具有一致的值分布来帮助稳定训练。层归一化的公式是:


图片


把条件分解一下:

  • Z 是层标准化的输入,在这个场景中是 x + Sublayer(x)。

  • mu 计算输入z 的均值

    ,其中 N 是 z 中的元素数(隐藏层的维度)。

  • Sigma 是输入 z 的标准差,计算方法如下:

  • epsilon 是为了数值稳定性而添加的一个小常数,以防止除以零。

  • gamma 是一个学习过的缩放参数,它允许模型调整规范化值。

  • bata 是一个学习移位参数,允许模型调整规范化值。

归一化输出确保每个子层接收平均值为 0 和方差为 1 的输入,这有助于保持稳定的梯度,提高了训练过程的效率和有效性。

3.2 位置编码


Transformer 同时处理序列中的所有令牌,而不是像递归模型(RNN)那样逐个处理。虽然这种并行处理是有效的,但这意味着模型本身并不理解令牌的顺序。为了给模型一个位置感,我们使用位置编码。此编码将有关序列中每个标记的位置的信息添加到其嵌入中。

位置编码是在编码器和解码器栈处理它们之前加入到输入嵌入中的数学表示。最常用的方法是使用不同频率的正弦和余弦函数来生成这些编码。位置编码的公式如下:

  • Pos 是令牌在序列中的位置(从 0 开始)。

  • i 是位置编码的维度索引。

  • d_model 是模型输入嵌入的维度,与位置编码的维度相同。

这些正弦和余弦函数确保序列中的每个位置都有唯一的编码。此外,使用不同的频率允许模型区分不同的位置,以一种既平滑又连续的方式。这对于模型有效地了解令牌的相对位置非常重要。
使用正弦函数和余弦函数有几个好处:
  • 周期性: 正弦函数和余弦函数是周期性的,这意味着它们在规则的时间间隔内重复它们的值。这种周期性对于捕获标记在不同长度序列中的相对位置非常有用。

  • 唯一编码: 每个位置(pos)都有一个独特的编码,因为每个维度的频率是不同的。这确保了模型能够区分不同的位置。

  • 平滑性: 正弦和余弦函数的平滑、连续变化使得模型更容易学习位置编码中的模式。

04
编码器的数学原理

编码器将输入序列转换为一组经过编码的表示形式。首先,输入序列 X 嵌入到一个高维空间中。这种嵌入捕获了序列中每个单词的意思。为了帮助模型理解序列中每个单词的位置,我们向这些嵌入添加位置编码,结果是 X_pos:


图片

接下来,这个组合序列通过多头注意力机制提供。这允许模型同时关注序列的不同部分,生成一个输出 Z_attn:


图片


然后,我们将原始输入 X _ pos 添加回该输出(称为残差连接的过程) ,并应用层标准化来稳定训练。这样我们就得到了 Z _ add _ norm _ 1:


图片


下一步是通过位置前馈网络传递这一结果,该网络应用了额外的变换。该网络的输出为 Z_ffn:


图片


我们再次将输入 Z _ add _ norm _ 1添加回这个输出,并应用层标准化来得到 Z _ encoder _ output:


图片


这个最终输出 Z _ encoder _ output 是输入序列的经过编码的表示形式,准备由解码器处理。


05
解码器的数学原理

解码器通过使用已编码的输入和先前生成的令牌生成输出序列。首先,输入序列 Y (右移)嵌入到一个高维空间。右移是指在开头插入一个特殊的开始标记(通常是‘ < SOS >’表示“启动顺序”) ,然后删除最后一个标记。然后在训练期间将这个移位序列用作解码器的输入。这样做的目的是确保解码器只能使用已经生成(或预测)的令牌,而不能使用任何未来的令牌,从而保持模型的自回归属性。

接下来,我们将位置编码添加到这些嵌入中,形成 Y _ pos:


图片


该序列通过掩蔽的多头注意力机制传递,该机制阻止模型查看序列中的未来标记输出是 Z_masked_attn:


图片


然后,我们将原始输入 Y _ pos 添加回这个输出,并应用层标准化得到 Z _ add _ norm _ 2:


图片


接下来,该输出通过交叉注意力机制传递,该机制允许解码器将注意力集中在来自编码器的编码输入序列的相关部分。结果是 Z _ cross _ attn:


图片


我们将输入 Z _ add _ norm _ 2添加回这个输出并应用层标准化,结果是 Z _ add _ norm _ 3:


图片


这个输出通过另一个位置前馈网络传递,产生 Z _ ffn _ decder:


图片


最后,我们将输入 Z _ add _ norm _ 3 添加回这个输出,并应用层标准化来获得最终的解码器输出 Z _ decder _ output:


图片


这个最终的输出,Z _ decder _ output,然后用来通过一个线性层和一个 Softmax 激活函数生成最终的输出序列。


06
一句话小结

本文从 Transformer 的整体结构开始,对每个组件的计算方式以数学公式表达, 一共 25 个公式,了解了这些数学原理, 无论是看开源代码还是手写 Transformer 都大有裨益。

ps. 当然,深入理解大模型的运行机制仍然是未来更好的开发基于大模型的应用,如果希望快速入门的话,大模型应用开发极简入门》(第2版)或许是个不错的选择。

最后啰嗦一句!要是觉得独自摸索大模型太费劲,想找搭子一起交流,扫码进群就对啦!群里能畅聊图书内容、技术难题,还能抢先读新书,紧跟领域新进展,更有专属福利。别等了,快进群,咱们抱团学习,一起进步!

图片

残差连接就像一个“后悔药”,如果某一层学到的东西不好,可以直接跳过。层归一化就像一个“磨皮滤镜”,让每一层看到的数据都更加“干净”,减少噪声的干扰。这两个技巧都是为了让模型学习得更好更快。

从信息检索的角度看,Query 相当于搜索关键词,Key 相当于文档的索引,Value 相当于文档的内容。通过计算 Query 和 Key 的相关性,可以找到与关键词最相关的文档,然后提取文档的内容作为结果。这种机制使得模型可以根据不同的关键词检索不同的信息。

如果把Transformer看作一个大脑,Query就是大脑发出的指令,Key是记忆的标签,Value是记忆的内容。大脑通过指令和标签的匹配,快速提取出相关的记忆。这样理解是不是更形象?

谢邀,人在实验室,刚下飞船。我个人理解是方便计算相对位置。因为sin(a+b)和cos(a+b)可以用sin(a)sin(b)和cos(a)cos(b)表示,这样模型可以通过学习不同位置的sin(a)和cos(a)来推断它们之间的相对位置关系。

可以将 Query 想象成一个问题,Key 是答案的线索,Value 是答案本身。通过计算 Query 和 Key 的相似度,可以找到与问题最相关的线索,然后根据线索提取相应的答案。这种机制使得模型可以根据不同的问题动态地关注不同的信息。

好问题!直接用位置数值也不是不行,但正余弦函数的周期性让模型更容易学到位置之间的相对关系,而且对长序列泛化性更好。你可以想象一下,如果直接用数值,序列稍微长一点,位置编码的数值就很大了,容易影响模型对其他信息的处理。

残差连接主要解决梯度消失的问题,让信息更容易在网络中传递,相当于给网络加了一条“捷径”。层归一化则是让每一层的输入分布更加稳定,避免训练过程中出现梯度爆炸或消失。除了加速训练,这两个技巧还能提高模型的泛化能力和鲁棒性。

从信号处理的角度看,正余弦函数可以将位置信息编码到不同的频率上,模型可以通过学习不同频率的信号来感知位置信息。而且,正余弦函数的线性组合可以表示任意周期函数(傅里叶变换的思想),这使得模型具有更强的表达能力。

可以从数学角度理解,残差连接相当于在优化目标函数时引入了一个正则化项,约束模型的参数变化不要太大,从而避免过拟合。层归一化则是在每一层都对数据进行标准化处理,使得每一层的输入都具有相似的分布,从而减少了内部协变量偏移现象,提高了模型的收敛速度和稳定性。