第20章 Transformer:现代大模型的核心结构

假设你正在翻译一句话。读到最后一个词时,前面的内容仍可能决定它的含义。循环神经网络的办法,是从左到右维护一份不断更新的隐藏状态;第 19 章的注意力机制则允许模型在需要时回看不同位置。2017 年,论文《Attention Is All You Need》提出了更彻底的方案:把注意力放到主体位置,让每个位置直接从其他相关位置收集信息。(Vaswani 等 2017年)

这个架构被命名为 Transformer。今天的大语言模型与原论文相比已经改变了位置编码、归一化方式、激活函数和训练规模,但一条核心数据流仍然清晰可辨:

Token 先变成向量;位置信息进入向量;自注意力在 Token 之间传递信息;前馈网络在每个位置加工信息;许多层重复这一过程;输出层把最终向量变成下一个 Token 的概率。

本章要做的,是跟随一批数据完整走过这条路。普通读者可以先抓住每个部件“负责什么”;技术深潜则会把矩阵形状、掩码、训练目标和计算代价逐项展开。

为什么不再排队传话

循环神经网络(RNN)像一支排队传话的队伍。第 \(t\) 个位置接收第 \(t-1\) 个位置留下的隐藏状态,再与当前输入一起产生新状态。顺序天然包含在计算过程中,但也带来两个困难。

第一,长距离信息要经过许多步才能到达。即使 LSTM 的门控机制缓解了梯度消失,早期信息仍需穿过一条长路径。第二,训练时各位置存在前后依赖,难以像矩阵乘法那样充分并行。

自注意力改变了信息路线。句子中的每个位置都可以直接计算它与其他位置的相关程度,并把相关位置的信息加权汇总。两个相距很远的词,在一层注意力中就可能建立联系。

结构 信息怎样移动 主要优势 主要代价
RNN 沿序列逐步传递隐藏状态 顺序自然、单步状态紧凑 路径长,训练并行度有限
自注意力 任意允许的位置可直接交互 路径短,训练可并行 标准注意力矩阵随序列长度平方增长

“不使用循环”并不意味着模型不再关心顺序。恰恰相反,顺序必须通过另一个部件明确加入,否则交换两个 Token 后,自注意力本身无法知道谁先谁后。

第一步:把文本变成 Token

模型不能直接接收“春风又绿江南岸”这串视觉字符。文本首先经过 Tokenization,被切分为一串离散单位,每个单位称为 Token。Token 可能是一个汉字、一个词、一个子词片段、标点,甚至是字节序列的一部分。

例如,一个只按汉字切分的玩具 Tokenizer 可能得到:

原文:春风又绿江南岸
Token:春 | 风 | 又 | 绿 | 江 | 南 | 岸
编号: 17 | 42 | 08 | 31 | 55 | 12 | 63

真实大模型通常使用子词或字节级方案,在词表大小、序列长度和生僻文本处理之间折中。BPE 一类方法通过反复合并常见符号对,构造可复用的子词单位。(Sennrich 等 2016年) Token 不是天然存在于语言中的唯一正确分界;它是模型设计的一部分。

Tokenization 会影响三件实在的事:

  • 同一段文字占用多少上下文长度;
  • 模型需要学习多少个词表条目;
  • 生僻词、数字、代码和不同语言被拆成什么样。

因此,“模型读了多少字”和“模型处理了多少 Token”不是同一个量。

第二步:编号变成向量

Token 编号只是词表中的索引。编号 63 不比编号 17 “更大”或“更有意义”。模型通过一个可训练的 嵌入矩阵(embedding matrix)把每个编号查成向量。

设词表大小为 \(V\),模型宽度为 \(d_{\text{model}}\),嵌入矩阵为:

\[ E \in \mathbb{R}^{V \times d_{\text{model}}} \]

输入批次包含 \(B\) 段序列,每段长度为 \(T\),则 Token 编号的形状为 \(B\times T\)。查表后得到:

\[ X \in \mathbb{R}^{B \times T \times d_{\text{model}}} \]

现在,每个位置不再是一个整数,而是一个长度为 \(d_{\text{model}}\) 的向量。训练开始时,这些向量通常没有语言意义;在预测误差的反向传播中,经常出现在类似上下文中的 Token 会受到相关的参数更新,表示逐渐形成。

核心机制:表示是训练出来的

Embedding 不是一本由人提前填写的词义词典。它是模型参数的一部分,由训练目标间接塑造。模型学到的是“哪些向量有助于降低预测误差”,不保证每个维度都对应一个可命名的人类概念。

第三步:告诉模型位置

如果只把一组向量交给自注意力,“猫追狗”和“狗追猫”包含相同的 Token 集合。要区分顺序,模型必须获得位置信息

原始 Transformer 使用固定的正弦、余弦位置编码,把不同频率的周期信号加到 Token Embedding 上。其一组分量写作:

\[ \begin{aligned} PE(pos, 2i) &= \sin\left(pos / 10000^{2i/d_{\text{model}}}\right) \\ PE(pos, 2i+1) &= \cos\left(pos / 10000^{2i/d_{\text{model}}}\right) \end{aligned} \]

这里 \(pos\) 是位置,\(i\) 是向量维度索引。不同频率让每个位置拥有不同模式,也让相对位移能够从这些模式中被利用。

位置进入模型不只有这一种办法。后来系统使用过可学习的绝对位置向量、相对位置偏置、旋转位置编码等。它们的共同任务不是“给每个词贴页码”这么简单,而是让注意力计算能够区分顺序和距离。

第四步:每个位置提出查询

进入自注意力层时,每个位置的向量会经过三组不同的线性变换,得到 Query(查询)Key(键)Value(值)

\[ Q=XW^Q, \qquad K=XW^K, \qquad V=XW^V \tag{1}\]

可以借用检索的直觉理解它们:

  • Query 表示“当前位置正在寻找什么信息”;
  • Key 表示“这个位置提供的信息适合被怎样匹配”;
  • Value 表示“如果这个位置被选中,实际传递什么内容”。

这个比喻只能帮助入门。Q、K、V 都是由数据学习出的向量,并没有人给某一维标记“主语”或“时间”。同一个输入向量经过不同矩阵投影,是为了把“怎样匹配”和“传递什么”分开。

对于一个注意力头,先计算每个 Query 与所有 Key 的点积,再除以 \(\sqrt{d_k}\)

\[ S = \frac{QK^T}{\sqrt{d_k}} \tag{2}\]

点积越大,表示当前 Query 与某个 Key 在模型学到的匹配空间里越契合。除以 \(\sqrt{d_k}\) 是为了控制数值尺度;当维度增大时,未经缩放的点积方差会变大,softmax 容易进入梯度很小的饱和区域。

接下来对每一行做 softmax,得到总和为 1 的权重,再加权汇总 Value:

\[ \operatorname{Attention}(Q,K,V) = \operatorname{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + M\right)V \tag{3}\]

\(M\) 是可选的掩码矩阵。输出中每个位置的向量,已经混入了它所关注位置的 Value 信息。

一个四 Token 的形状追踪

暂时忽略批次,设序列有 4 个 Token,模型宽度为 8,一个头的 Query 和 Key 宽度为 4:

张量 形状 含义
\(X\) \(4\times8\) 4 个位置,每个位置 8 维
\(Q,K,V\) \(4\times4\) 每个位置投影出 4 维查询、键和值
\(QK^T\) \(4\times4\) 每个位置对每个位置的匹配分数
\(A=\operatorname{softmax}(S)\) \(4\times4\) 每行是一组注意力权重
\(AV\) \(4\times4\) 每个位置汇总后的信息

\(4\times4\) 的注意力矩阵是关键:行表示“谁在查询”,列表示“它查看谁”。序列长度从 4 增至 4,000 时,这个矩阵的元素数量从 16 增至 1,600 万,而且每个批次、每层、每个头都要进行相应计算。

