一文讲清Transformer工作原理,36张图解 Transformer

01 整体视角

我们先从高层角度看一下这个模型,把它当作一个黑盒来看。在机器翻译的应用中,它接收一段源语言的句子,输出目标语言的翻译结果。

如果我们"打开"这个像擎天柱一样强大的结构,会看到里面主要包括三个部分:一个编码器模块、一个解码器模块,以及它们之间的连接。

编码器模块由多个编码器堆叠而成(论文中是堆叠了六层编码器------这个数字并没有什么神奇之处,完全可以尝试其他层数的组合)。解码器模块也是相同数量的解码器堆叠而成。

更多AI大模型学习视频及资源,都在智泊AI

每个编码器结构都完全相同(但它们之间并不共享参数)。每个编码器又被细分为两个子层:

编码器结构‌

输入序列首先进入自注意力层(self-attention),该子层通过动态关联输入序列中所有词语的表示,使当前词的编码能够整合全局上下文信息。self-attention的具体实现机制将在后续章节展开说明。

自注意力层的输出会进一步输入至前馈神经网络(feed-forward neural network)。该网络采用位置独立的计算方式,即每个时间步的变换操作完全相同且并行执行,各位置间的特征计算不相互依赖。

‌解码器结构‌

解码器同样包含自注意力层和前馈网络层,但在二者之间嵌入了交叉注意力层(cross-attention)。

该层通过显式建模输入序列与当前生成词的关联性,实现类似传统seq2seq模型中注意力机制的聚焦功能,确保解码过程始终关注最相关的上下文信息。

02 引入张量的视角

现在我们已经了解了模型的主要组成部分,接下来我们开始关注向量(或张量)是如何在这些组件之间流动的,从而把一个训练好的模型输入,转化为输出。

就像大多数 NLP 应用中一样,首先我们要做的是将每个输入词转换为一个向量,这一步通常通过嵌入算法(embedding)完成。

每个词均会被映射为512维的向量空间表示。为便于理解,这些向量可抽象为几何方块进行可视化。

词嵌入过程仅在底层编码器层执行。所有编码器的统一接口定义为:接收一个由多个512维向量构成的序列------在底层编码器中,该序列对应词嵌入结果。

而在上层编码器中,则来自下层编码器的输出。序列长度作为可配置的超参数,一般依据训练数据中的最大句长设定。

当输入序列完成词嵌入后,这些向量将按序流经编码器内部的两个核心子层进行处理。

此时我们能够观察到 Transformer 的核心机制特征:编码器内每个位置的词向量均沿独立路径传递。在 self-attention 层中,这些路径会建立相互依赖。

而后续的前馈层则不存在路径间的依赖关系,使得各路径可同步运算,从而提升计算效率。

随后我们将采用更简短的句子示例,逐步分析编码器中各子层的具体处理过程。

03 进入编码阶段

如同前文所述,编码器的输入由一组向量构成。其具体处理步骤如下:首先将向量序列输入至self-attention层进行特征提取,随后通过前馈神经网络进一步加工,最终将处理结果传递至上层相邻编码器以延续后续处理流程。

每个位置的词向量会首先接受self-attention机制的运算处理,随后各自输入到一个前馈神经网络中------需要强调的是,这个神经网络在所有位置共享同一套参数,但每个词向量都是独立地完成前向传播的。

04 高层次理解 Self-Attention

别被我反复强调"self-attention"这个术语弄得紧张,仿佛这是人尽皆知的概念。事实上,直到研读《Attention is All You Need》这篇论文时,我才首次接触到这个机制。下面我们用更通俗的方式说明它的运作原理。

考虑需要翻译的这句话:

"The animal didn't cross the street because it was too tired."(这只动物没有过马路,因为它太累了。)

这里的"it"究竟指代什么?是街道(street)还是动物(animal)?对人类而言这再简单不过,但对机器算法却是个挑战。

当模型解析到"it"这个单词时,self-attention机制会促使它建立与"animal"的关联关系。

在逐个处理输入序列每个词(即每个位置)的过程中,self-attention赋予模型回溯整个序列的能力,从而获取对当前词进行精准编码所需的"上下文线索"。

