第 7 章:Transformer 内部到底怎样流动信息

开篇问题

上一章我们拆开了 Attention。但一个完整的 Transformer 不只有 Attention。

当一串 Token 进入模型后,它们会经历 Embedding、位置编码、多层 Transformer Block、归一化、输出层等步骤。每一步都在改变 Token 的表示,让它更适合最终预测下一个 Token。

这一章的目标是把前面的概念串起来:从输入 Token 到输出概率,Transformer 内部的信息到底怎样流动?

本章你会理解什么

读完本章,你应该能理解:

  • Transformer 的输入如何从 Token ID 变成向量序列。
  • 一个 Transformer Block 通常包含哪些部分。
  • Attention 和前馈网络分别负责什么类型的变换。
  • 残差连接和归一化为什么对深层模型重要。
  • 语言模型如何把最后的隐藏表示变成下一个 Token 的概率。

核心概念

Transformer 处理的是一整段向量序列

分词器会先把文本切成 Token,再把 Token 映射成 ID:

"大模型很强"
-> ["大", "模型", "很", "强"]
-> [1024, 3812, 91, 778]

但 Transformer 不直接处理整数 ID。它会通过 Embedding 表把每个 ID 查成向量:

1024 -> [0.12, -0.08, ...]
3812 -> [0.31, 0.44, ...]

于是模型真正看到的是一个向量序列:

[x1, x2, x3, x4, ...]

每个位置都有一个向量,每个向量会在层与层之间不断被更新。

Transformer Block 是可重复堆叠的处理单元

现代语言模型通常由很多个 Transformer Block 堆叠而成。一个简化的 Block 可以理解为:

输入表示
-> Self-Attention
-> 残差连接与归一化
-> 前馈网络
-> 残差连接与归一化
-> 输出表示

不同模型会在归一化顺序、激活函数、位置编码等细节上有差异,但核心思想相近:Attention 负责跨位置聚合信息,前馈网络负责对每个位置的表示做进一步变换。

每一层都在重写 Token 的上下文表示

进入模型时,“苹果”这个 Token 的向量主要表示它自身。经过多层 Transformer 后,它的表示会逐渐融合上下文。

在不同句子中,同一个 Token 的最终表示可能很不同:

我买了一个苹果。
苹果发布了新的芯片。

同样是“苹果”,上下文不同,模型内部表示也会不同。Transformer 的层层计算,就是在把静态 Token 表示变成动态上下文表示。

机制拆解

第一步:Token ID 进入 Embedding 层

Embedding 层可以看成一个巨大的查表结构:

embedding[tokenId] -> vector

如果词表有 100000 个 Token,隐藏维度是 4096,那么 Embedding 表就是一个 100000 x 4096 的矩阵。每个 Token ID 对应其中一行。

这些向量不是人工设计的,而是在训练中一起学习。训练会让常见搭配、相似用法、结构角色等信息逐渐写入向量空间。

第二步:加入位置信息

只知道 Token 是什么还不够,还要知道它在哪里。

用户 删除 文件
文件 删除 用户

这两句话包含相同 Token,但顺序不同,含义不同。Transformer 会把位置信息加入表示中,让模型区分顺序。

简化理解:

输入表示 = Token Embedding + Position Information

有些模型使用绝对位置编码,有些使用相对位置编码或旋转位置编码。实现细节不同,但目的都是把顺序关系注入模型。

第三步:Self-Attention 做跨位置通信

进入 Transformer Block 后,Self-Attention 会让每个位置根据上下文更新自己。

例如句子:

这个函数虽然名字叫 parse,但它实际上会发起网络请求。

处理“它”时,Attention 可以从“这个函数”取回信息。处理“网络请求”时,Attention 可能会参考“实际上”和“发起”。每个位置都可以从其他位置读取对自己有用的信息。

Self-Attention 的输出仍然是一串向量,长度不变:

[x1, x2, x3]
-> Attention
-> [a1, a2, a3]

变化的是每个位置的向量内容:它们已经融合了上下文。

第四步:残差连接保留原始通路

深层神经网络训练困难的一个原因是:如果每层都完全重写表示,早期信息和梯度都可能在层层变换中变弱。

残差连接的做法是把输入直接加到输出上:

newX = x + attention(x)

它像给信息保留了一条直达通道。即使某一层学到的变换暂时不理想,模型也不必完全丢掉原来的表示。

对开发者来说,可以把残差理解成“在原对象基础上打补丁”,而不是每次都从零构造一个新对象:

next = {
  ...previous,
  ...learnedUpdate,
};

数学上不是对象合并,但这个类比能帮助你理解为什么残差连接让深层堆叠更稳定。

第五步:归一化让数值更稳定

LayerNorm 等归一化操作会调整向量的数值分布,让训练更稳定。

在深层模型中,每一层都会改变表示。如果数值尺度不断变大或变小,后续层会越来越难训练。归一化像是在层与层之间做一次校准,让表示保持在更可控的范围里。

你不需要把归一化理解成业务语义操作。它主要是优化层面的稳定器。

第六步:前馈网络做逐位置变换

Attention 解决的是“不同位置之间如何交换信息”。前馈网络处理的是“每个位置拿到上下文信息后,如何进一步加工”。

前馈网络通常对每个位置独立应用同一套小网络:

x1 -> FFN -> y1
x2 -> FFN -> y2
x3 -> FFN -> y3

