第 5 章:为什么需要 Transformer

开篇问题

语言不是孤立 Token 的集合,而是一串有顺序、有依赖、有上下文的序列。

当你读到这句话:

小王把钥匙放进抽屉,因为它太小了。

“它”指什么?可能是钥匙,也可能是抽屉,取决于上下文和常识。模型要预测后续内容,不能只看最近一个词,而要在整段文本中建立关系。

这一章要回答的问题是:既然神经网络可以学习,为什么还需要 Transformer 这种专门结构?它到底解决了序列建模里的哪些痛点?

本章你会理解什么

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

  • 序列建模为什么比普通输入输出映射更难。
  • 早期循环结构为什么在长距离依赖和并行训练上遇到瓶颈。
  • Transformer 的核心突破不是“更深”,而是用 Attention 直接建模 Token 之间的关系。
  • 为什么大语言模型几乎都以 Transformer 或其变体为基础。

核心概念

序列建模关注“位置”和“关系”

同样的 Token,顺序不同,含义可能完全不同:

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

语言模型需要同时理解两件事:

  • 位置:每个 Token 出现在第几个位置。
  • 关系:每个 Token 应该参考哪些其他 Token。

普通神经网络如果只接收一个固定向量,很难自然表达这种结构。序列模型的任务,就是让模型在处理一串 Token 时保留顺序信息,并捕捉远近不同的依赖。

长距离依赖是语言理解的难点

很多关键关系并不发生在相邻 Token 之间:

那个昨天在会议上提出缓存一致性问题的后端工程师,今天终于提交了修复。

“提交了修复”的主体是“后端工程师”,中间隔了很长一段修饰语。模型如果只关注局部窗口,就容易丢失主干结构。

代码里也一样:

function createClient(config) {
  // many lines
  return new Client(config);
}

return 处的 config 需要和函数参数建立联系。真实代码文件中,这种依赖可能跨越几十行甚至几百行。

Transformer 的目标是让 Token 彼此“看见”

Transformer 的关键思想是:处理某个 Token 时,不只按顺序接收前一个状态,而是让它直接查看上下文里的其他 Token,并计算哪些更重要。

这种机制就是 Attention。它让模型能回答类似问题:

当前位置要理解自己,应该重点参考哪些位置?

例如处理“它”时,模型可以把注意力分配给“钥匙”“抽屉”“太小”等位置,而不是只依赖最近的词。

机制拆解

传统循环模型:按时间一步步读

在 Transformer 之前,处理序列常见的方式是循环神经网络,也就是 RNN 一类结构。它的基本思路很自然:

读第 1 个 Token,更新状态
读第 2 个 Token,更新状态
读第 3 个 Token,更新状态
...

状态像一个滚动变量,试图记住前面读过的信息。

这个设计很像逐行读取日志:

let state = init();

for (const token of tokens) {
  state = update(state, token);
}

它的问题也来自这里:后面的计算依赖前面的状态,难以大规模并行;越早的信息要经过越多次状态传递,越容易被冲淡。

长距离信息会被压缩在一个状态里

如果一句话有 100 个 Token,RNN 在第 100 个位置要使用第 3 个位置的信息时,这个信息已经被连续更新了很多次。模型必须把所有历史压在一个不断变化的状态里。

这像把一个长需求文档压缩成一个变量 summary,然后每读一段就覆盖一次:

summary = update(summary, paragraph);

如果后面某个决策需要第一段里的一个细节,模型必须保证这个细节没有在更新中丢失。长序列越长,这件事越困难。

Transformer:每个位置直接访问其他位置

Transformer 换了一种方式。它不要求信息必须沿着时间一步步传递,而是在每一层里让每个 Token 与其他 Token 建立连接。

可以把一层 Transformer 粗略看成:

每个 Token 生成一个当前表示
每个 Token 查看上下文中其他 Token
根据相关性聚合信息
再经过前馈网络做变换

这带来两个重要结果:

  • 长距离依赖不必经过很多步传递,可以通过 Attention 直接连接。
  • 同一层里多个位置的计算可以并行,更适合 GPU。

位置编码:没有循环顺序,也要知道先后

Attention 本身主要关心 Token 之间的匹配关系。如果没有额外信息,它并不天然知道“谁在前谁在后”。