若你了解RNN,可以类比其通过hidden state(隐藏状态)来整合历史词向量与当前词表示的方法。而在Transformer架构中,self-attention正是实现跨词"理解"的核心手段,它能将相关词的信息动态注入到当前词的表征中。

当我们在第5层编码器(即编码器堆栈的顶层)对单词"it"进行编码时,self-attention机制会分配部分注意力权重给"The animal",并将"animal"的语义特征整合到"it"的编码表示中。

Tensor2Tensor的notebook示例提供了可交互式可视化Transformer模型的工具,强烈推荐尝试。

05 Self-Attention 机制详解

我们先来解析如何通过向量运算实现 self-attention,再探讨其矩阵运算的底层实现逻辑。‌

‌第一步‌

将每个编码器的输入向量(即词嵌入向量)分别映射为三种特征向量:Query 向量、Key 向量和 Value 向量。这一过程意味着每个词嵌入都会被线性变换为三个不同功能的向量。

具体实现时,需将原始词嵌入与三组可学习权重矩阵进行矩阵乘法运算。这些权重矩阵在模型训练过程中通过梯度下降优化得到。

需要特别说明的是,变换后的向量维度会低于原始词嵌入维度。典型配置中,Query/Key/Value 向量维度为 64,而词嵌入及编码器输入/输出的维度为 512。

这种维度缩减并非强制要求,而是为了优化多头注意力机制的计算稳定性而设计的架构选择。

通过将输入向量x₁与权重矩阵WQ相乘,我们获得该词对应的"query"向量q₁。

类似地,输入句子中的每个词都会通过相同的线性变换过程,生成各自的"query"、"key"和"value"向量,这相当于每个词都经历了三种独立的线性映射转换。

那么,"query"、"key"和"value"向量究竟代表什么?

它们是注意力机制计算过程的数学抽象,为理解和实现self-attention提供了结构化视角。随着后续注意力计算步骤的展开,你将清晰看到每个向量在机制中的具体作用。

‌第二步‌

在打分计算阶段(score),以句子首词"Thinking"为例,我们需要将其与句中所有词进行关联度评分。该分数决定了编码当前词时应对其他词给予多少关注权重。

具体实现时,分数通过当前词的query向量与其他词的key向量进行点积运算(dot product)获得。例如处理位置1的词时,首个分数为q₁·k₁,第二个分数为q₁·k₂,后续分数依此类推。

第三步和第四步

计算步骤‌

将原始打分值除以8(该数值源于key向量维度的平方根,原文采用维度64,故计算得√64=8)。

此操作的核心目的是优化梯度稳定性。虽然可调整该参数,但8是标准推荐值。随后将计算结果输入softmax函数。

‌功能说明‌

softmax通过归一化处理将输出转化为非负概率分布,且所有结果之和为1。这使得模型能够动态分配输入序列中各词的注意力权重,权重值直接反映该词对当前预测的贡献强度。

softmax 分值‌用于衡量当前位置下每个词的表达强度(注意力权重)。理论上,该位置的词应获得最大归一化分数,但实际中通常会对与之关联的词赋予显著权重。

‌第五步‌

对每个 value 向量施加对应的 softmax 得分(为后续求和做准备)。核心逻辑在于:通过放大目标词的数值(如保留原值),并对无关词施加极低系数(例如 0.001)实现影响压制。

‌第六步‌

汇总加权后的 value 向量。最终输出即自注意力层对当前位置(如首词)的编码结果。

自注意力计算至此已完成‌。所得结果向量将作为输入传递给前馈神经网络。

实际工程实现中该计算会采用矩阵形式来提升运算效率。当前我们已掌握单词层面的计算逻辑,后续将重点探讨矩阵形式下的自注意力实现方法。

06 矩阵计算自注意力

第一步计算 Query、Key 和 Value 矩阵。我们通过将嵌入向量打包成一个矩阵 X,然后将其分别乘以我们训练好的权重矩阵(WQ、WK、WV)来实现。