因果掩码:不能偷看答案

要训练一个从左到右预测下一个 Token 的语言模型,位置 \(t\) 只能使用位置 \(t\) 及以前的信息。如果它在训练时看到未来 Token,任务就会泄漏答案。

因果掩码(causal mask)把未来位置的注意力分数设为负无穷。softmax 后,这些位置的权重变成 0:

\[ M_{ij}= \begin{cases} 0, & j\le i \\ -\infty, & j>i \end{cases} \]

四个位置允许查看的范围如下:

查询位置 可见位置 1 可见位置 2 可见位置 3 可见位置 4
1 可见 - - -
2 可见 可见 - -
3 可见 可见 可见 -
4 可见 可见 可见 可见

这里有一个容易混淆的事实:训练时,整段序列的所有位置仍然可以用矩阵并行计算。掩码限制的是信息流向,不是强迫硬件从左到右逐位置运行。

多头注意力:同时学习不同匹配方式

单个注意力头只在一组投影空间里比较 Token。多头注意力(multi-head attention)把模型宽度分成多个头,每个头拥有自己的 \(W^Q,W^K,W^V\),独立产生注意力结果,再拼接并投影回模型宽度:

\[ \begin{aligned} \text{head}_h &= \operatorname{Attention}(XW_h^Q,XW_h^K,XW_h^V) \\ \operatorname{MHA}(X) &= \operatorname{Concat}(\text{head}_1,\ldots,\text{head}_H)W^O \end{aligned} \tag{4}\]

不同头有机会学习不同关系,例如局部搭配、远距离指代或某类结构线索,但不能机械地认为“一个头就对应一种语法规则”。头的功能可能重叠、随层次改变,也会被后续计算重新组合。

技术深潜:把批次和头维度放回来

设批次大小为 \(B\),序列长度为 \(T\),头数为 \(H\),每头维度为 \(d_h\),通常有 \(d_{\text{model}}=H d_h\)。实现中的典型形状是:

阶段 形状
输入 \(X\) \([B,T,d_{\text{model}}]\)
线性投影后的 \(Q,K,V\) \([B,T,Hd_h]\)
拆分头并转置 \([B,H,T,d_h]\)
注意力分数 \([B,H,T,T]\)
\(V\) 相乘 \([B,H,T,d_h]\)
合并各头 \([B,T,Hd_h]\)
输出投影 \([B,T,d_{\text{model}}]\)

很多实现错误不是公式理解错,而是在 reshapetranspose 后混淆了 \(T\)\(H\)\(d_h\)。一个可靠习惯是为关键张量写出形状断言,并用很小的 \(B,T,H\) 做单元测试。

注意力权重上的 dropout 应用于 softmax 之后;因果掩码必须在 softmax 之前加入分数。如果先做 softmax 再把未来权重设为 0,剩余权重不再自动归一化为 1。

注意力之后,为什么还要前馈网络

如果把 Transformer 简化成“很多注意力”,会漏掉几乎每层都存在的另一半:前馈网络(feed-forward network,FFN)。它对每个位置分别应用相同的两层非线性变换:

\[ \operatorname{FFN}(x)=W_2\,\sigma(W_1x+b_1)+b_2 \]

中间维度通常比模型宽度大。注意力负责在位置之间搬运和混合信息;FFN 负责在每个位置的特征维度上进行非线性加工。二者分工不同,缺一不可。

每个子层外还有残差连接,把输入直接加回输出:

\[ y=x+\operatorname{Sublayer}(x) \]

残差路径让深层网络更容易传递信息和梯度,这一思想在深度残差网络中得到系统展示。(He 等 2016年) 层归一化(Layer Normalization)则按单个样本的特征维度调整数值尺度。(Ba 等 2016年)