所以 Transformer 需要位置编码,把位置信息加入 Token 表示中:

Token 向量 + 位置向量 = 带位置感的输入表示

这样模型既知道某个 Token 是什么,也知道它大概出现在序列中的哪里。

不同 Transformer 变体会使用不同的位置编码方式,但核心目的相同:让模型理解顺序。

堆叠层:从浅层关系到深层表示

一层 Attention 只能做一次上下文聚合。Transformer 会堆叠很多层,让 Token 表示反复更新。

第一层可能更关注局部搭配,后面的层可能组合出更抽象的关系。不要把这理解成固定分工,因为模型内部没有人工规定“第几层负责语法”。更稳妥的理解是:多层堆叠给了模型多次重写表示的机会。

原始 Token 表示
-> 第 1 层:根据上下文更新一次
-> 第 2 层:基于更新后的表示再看上下文
-> 第 N 层:形成更适合预测的表示

为什么 Transformer 适合大规模训练

大模型训练不仅需要效果,还需要可扩展性。Transformer 适合扩展,主要因为:

  • 序列内许多位置可以并行计算。
  • Attention 让长距离依赖更容易被捕捉。
  • 模型结构规整,主要由矩阵运算组成,适合 GPU/TPU。
  • 堆叠更多层、增加隐藏维度和训练数据后,能力可以持续提升。

这并不代表 Transformer 完美。Attention 的计算量会随序列长度增长得很快,长上下文会带来显存和计算压力。但在效果与可扩展性之间,它取得了非常强的平衡。

开发者常见误解

误解一:Transformer 只是更大的神经网络

规模很重要,但 Transformer 的关键不是单纯变大,而是引入了适合序列关系建模的结构。没有 Attention,模型即使很大,也很难以同样方式高效处理长距离依赖。

误解二:有了 Transformer,模型就能无限理解上下文

Transformer 能更好地建模上下文,但上下文窗口仍然有限,Attention 计算也有成本。即使上下文很长,模型也不保证能稳定使用每个细节。

“能放进去”和“能可靠用上”是两件事。

误解三:位置编码只是一个小细节

位置编码看起来像输入预处理,但它解决的是序列建模的根本问题:顺序。没有位置信息,模型很难区分“用户删除文件”和“文件删除用户”。

误解四:Attention 等于解释模型思考过程

Attention 权重能显示模型在某一层某一头里关注了哪些位置,但它不是完整的可解释性报告。模型的最终行为来自多层、多头、前馈网络和参数共同作用,不能简单说“注意力高就代表模型就是这么推理的”。

小实验/思考实验

实验一:只看最近 3 个词会发生什么

尝试阅读下面句子,但每次只允许自己看当前位置前面的 3 个词:

那个负责支付系统重构并修复了多次线上事故的工程师,决定把服务拆成更小的模块。

读到“决定”时,如果只能看最近几个词,你很难立刻知道是谁决定。真实语言里,很多依赖都跨越局部窗口。

Transformer 的 Attention 让当前位置可以直接参考更远处的信息。

实验二:比较串行日志读取和全局索引

想象你要在一份 200 行日志里找某个请求 ID 的上下文。

一种方式是从第 1 行读到第 200 行,并努力在脑中维护状态。另一种方式是先建立一个索引,让每一行都能直接查到相关行。

RNN 更像第一种方式,Transformer 更像第二种方式。这个类比不完全等价,但能帮助你理解为什么直接建立位置间关系很重要。

本章小结

Transformer 出现的背景,是序列建模既需要理解顺序,又需要捕捉远距离关系。早期循环结构按顺序传递状态,直观但难以并行,也容易在长序列中丢失早期信息。

Transformer 用 Attention 让每个 Token 可以直接参考上下文中的其他 Token,再通过位置编码保留顺序信息,通过多层堆叠不断更新表示。它既改善了长距离依赖建模,也非常适合大规模矩阵计算,因此成为现代大语言模型的核心架构。

自测题

  1. 序列建模为什么不能只把 Token 当成无序集合?
  2. RNN 类结构在长距离依赖上为什么容易遇到困难?
  3. Transformer 为什么更适合并行训练?
  4. Attention 在 Transformer 中解决了什么核心问题?
  5. 为什么位置编码对 Transformer 很重要?