X 矩阵中的每一行都对应输入句子中的一个单词。我们再次看到嵌入向量(512,图中是 4 个框)与 q/k/v 向量(64,图中是 3 个框)大小的差异。

最后,由于我们处理的是矩阵运算,我们可以将步骤二到六合并为一个公式来计算自注意力层的输出。

自注意力计算的矩阵形式

07 多头注意力机制

论文通过引入一种称为"多头"的注意力机制对自注意力层进行了进一步优化。这种改进显著提升了注意力层的性能,具体表现在以下两个关键方面:

1.它增强了模型对多元位置的关注能力。正如前文示例所示,z1虽然整合了其他编码的部分信息,但可能受实际单词本身的支配性影响。

以翻译句子"那只动物没有穿越街道,因为它太累了"为例,准确识别"它"的指代对象将具有重要价值。

2.它构建了注意力层的多重 "表征子空间"。如后续内容所示,采用多头注意力机制时,系统会配置多组查询/键/值权重矩阵(Transformer模型采用八个注意力头,对应每个编码器/解码器包含八组矩阵)。

这些矩阵经过随机初始化后,在训练过程中会将输入嵌入(或来自底层编码器/解码器的向量)分别投射到各异的表征子空间中。

通过多头注意力机制,我们为每个头保持独立的 Q/K/V 权重矩阵,从而得到不同的 Q/K/V 矩阵。像之前一样,我们将 X 与 WQ/WK/WV 矩阵相乘,以生成 Q/K/V 矩阵。

如果我们按照之前概述的方式,使用不同的权重矩阵分别计算八次自注意力机制,我们最终会得到八个不同的 Z 矩阵。

这给我们带来了一些挑战。因为前馈层并不期望八个矩阵,而是期望一个矩阵(每个词对应一个向量)。所以我们需要一种方法将这八个矩阵压缩成一个矩阵。

我们怎么做到这一点呢?我们将这些矩阵拼接起来,然后用一个额外的权重矩阵 WO 进行乘法运算。

这就是多头自注意力的全部内容了。我知道涉及了不少矩阵。让我试着把它们都放在一个图示里,我们可以在一个地方一起查看它们。

现在我们已经讲解了注意力头,让我们回到之前的例子,看看在编码句子中 "it" 这个词时,不同的注意力头分别关注了哪些部分:

当我们编码 "it" 这个词时,一个注意力头主要关注 "the animal" ,而另一个则主要关注 "tired" ------在某种意义上,模型对 "it" 这个词的表示同时包含了 "animal" 和 "tired" 这两个词的一部分表示。

然而,如果我们将所有注意力头都加到图中,事情可能就变得难以解释了:

08 使用位置编码表示序列顺序

当前模型描述中存在一个关键缺失------对输入序列中单词顺序的建模机制。

为弥补这一不足,Transformer采用位置编码向量与输入嵌入向量相加的方式。

这些编码向量具有特定的数学规律,模型通过训练掌握这些规律,从而识别单词的绝对位置或相对间距。

其设计原理在于:当嵌入向量被转换为Q/K/V向量并参与点积注意力计算时,位置编码能够为模型注入明确的空间关系信息。

为了让模型理解单词的顺序,我们在每个输入的嵌入向量上加上了位置编码向量,这些向量的值遵循特定的模式。

假设嵌入向量的维度为 4,那么实际的位置编码会像这样:

一个真实的例子,使用大小为 4 的嵌入向量来展示位置编码

这个模式是什么样的呢?

在下图中,每一行对应一个位置编码向量。所以第一行就是我们会加到输入序列中第一个单词嵌入向量上的那个位置编码。

每一行包含 512 个值------每个值的范围在 1 到 -1 之间。我们通过颜色编码使得这个模式更加明显。

这是一个实际案例,展示了包含20个单词(行)和512维嵌入维度(列)的位置编码矩阵。

观察可见该矩阵在中间位置被划分为两个部分:左侧数值由正弦函数生成,右侧数值由余弦函数生成,两部分通过拼接组合构成完整的 position embedding 向量。