它不会直接让位置之间通信,因为通信已经由 Attention 完成。它更像是对每个位置的上下文表示做非线性变换,提炼出更适合下一层使用的特征。

一个常见结构是:

线性变换 -> 激活函数 -> 线性变换

激活函数提供非线性能力,否则多层线性变换叠在一起仍然只是线性变换,表达能力会受限。

第七步:多层堆叠形成深层上下文表示

一个 Block 只更新一次表示。大模型会堆叠很多层:

Embedding
-> Block 1
-> Block 2
-> Block 3
-> ...
-> Block N

每经过一层,每个 Token 的表示都会基于新的上下文再加工一次。较浅层可能更接近局部形式和短距离关系,较深层可能组合出更抽象的模式。这里仍然要谨慎:层的功能不是人工硬编码的,不能机械地说某一层只负责某一种能力。

第八步:输出层给出下一个 Token 概率

经过最后一层后,每个位置都有一个最终隐藏向量。对自回归语言模型来说,模型会用当前位置的隐藏向量预测下一个 Token。

简化流程:

最后隐藏向量
-> 线性映射到词表大小
-> softmax
-> 每个 Token 的概率

如果词表有 100000 个 Token,输出层就会给出 100000 个分数。softmax 把这些分数转成概率分布。

生成时,系统再根据这个概率分布选择下一个 Token。选择方式可以是贪心、采样、top-k、top-p 等。那些属于生成策略,不是本章重点。这里你只需要知道:Transformer 输出的是概率分布,不是直接吐出字符串。

一次完整前向传播

把所有步骤串起来,一次前向传播可以这样理解:

文本
-> 分词得到 Token ID
-> Embedding 查表得到 Token 向量
-> 加入位置信息
-> 进入第 1 个 Transformer Block
   -> Self-Attention 聚合上下文
   -> 残差连接与归一化
   -> 前馈网络加工表示
   -> 残差连接与归一化
-> 进入后续多个 Block
-> 得到最终隐藏表示
-> 映射到词表分数
-> softmax 得到下一个 Token 概率

训练时,这个流程后面还会接 loss 计算和反向传播。推理时,模型会根据概率选出下一个 Token,把它追加到上下文中,再重复这个流程。

开发者常见误解

误解一:Embedding 就是词典释义

Embedding 不是自然语言词典,也不是人工标签。它是训练出来的向量表示。一个 Token 的向量没有单独可读的解释,意义来自它在模型计算中的作用。

误解二:Attention 负责全部计算

Attention 很关键,但 Transformer Block 还包含前馈网络、残差连接、归一化等组件。前馈网络提供大量参数和非线性变换能力,对模型表达能力非常重要。

误解三:每一层都有清晰的人类语义职责

我们可以观察到某些层、某些头呈现出特定模式,但这不是严格模块划分。Transformer 内部是分布式表示,不像传统软件那样有明确命名的业务模块。

误解四:模型一次生成整段回答

自回归语言模型通常是一个 Token 一个 Token 地生成。每一步根据当前上下文预测下一个 Token,再把新 Token 加回上下文。长回答是多次预测累积出来的结果。

误解五:上下文放进模型后一定被完整使用

Transformer 允许 Token 之间建立联系,但不保证每个细节都会被稳定利用。上下文长度、位置、提示方式、模型能力和注意力分配都会影响最终效果。

小实验/思考实验

实验一:跟踪一个 Token 的表示变化

选择句子:

JavaScript 的闭包让函数可以记住创建时的作用域。

想象“闭包”这个 Token 在不同阶段的表示:

Embedding 阶段:主要是“闭包”这个 Token 的通用表示。
加入位置后:知道它出现在句子前部。
经过 Attention 后:吸收“JavaScript”“函数”“作用域”等上下文。
经过多层后:形成更适合预测后续解释的表示。

这能帮助你理解:Transformer 中的 Token 向量不是静态词义,而是会随上下文不断变化。

实验二:为什么需要前馈网络

假设 Attention 已经把相关信息汇总到了当前位置:

当前位置表示 = 当前词 + 相关上下文

接下来模型还需要判断这些信息如何组合。比如“不是很好”和“很好”只差一个否定词,但含义相反。前馈网络提供逐位置的非线性加工能力,让模型能对已经汇总的信息做更复杂的变换。

实验三:逐 Token 生成

给定上下文:

Transformer 的核心机制是

模型可能先预测:

Attention

然后新上下文变成:

Transformer 的核心机制是 Attention

模型再预测下一个 Token。这个循环不断发生,直到生成结束标记或达到长度限制。

本章小结

Transformer 的内部流程可以理解为:先把 Token ID 变成向量,再加入位置信息,然后通过多层 Transformer Block 反复更新每个位置的上下文表示。每个 Block 中,Self-Attention 负责跨位置读取信息,前馈网络负责对每个位置做进一步非线性加工,残差连接和归一化帮助深层网络稳定训练。

最后,模型把隐藏表示映射到词表上的分数,并转换成下一个 Token 的概率分布。大语言模型的生成过程,就是这个预测过程一轮又一轮地展开。

自测题

  1. Token ID 为什么不能直接作为 Transformer 的输入?
  2. 位置编码解决了什么问题?
  3. 在 Transformer Block 中,Attention 和前馈网络分别负责什么?
  4. 残差连接为什么有助于训练深层模型?
  5. 语言模型最后为什么输出的是词表上的概率分布?
  6. 为什么说同一个 Token 在不同上下文中的表示会不同?