原始 Transformer 采用子层之后归一化的 Post-LN 结构。许多现代大语言模型改用 Pre-LN,也就是先归一化,再进入注意力或 FFN:

原始 Post-LN:x -> 子层 -> 加上 x -> LayerNorm
常见 Pre-LN: x -> LayerNorm -> 子层 -> 加上 x

Pre-LN 往往让很深网络的优化更稳定,但“Transformer 必须采用哪一种”并没有脱离具体模型与训练设置的唯一答案。

一个解码器 Block 的完整旅程

现代自回归语言模型常使用仅解码器(decoder-only)结构。一个 Pre-LN Block 可以概括为:

图 1: 仅解码器 Transformer 将 Token 和位置信息送入多层因果自注意力与前馈网络,经过输出投影和 Softmax 得到下一个 Token 的概率;训练可以并行计算各位置损失,生成仍然逐 Token 进行。

第一条支路让每个位置读取允许范围内的其他位置;第二条支路对汇总后的表示进行逐位置加工。输出 \(y\) 再成为下一层的输入。堆叠许多层后,早期的局部线索可以被反复组合成更复杂的上下文表示。

原始论文用于机器翻译,包含编码器和解码器。编码器允许所有输入位置彼此注意;解码器除因果自注意力外,还通过交叉注意力读取编码器输出。后来出现了三条常见路线:

架构 注意力方式 典型训练任务
仅编码器 输入内部通常双向可见 掩码词预测、表示学习
编码器-解码器 编码器双向;解码器因果;二者交叉注意 翻译、条件生成
仅解码器 对已有上下文做因果注意力 下一个 Token 预测、开放式生成

大语言模型常见的仅解码器路线,并不等于 Transformer 的全部定义。

从隐藏向量到下一个 Token

最后一层为每个位置输出一个 \(d_{\text{model}}\) 维向量。线性输出层把它投影到词表大小 \(V\),得到 logits

\[ L = HW_{\text{out}} + b, \qquad L\in\mathbb{R}^{B\times T\times V} \]

softmax 把某一位置上的 \(V\) 个 logits 转成概率分布。训练数据中的目标向右错开一位:

输入: 人 工 智 能 正
目标: 工 智 能 正 在

模型在每个位置预测真实下一个 Token,通常使用交叉熵损失。若真实目标是 \(y_t\),模型给出的条件概率为 \(p_\theta(y_t\mid y_{<t})\),一段序列的平均负对数似然为:

\[ \mathcal{L}(\theta)=-\frac{1}{T}\sum_{t=1}^{T} \log p_\theta(y_t\mid y_{<t}) \tag{5}\]

反向传播会把这一个标量损失的梯度送回输出层、每个 Transformer Block、位置表示和 Token Embedding。模型不是直接收到“这句话的语法规则是什么”的讲解,而是在海量预测错误中调整参数。

核心机制:并行训练,顺序生成

训练时,已知整段正确文本,因果掩码允许同时计算所有位置的下一 Token 损失。生成时,未来 Token 尚不存在,模型必须先产生一个 Token,把它加入上下文,再产生下一个。Transformer 消除了 RNN 在训练数据流上的逐步依赖,却没有消除自回归生成本身的顺序依赖。

训练与生成不是同一条计算路径

训练阶段常使用 teacher forcing:模型在每个位置看到的历史前缀来自真实数据。生成阶段则看到自己此前生成的 Token。一个早期错误可能改变后续上下文,错误由此累积。

生成时,模型先根据提示词计算概率分布,再选择下一个 Token。总选最高概率称为贪心解码;按分布采样可以增加多样性;温度、top-k 和 top-p 等参数改变候选分布。它们改变的是选择策略,不会为模型补充训练中没有学到的事实。

为了避免每一步都重新计算整个前缀,推理系统通常缓存每层过去 Token 的 Key 和 Value,即 KV Cache。生成第 \(t+1\) 个 Token 时,只需为新位置计算新的 Q、K、V,再让新 Query 读取缓存。缓存以显存换取速度,并且会随层数、上下文长度、批次和 KV 头数增长。