相关数学公式详见原始论文第3.5节的说明,具体实现代码可见于 get_timing_signal_1d() 函数。

该方法具有显著优势------能够有效处理训练数据中未出现过的超长序列(例如当模型需要翻译比训练集最长句子更长的文本时)。

当前示例采用 Tensor2Tensor 库的 Transformer 实现方案。

需注意论文原始方法采用信号交织(interleave)而非简单拼接,下图直观展示了这种差异。对应的代码实现如下:

09 残差连接

在我们继续之前,需要提到一个编码器架构中的细节:每个编码器中的每个子层(自注意力层、前馈神经网络层)都有一个残差连接,并且每个子层之后都会进行层归一化。

如果我们用图示的方式来展示 self-attention 相关的向量流动和 layer normalization 操作,它大致是这样的:

这同样适用于解码器的各个子层。如果我们设想一个包含两个堆叠编码器和两个堆叠解码器的 Transformer,它的结构大致如下:

10 解码器端

现在我们已经对编码器端的主要概念有了基本认识,这实际上也让我们初步掌握了解码器各个组件的运作机制。

不过,我们还是需要深入探究一下这些组件是如何协同配合的。

编码器会对输入序列进行初步处理。位于最顶层的编码器输出会被转化为一组注意力向量 K 和 V。

这组向量会被每个解码器在其"encoder - decoder attention"层中调用,从而协助解码器聚焦于输入序列的关键位置。

在编码阶段结束后,我们随即转入解码阶段。解码过程中的每一步都会产生目标序列中的一个元素(以本例中的英文翻译句子为例)。

这一循环持续进行,直至生成一个特殊符号,标志着 Transformer 的解码器已完成所有输出。

每一步的输出都会作为输入,传递至下一时间步的最底层解码器,随后这些解码器会如同编码器一般,逐层向上传递它们的解码结果。

同样地,正如我们在编码器侧对输入的处理方式,我们也会对解码器的输入进行 embedding 操作,并添加位置编码,以标识每个词的位置。

解码器中的 self attention 层与编码器中的自注意力层略有不同:

在解码器中,self-attention 层只允许关注输出序列中较早的位置。这是通过在自注意力计算的 softmax 步骤之前,将未来的位置掩蔽(设置为 -inf)来实现的。

"Encoder-Decoder Attention" 层的工作原理与多头自注意力相同,不同之处在于它从下层生成 Query 矩阵,而从编码器堆叠的输出中获取 Keys 和 Values 矩阵。

11 最终的线性和 softmax 层

解码器堆叠生成的是一个连续值向量‌。如何将其转化为具体单词?这一过程由最终线性层完成,后续衔接softmax层实现。

‌线性层‌作为基础全连接网络,将解码器输出的向量映射至更高维空间,生成称为logits的特征向量。

若模型词汇库包含10,000个英文单词(即训练数据构建的"输出词汇表"),则logits向量将包含10,000个维度,每个维度对应一个单词的预测得分。

这正是线性层输出的数学表征。

‌softmax层‌通过指数归一化将这些得分转化为概率分布(确保所有值非负且总和为1.0)。

最终选取概率最大的维度,其对应的单词即为当前时间步的输出结果。

这张图从底部开始,展示了作为解码器堆叠输出的向量。然后,这个向量被转化为一个输出单词。

12 训练回顾

现在我们已经覆盖了经过训练的 Transformer 的整个前向传播过程,接下来我们可以简要回顾一下训练模型的直觉。

在训练过程中,一个未训练的模型会经过完全相同的前向传播。但是,由于我们是在一个带标签的训练数据集上训练它,我们可以将它的输出与实际的正确输出进行比较。

为了可视化这一过程,假设我们的输出词汇表只包含 6 个单词("a"、"am"、"i"、"thanks"、"student"和""(即"句子结束"))。

我们的模型的输出词汇表是在训练开始之前的预处理阶段创建的。

一旦我们定义了输出词汇表,就可以使用一个与词汇表宽度相同的向量来表示词汇表中的每个单词,这也被称为独热编码(one-hot encoding)。

例如,我们可以使用以下向量来表示单词 "am":