它为什么能扩展,又在哪里昂贵

Transformer 的成功不来自一个神奇部件。至少有四个因素彼此配合:

  1. 训练时的位置计算高度并行,适合现代加速器;
  2. 注意力让远距离位置之间拥有短的信息路径;
  3. 同一 Block 可以稳定堆叠,扩大参数量和表示深度;
  4. 下一个 Token 预测能从未经人工逐条标注的文本中构造海量训练信号。

标准全注意力也有明确代价。注意力分数含 \(T\times T\) 的位置对,计算量和中间存储随序列长度快速增长。FlashAttention 等方法通过减少高带宽内存与片上存储之间的数据搬运,使精确注意力更快、更省显存,但不改变标准注意力关于位置对数量的基本二次关系。(Dao 等 2022年)

更长上下文因此不是“把一个数字调大”这么简单。它同时涉及位置表示能否外推、训练样本是否覆盖长依赖、KV Cache 容量、注意力计算和模型能否真正找到远处信息。能接收很长输入,也不保证能稳定利用其中每一处内容。

注意力权重告诉了我们什么

注意力矩阵可以可视化。我们可能观察到某个头偏向相邻 Token,或某层对匹配的标点和指代位置给出较大权重。这类图对发现行为线索很有价值。

但注意力权重不是模型推理过程的完整解释。原因包括:

  • Value 向量传递的内容同样重要;
  • 多个头和多层会反复混合信息;
  • 残差连接绕过注意力支路传递内容;
  • FFN 继续进行大量非线性计算;
  • 高权重表示这一步混合得多,不自动等于对最终答案有因果决定作用。

因此,可以说“这个头在此输入上重点读取了某些位置”,不应仅凭一张热力图就断言“模型正按人类的某条规则思考”。

一次完整的数据流核对

现在把主要步骤压缩在一张表中。设批次为 \(B\)、长度为 \(T\)、模型宽度为 \(D\)、头数为 \(H\)、每头宽度为 \(D_h\)、词表为 \(V\)

步骤 输入形状 输出形状 学习参数
Token 查表 \([B,T]\) \([B,T,D]\) 嵌入矩阵
加入位置 \([B,T,D]\) \([B,T,D]\) 取决于位置方案
Q/K/V 投影 \([B,T,D]\) 三组 \([B,H,T,D_h]\) \(W^Q,W^K,W^V\)
因果注意力 Q/K/V \([B,H,T,D_h]\) 无新增参数
合并头与投影 \([B,H,T,D_h]\) \([B,T,D]\) \(W^O\)
残差与归一化 两组 \([B,T,D]\) \([B,T,D]\) 归一化缩放与偏置
前馈网络 \([B,T,D]\) \([B,T,D]\) 两层权重与偏置
输出到词表 \([B,T,D]\) \([B,T,V]\) 输出矩阵
交叉熵 logits 与目标 \([B,T]\) 标量 无新增参数

遇到一个新模型时,先问清这张表中的每一项,通常比先记住模型商品名更有用:它怎样切 Token?如何表示位置?使用什么掩码?注意力头如何分组?FFN 多宽?归一化放在哪里?训练目标是什么?这些选择共同决定模型的能力与成本。

Transformer 没有解决什么

Transformer 解决了序列建模中的一组结构和优化问题,不等于自动解决智能的全部问题。

它没有保证事实正确。下一个 Token 概率来自训练分布与当前上下文,不是一个内置事实数据库的查询结果。它没有保证长程任务可靠。生成步骤越多,局部错误、工具失败和错误假设越可能累积。它也没有消除数据问题:偏差、重复、低质量内容和版权来源会通过训练过程影响模型。

更重要的是,架构本身不等于最终系统。现代助手还会叠加大规模预训练、指令微调、偏好优化、检索、工具调用、安全策略和推理时搜索。后续章节会逐层加入这些部分。