示例:我们输出词汇表的独热编码

回顾完训练过程后,让我们来讨论一下模型的损失函数------在训练阶段我们优化的指标,目的是让模型变得更精确,最终获得一个经过训练并且非常准确的模型。

13 损失函数

假设我们正在训练我们的模型。假设这是训练阶段的第一步,我们用一个简单的例子进行训练------将 "merci" 翻译成 "thanks"。

这意味着,我们希望模型的输出是一个概率分布,指向 "thanks" 这个词。但由于这个模型还没有经过训练,这种情况可能不会马上发生。

由于模型的权重参数是随机初始化的,未经训练的模型会为每个词汇单元生成一个具有随机值的概率分布。

通过将模型输出与真实目标分布进行对比,可利用反向传播算法迭代更新所有权重参数,使输出分布逐步逼近理想结果。

衡量两个概率分布差异的常用方法是计算二者之间的差值。但需说明,这仅是简化说明案例。

实际应用中需处理更长的序列------例如输入法语句子"je suis étudiant"时,模型需要逐词生成对应的英语概率分布序列:

每个概率分布均由长度为vocab_size的向量表征(示例中为6,实际场景可能达到30,000或50,000量级)

在第一个输出分布中,单词"i"对应的概率值应达到峰值

第二个分布则需使"am"的概率占据主导地位

依此类推,直至第五个分布指向句子结束符'',该符号同样对应着10,000规模词汇表中的特定单元

我们将在训练示例中为单个句子训练模型的目标概率分布。

在对模型进行足够长时间的训练,并且使用了足够大的数据集后,我们希望生成的概率分布看起来像这样:

通过训练,模型能够生成符合预期的翻译结果。需注意的是,这无法确证该短语是否存在于训练数据中。

关键在于,softmax 的特性使每个输出位置都保留微小概率,这一特性对训练过程至关重要。

由于模型逐词生成输出,一种策略是直接从概率分布中选择最高概率的单词(即贪婪解码)。

另一种方法则保留前两个候选词(如 'I' 和 'a'),在后续步骤中分别以这两个词为起点运行模型:一次假设首词为 'I',另一次假设为 'a',再综合比较位置 #1#2 的误差,选择误差较小的分支。

此过程会逐位置(#2#3 等)重复,称为‌束搜索‌(beam search)。

示例中,束宽(beam_size)设为 2(即始终保留两个未完成的翻译假设),返回束(top_beams)同样为 2(最终输出两个翻译结果)。

这些均为可调整的超参数。

更多AI大模型学习视频及资源,都在智泊AI

相关推荐
爱听歌的周童鞋4 小时前
斯坦福大学 | CS336 | 从零开始构建语言模型 | Spring 2025 | 笔记 | Lecture 6: Kernels,Triton
llm·triton·profiling·cs336·kernels
熊猫钓鱼>_>4 小时前
基于模板提高垂直领域大模型应用场景的文字语言组织准确性
自动化·llm·多模态·模板·rag·垂直领域
大模型教程7 小时前
开源RAG神器RAGFlow深度解析:融合Agent能力,零门槛搭建企业级AI知识库
程序员·llm·agent
AI大模型7 小时前
斩获72k Star!谷歌云AI大牛开源LLM应用案例库,拿来即用
程序员·llm·agent
AI大模型7 小时前
GitHub斩获 19.9k 星!免费!从零开始系统学习大语言模型
程序员·llm·agent
大模型教程7 小时前
后悔没早点读!Sebastian Raschka 新书《从头开始推理》
程序员·llm·agent
302AI8 小时前
Sonnet 4 平替?Claude Haiku 4.5 实测杀疯了:性能不输,价格砍半
llm·claude
武子康8 小时前
AI研究-113 DeepSeek-OCR 原理与架构全解|视觉压缩长文本 SAM-base 16×下采样 CLIP-L 3B-MoE
深度学习·llm·deepseek
扫地的小何尚1 天前
AI创新的火花:NVIDIA DGX Spark开箱与深度解析
大数据·人工智能·spark·llm·gpu·nvidia·dgx