实践路径:P08 训练迷你 Transformer

阅读公式能够理解各部分关系,亲手跟踪张量则能发现理解中的空白。P08 使用项目自带的短篇中文语料,训练一个字符级、仅解码器的迷你 Transformer。它有意保持很小,不追求流畅的通用语言能力。

实践将验证四件事:

  1. 输入与目标为何错开一个 Token;
  2. 因果掩码怎样阻止未来信息泄漏;
  3. \([B,T,D]\) 如何拆成 \([B,H,T,D_h]\) 再合并;
  4. 损失下降与生成改善为何不能证明模型获得了通用理解。

完整步骤见实践 P08。普通读者可以跳过实践,直接进入下一章;后文不会默认你已经运行代码。

本章小结

  • Tokenizer 把文本变成离散编号,Embedding 再把编号变成可训练向量。
  • 位置信息补上自注意力本身无法区分的顺序。
  • Query 与 Key 决定匹配权重,Value 决定被汇总的内容;缩放和掩码保证数值与信息流符合任务要求。
  • 多头注意力在不同投影空间中并行匹配,FFN 则逐位置加工特征;残差和归一化支撑深层训练。
  • 自回归模型训练时可并行计算多个位置,生成时仍必须逐 Token 推进,KV Cache 用空间换速度。
  • 注意力矩阵随序列长度平方增长;工程优化能显著减少实际开销,但长上下文仍有计算与有效利用问题。
  • Transformer 是现代大模型的核心结构,不是完整助手的全部。预训练、对齐、检索和工具会在后续章节加入。

思考问题

  1. 如果删除位置编码,又不给注意力加入任何相对位置信息,模型会难以区分哪些句子?
  2. 因果掩码允许训练并行,却不允许生成并行,这两件事为什么不矛盾?
  3. 把上下文长度扩大两倍时,标准注意力分数矩阵的元素数量变成多少倍?
  4. 为什么看到某个注意力头对一个词给出最高权重,仍不足以证明这个词决定了最终输出?

延伸阅读

  • 原始 Transformer 论文适合对照编码器、解码器、多头注意力和位置编码的最初组合。(Vaswani 等 2017年)
  • Layer Normalization 与残差网络论文分别解释深层训练中两个基础部件的来源。(Ba 等 2016年; He 等 2016年)
  • FlashAttention 论文适合进一步理解:同一个数学算法,在硬件内存层级上的实现方式为何会显著改变速度。(Dao 等 2022年)

参考文献

Ba, Jimmy Lei, Jamie Ryan Kiros, 和 Geoffrey E. Hinton. 2016年. 《Layer Normalization》. arXiv preprint arXiv:1607.06450, 网络首发. https://doi.org/10.48550/arXiv.1607.06450.
Dao, Tri, Daniel Y. Fu, Stefano Ermon, Atri Rudra, 和 Christopher Ré. 2022年. 《FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness》. Advances in Neural Information Processing Systems 35, 16344~59. https://papers.nips.cc/paper_files/paper/2022/hash/67d57c32e20fd0a7a302cb81d36e40d5-Abstract-Conference.html.
He, Kaiming, Xiangyu Zhang, Shaoqing Ren, 和 Jian Sun. 2016年. 《Deep Residual Learning for Image Recognition》. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, 770~78. https://doi.org/10.1109/CVPR.2016.90.
Sennrich, Rico, Barry Haddow, 和 Alexandra Birch. 2016年. 《Neural Machine Translation of Rare Words with Subword Units》. Proceedings of the 54th Annual Meeting of the Association for Computational Linguistics, 1715~25. https://doi.org/10.18653/v1/P16-1162.
Vaswani, Ashish, Noam Shazeer, Niki Parmar, 等. 2017年. 《Attention Is All You Need》. Advances in Neural Information Processing Systems 30, 5998~6008. https://papers.nips.cc/paper/7181-attention-is-all-you-need.