跳到主要内容

一层里的六步 — 6×768 进去,6×768 出来,所以能反复堆 12 次

这一章讲三件事: Transformer 的一层里到底发生了什么(只有六步); 三个看似边角、实则生死的设计(位置编码——给每个位置发「身份签名」的机制、前馈层、规范化的位置); 以及同一块积木怎么搭出三种模型,为什么其中一种通吃了今天。

它在全书链条里的位置: 第 09 章给了机制,这一章把它装进标准件。 读完这一章,「大模型」这三个字在你眼里就不再是一团雾, 而是「这一块,堆了几十次」。

1. 一层里到底发生了什么

上一章的注意力是核心,但单靠它还不够。 一个完整的 Transformer 层,书里叫积木,由四个部件组成1:

  1. 多头自注意力:上一章讲的,让任意两个位置直接对话;
  2. 前馈网络:每个位置独立地过一个两层的小网络,做「深加工」;
  3. 残差连接:第 06、08 章那个加号,让梯度畅通;
  4. 层规范化:第 08 章那个「沿一行求统计」,稳住数值。

四个部件按固定顺序串起来,就是一层; 这一层原样堆 N 次(典型取值 12、24、96 甚至更多), 就是一个完整的 Transformer2

书里给这个设计的评语是:它把「搭深层网络所需的关键技巧」 打包成了一个标准化模块——标准化带来巨大的工程优势: 同一个模块可以反复堆,方便调参、缩放、分布式训练(把一份训练拆给多台机器一起跑)3

2. 走查:6 个片段进入一层

这一章的主走查:拿第 09 章那半句话的前六个片段,送进一层。

六个片段:「那」「只」「猫」「没」「过」「马路」。 每个片段此刻是一串 768 个数(第 02 章说过,词会被变成一串数; 768 这个宽度取自一个真实的教学级配置,马上会讲)。 整层的输入是 6 × 768 的一张表;走完六步,出来还是 6 × 768—— 形状不变,这正是它能反复堆的原因。

输入(6×768)

① 层规范化 每行的 768 个数按回标准尺度
② 多头注意力 每个位置和所有位置对话(第 09 章那三步)
③ 加回去 输出 = 输入 + 注意力的结果 ← 残差
④ 层规范化 再按回标准尺度
⑤ 前馈网络 每个位置独立:768 → 3072 → 768
⑥ 加回去 输出 = 输入 + 前馈的结果 ← 残差

输出(6×768) ← 形状不变,可以直接送进下一层

这张图看的是一层里的六步。注意两次「加回去」——这是这块积木的骨架。

逐步走查,旁边放上数:

  • 第①步,层规范化。六个片段各自独立, 每个片段那 768 个数被按回「不大不小」的范围(第 08 章的机制,这里不重复)。
  • 第②步,多头注意力——几组并行的注意力。「猫」和「马路」对上暗号, 「猫」的新表示里掺进了「马路」的一份;「过」里掺进了「猫」的一份。 参与的是 12 个头(每个头负责 768 ÷ 12 = 64 个数),各看各的,最后拼起来。
  • 第③步,第一次加回去:注意力的结果不替换原值,而是加到原值上。 于是「猫」= 原来的「猫」+ 注意力带来的修正。
  • 第④⑤步,再过一次规范化,然后每个位置独立过前馈网络: 768 个数先放大到 3072 个(4 倍),再压回 768。 这一步不看别的位置,只对每个位置自己这份信息做深加工。
  • 第⑥步,第二次加回去

走完,六个片段每个都还是 768 个数,但内容变了: 「猫」这串数里,现在既有它自己,也有从「马路」借来的上下文, 还有前馈层加工过的深层特征。这张 6 × 768 的表,可以直接原样送进下一层, 下一层再重复同样的六步。

补充(不在书里,依据我们的 frontier 书架): 这六步不是示意图,是代码的形状。 nanoGPT(一个教学级实现,默认 12 层、768 宽)的一层, 核心就是两句「x = x + …」,中间夹着规范化、注意力、规范化、前馈4; 前馈层第一步正好放大到 4 倍宽5; 12 和 768 这两个数直接写在配置里6你读过的所有「千亿参数的大模型」,一层的基本形状和这几行没有本质区别。

3. 残差把「加回去」做了两次

第 08 章讲过残差流是「公共白板」。在这块积木里,它具体到不能再具体: 一层 = 两句「加回去」

这个设计有一个容易被忽略的后果:任何一层都可以「少干点活」甚至「不干活」。 如果某一层的注意力和前馈都输出接近零的修正, 这一层就退化成原样照抄——信息顺着主干道流过去,什么也不损失。 这让 12 层、24 层、96 层的堆叠有了退路:堆多了不会更差, 因为多余的层可以学会「什么都不改」。

这也是第 08 章说的「每层只学小修正」在这块积木上的样子。

4. 打乱词序,结果不变

现在说这块积木的一个致命盲点,第 09 章埋过伏笔。

把六个片段随意打乱,注意力算出来的结果完全一样。 它看到的只是「六串数」,不知道谁在前谁在后7。 「我打他」和「他打我」,在它眼里是同一堆东西8

这不是小毛病:语言里顺序就是意义。 循环网络靠一步步读,天生带着顺序;注意力为了并行,把顺序弄丢了。 顺序必须被显式地补回去——下一节就是补法。

5. 位置编码:给每个位置一个签名

补法朴素:给每个位置配一个独特的「签名」,加到那串数上。

这样一来,「第 1 个位置的猫」和「第 3 个位置的猫」的两串数就不一样了, 注意力也就分得清谁在前谁在后9。 这个做法叫位置编码。原论文用一组正弦、余弦函数生成签名: 不同位置得到不同的波形组合,而且波形有界、有规律10

「猫」这串数 = 词本身的内容 + 第 3 号位置的签名
「猫」这串数 = 词本身的内容 + 第 17 号位置的签名
同一个词,换个位置,串数就不同 → 注意力能分清顺序了

这张图看的是补法:不改机制,只在输入上加一个签名。

6. 从正弦到旋转:一个边角设计改了四代

这一节的主角是旋转位置编码(把「第几个词」换算成一个转角,查询和键各自带着转角去比对)——它前后换了四代。

位置编码听着像边角料,实际是被改得最多的部分之一。 书里列了一部简史11:

代数做法留下的问题
正弦签名(2017)用波形函数算出来,不是学出来的信号固定,不随任务调整
可学习签名(BERT)每个位置配一个可训练的向量,让模型自己学不能外推:训练时见过多长,就只能处理多长
相对距离编码不编码「第几个」,直接编码「隔多远」实现更绕
旋转位置编码(把查询和键按位置各转一个角度)第 i 个位置转 i 格;今天大模型的主流

这张表看的是同一道题的四代答案:从「写死」到「学会」,从「绝对位置」到「相对距离」。

第四代的巧思值得一句展开:它不往输入上加东西, 而是在打分之前,把查询和键各自转一个角度—— 两个位置转过的角度差,正好等于它们的距离。 于是打分自然带上了「隔多远」,既简洁又能外推到更长的序列12补充(不在书里,依据我们的 frontier 书架): 这个「转一下」 在 Llama 的真实实现里就是两行:查询和键各自乘上余弦、加上旋转一半后乘正弦13

7. 前馈层:参数大头不在注意力里

这一节纠正一个几乎人人都会犯的想当然。

注意力是这块积木的招牌,所以多数人会猜参数的大头在注意力。 书里给的事实正好相反:Transformer 的大部分参数,在前馈网络里14

原因就在第 2 节那个「放大 4 倍再压回」: 768 进、3072 出、3072 进、768 回——两次变换各是一张 768 × 3072 的表, 光这一个前馈层就是几百万个数,比注意力那三个矩阵加起来还大。 典型配置就是前馈层宽到 4 倍15

参数在这,装的东西也在这。研究者用探针和「知识编辑」实验发现, 事实类知识(「法国的首都是巴黎」这类)的痕迹,常常能在前馈层里找到—— 有人把它比作这块积木的「记忆体」16。 书里的提醒也要带上:知识不是锁在一个抽屉里, 而是分布在整套回路中17

这也顺手解释了第 11 节那个设计的选址:要拆,就拆最胖的这块。

8. 规范化,放前面还是后面

第 2 节的六步里,规范化放在每个部件之前。这不是唯一的放法—— 原论文当年放在之后。差别在哪?

放在之后(后规范化)的版本,深层时训练不稳: 梯度分布会越来越不均衡,层数一多就训不动。 放在之前(前规范化),主干道从输入到输出一路畅通无阻, 训练稳得多,能训深得多的网络18

今天的大模型几乎清一色用前规范化19。 这是第 08 章那条主线的又一次应验:让主干道永远在线, 其余一切都挂到路边去。

9. 三种范式:同一块积木的三种搭法

到目前为止,我们说的都是「一层」。把许多层堆起来, 按「留哪一半、掩码怎么放」的不同,能搭出三种模型20:

范式代表作它看什么适合什么
仅编码器BERT整句,左右都看理解类:分类、问答、挑出人名地名
仅解码器GPT 系列只看自己和前文(第 09 章那块掩码)生成类:续写、对话、写代码
编码器-解码器原始论文、T5先整句读进来,再逐词往外写,中间用交叉注意力转换类:翻译、语音识别

这张表看的是一个精彩的事实:三种范式的底层积木完全一样, 差别只在掩码和接线21

BERT 的训练方式是「完形填空」:随机遮住句子里 15% 的词,让它猜—— 所以它必须把整句看完,左右都重要22。 仅解码器的训练方式是「猜下一个词」,所以必须戴上第 09 章那块因果掩码23

10. 为什么仅解码器赢了

三种范式,今天的大语言模型几乎清一色是第二种。为什么?

书里给了两个原因24:

  1. 生成任务更通用。 只要能猜下一个词,就能回答、写代码、翻译、写诗—— 几乎所有语言任务都可以改写成「接着往下写」;
  2. 用法更灵活。 同一个模型,换一段提示(打给模型的那几句指令)就换一个任务, 不用为每个任务专门再训一遍。

「会接龙就会做几乎所有任务」——这个判断在当时并不明显, 是 GPT 系列一路放大之后才被验证的。第 15 章会讲这条放大的路。

11. 混合专家:大,但不必全算

最后一项现代改造,解决「越大越贵」的魔咒。

普通积木里,参数量和计算量绑得很紧:多一倍参数,每个词元就要多算一倍。 混合专家的做法,是把最胖的那个部件——前馈层——拆成很多个「专家」, 每个词元进来时,一个叫路由器的小网络决定把它送到哪几个专家那里, 其余专家这一次完全不参与计算25

一个词元进来 → 路由器:「这个词送去专家 3 和专家 17」
专家 1 专家 2 [专家 3] … [专家 17] … 专家 64
(闲) (闲) 干活 干活 (闲)

这张图看的是「大而不必全算」:总参数可以很大,每次动用的只是一小部分。

效果:模型的总容量可以做到几千亿参数,但每个词元实际经过的计算, 只相当于几百亿参数26。书里点名的 DeepSeek-V3、Mixtral 等前沿模型都走这条路。 理解它只要记住一句:参数是图书馆的藏书,计算是这一次翻开的书—— 混合专家让藏书可以极多,而每次只翻几页。

12. 作者的判断与证据

有证据的部分。 六步的结构、前馈层 4 倍宽、前规范化更稳、 三种范式的差别,都有论文和广泛复现; nanoGPT 的 12 层 768 宽是公开代码里的真实配置; 旋转位置编码的两行实现也是真实代码。

要分开看的三处:

  1. 「前馈层是记忆体」。 这是探针和知识编辑实验的观察,书里自己也说 「知识不是锁在一个抽屉里」。当成倾向,别当成结构图。
  2. 「多余的层可以学会不干活」。 这是我们的讲法,帮助理解残差的退路; 真实深层网络里,很难证明某一层真的「什么都没干」。
  3. 「仅解码器赢了」。 赢在「通用语言任务的主流行列」, 但翻译、语音识别这类边界清晰的转换任务,编码器-解码器今天仍然是主力27

判断(我们的,不是书里的):这块积木最被低估的设计,是「形状进出相同」。 6×768 进、6×768 出——正因为一层不改变形状,它才能像乐高一样任意堆, 而「能任意堆」正是规模法则得以成立的前提:想更大?再堆十层。 如果错,会错在: 形状不变不是免费的——它要求所有部件都迁就同一个宽度, 也让「信息该以什么粒度流动」这件事没有了别的选择。 近年已经有研究在松动这条约束,只是我们书架上的真实配置还没跟上。

13. 边界与局限

  • 多头之后怎么拼,只给了一句话。 拼接后再过一次线性变换,书里没展开。
  • 路由器怎么训练、怎么防止所有词元都挤向同一个专家,书里没有讲。 这是混合专家今天的主要工程难题。
  • 「为什么 4 倍」没有解释。 4 倍宽是经验配置,书里给了事实没给推导。
  • 位置编码的「外推」只说了方向。 训练时没见过那么长,推理时硬拉更长, 会出现「中间丢失」(关注开头结尾、忽略中间)等问题28——第 11 章还会碰到。
  • 每种范式只给了代表和适合场景。 BERT 一系今天的位置、 编码器-解码器在翻译上的存量,书里没有给市场份额的数字。

14. 可带走的

  1. 一层只有六步:规范化、注意力、加回去、规范化、前馈、加回去。
  2. 形状进出相同(6×768 进,6×768 出),所以能原样堆十几次到几十次。
  3. 一层 = 两句「加回去」。 多余的层可以学会不干活,这是深堆的退路。
  4. 注意力天生没有顺序概念,位置必须显式补进去。 「我打他」和「他打我」只差在签名上。
  5. 位置编码改了四代:写死 → 学会 → 相对距离 → 转一个角度。 今天的真实实现里只有两行。
  6. 参数大头在前馈层,不在注意力。 要拆就拆最胖的——这就是混合专家的选址。
  7. 规范化放前面,主干道才一路畅通。 今天的大模型清一色这么放。
  8. 三种范式是同一块积木的三种搭法,差别只在掩码和接线。
  9. 仅解码器赢在通用:会接龙就会做几乎所有任务。
  10. 混合专家:藏书可以极多,每次只翻几页。 大,但不必全算。

15. 原文地图

主题原书章原文位置
积木的四个部件第5章 注意力:引爆大模型的引擎text/06-ch05.txt:207(搜「四个部分组成」)
六步顺序第5章 注意力:引爆大模型的引擎text/06-ch05.txt:219(搜「残差相加」)
堆 N 次第5章 注意力:引爆大模型的引擎text/06-ch05.txt:224(搜「典型取值 12、24、96」)
标准化的工程优势第5章 注意力:引爆大模型的引擎text/06-ch05.txt:247(搜「标准化带来」)
打乱词序第5章 注意力:引爆大模型的引擎text/06-ch05.txt:252(搜「随意打乱」) · :253(搜「我打他」)
位置编码第5章 注意力:引爆大模型的引擎text/06-ch05.txt:254(搜「独特的向量」)
位置编码简史第5章 注意力:引爆大模型的引擎text/06-ch05.txt:320(搜「正弦和余弦」) · :324(搜「可学习参数」) · :329(搜「相对位置编码」) · :332(搜「旋转位置编码」)
FFN 大部分参数第5章 注意力:引爆大模型的引擎text/06-ch05.txt:211(搜「大部分参数」)
FFN 宽 4 倍第5章 注意力:引爆大模型的引擎text/06-ch05.txt:502(搜「4 倍」)
FFN 像记忆体第5章 注意力:引爆大模型的引擎text/06-ch05.txt:504(搜「记忆体」)
前规范化第5章 注意力:引爆大模型的引擎text/06-ch05.txt:511(搜「前规范化」)
三种范式第5章 注意力:引爆大模型的引擎text/06-ch05.txt:283(搜「仅编码器」) · :293(搜「仅解码器」) · :306(搜「编码器-解码器」) · :311(搜「底层积木完全一样」)
BERT 填空第5章 注意力:引爆大模型的引擎text/06-ch05.txt:287(搜「15%」)
仅解码器为什么赢第5章 注意力:引爆大模型的引擎text/06-ch05.txt:301(搜「生成任务本身更通用」)
混合专家第5章 注意力:引爆大模型的引擎text/06-ch05.txt:396(搜「混合专家模型」) · :398(搜「路由器」)
中间丢失第5章 注意力:引爆大模型的引擎text/06-ch05.txt:515(搜「关注开头和结尾」)

Footnotes

  1. 出处:「第5章 注意力:引爆大模型的引擎」第 207 段(text/06-ch05.txt:207,搜「四个部分组成」)。

  2. 出处:「第5章 注意力:引爆大模型的引擎」第 224 段(text/06-ch05.txt:224,搜「典型取值 12、24、96」)。

  3. 出处:「第5章 注意力:引爆大模型的引擎」第 247 段(text/06-ch05.txt:247,搜「标准化带来」)。

  4. 补充(不在书里,依据我们的 frontier 书架):nanoGPT 的一层(Block)的前向就是 「x = x + attn(ln_1(x)); x = x + mlp(ln_2(x))」两句。 依据: shelf=ai-frontier-reference/nanogpt@src:model.py:104 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=Block.forward 第 104 行是 x = x + self.attn(self.ln_1(x))。 另一份: shelf=ai-frontier-reference/nanogpt@src:model.py:105 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=第 105 行是 x = x + self.mlp(self.ln_2(x))。

  5. 补充(不在书里,依据我们的 frontier 书架):前馈层第一步把 768 维放大到 4 倍。 依据: shelf=ai-frontier-reference/nanogpt@src:model.py:82 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=c_fc 是 nn.Linear(config.n_embd, 4 * config.n_embd)。

  6. 补充(不在书里,依据我们的 frontier 书架):默认配置 12 层、12 头、768 宽。 依据: shelf=ai-frontier-reference/nanogpt@src:model.py:112 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=n_layer: int = 12。 另一份: shelf=ai-frontier-reference/nanogpt@src:model.py:114 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=n_embd: int = 768。

  7. 出处:「第5章 注意力:引爆大模型的引擎」第 252 段(text/06-ch05.txt:252,搜「随意打乱」)。 原文:「把句子里的词随意打乱,自注意力的计算结果是完全一样的」。

  8. 出处:「第5章 注意力:引爆大模型的引擎」第 253 段(text/06-ch05.txt:253,搜「我打他」)。

  9. 出处:「第5章 注意力:引爆大模型的引擎」第 254 段(text/06-ch05.txt:254,搜「独特的向量」)。

  10. 出处:「第5章 注意力:引爆大模型的引擎」第 320 段(text/06-ch05.txt:320,搜「正弦和余弦」)。 原文列的好处:值域有界、周期组合让不同距离有独特差异、理论上能外推。

  11. 出处:「第5章 注意力:引爆大模型的引擎」第 320 段(text/06-ch05.txt:320,搜「正弦和余弦」)、 第 324 段(text/06-ch05.txt:324,搜「可学习参数」)、 第 329 段(text/06-ch05.txt:329,搜「相对位置编码」)、 第 332 段(text/06-ch05.txt:332,搜「旋转位置编码」)。 表里「留下的问题」一列是我们照书里的叙述压的。

  12. 出处:「第5章 注意力:引爆大模型的引擎」第 334 段(text/06-ch05.txt:334,搜「旋转变换」)。

  13. 补充(不在书里,依据我们的 frontier 书架):Llama 的旋转位置编码, 查询和键各自一行:乘 cos 加上 rotate_half 后乘 sin。 依据: shelf=ai-frontier-reference/transformers@src:src/transformers/models/llama/modeling_llama.py:158 @b6c0bfe04c823a7b2ca48f91b8b91b2a7741f309 事实=第 158 行是 q_embed = (q * cos) + (rotate_half(q) * sin),第 159 行对 k 同样处理。

  14. 出处:「第5章 注意力:引爆大模型的引擎」第 211 段(text/06-ch05.txt:211,搜「大部分参数」)。 原文:「有意思的是,Transformer 的大部分参数其实都在 FFN 里,不是在注意力里」。

  15. 出处:「第5章 注意力:引爆大模型的引擎」第 502 段(text/06-ch05.txt:502,搜「4 倍」)。

  16. 出处:「第5章 注意力:引爆大模型的引擎」第 504 段(text/06-ch05.txt:504,搜「记忆体」)。

  17. 出处:「第5章 注意力:引爆大模型的引擎」第 475 段(text/06-ch05.txt:475,搜「关系网」)。

  18. 出处:「第5章 注意力:引爆大模型的引擎」第 509 段(text/06-ch05.txt:509,搜「后规范化」) 与第 511 段(text/06-ch05.txt:511,搜「前规范化」)。

  19. 出处:「第5章 注意力:引爆大模型的引擎」第 512 段(text/06-ch05.txt:512,搜「都采用 Pre-LN」)。

  20. 出处:「第5章 注意力:引爆大模型的引擎」第 283 段(text/06-ch05.txt:283,搜「仅编码器」)、 第 293 段(text/06-ch05.txt:293,搜「仅解码器」)、 第 306 段(text/06-ch05.txt:306,搜「编码器-解码器」)。

  21. 出处:「第5章 注意力:引爆大模型的引擎」第 311 段(text/06-ch05.txt:311,搜「底层积木完全一样」)。

  22. 出处:「第5章 注意力:引爆大模型的引擎」第 287 段(text/06-ch05.txt:287,搜「15%」)。

  23. 出处:「第5章 注意力:引爆大模型的引擎」第 293 段(text/06-ch05.txt:293,搜「仅解码器」)。

  24. 出处:「第5章 注意力:引爆大模型的引擎」第 301 段(text/06-ch05.txt:301,搜「生成任务本身更通用」) 与第 305 段(text/06-ch05.txt:305,搜「提示词做不同任务」)。

  25. 出处:「第5章 注意力:引爆大模型的引擎」第 396 段(text/06-ch05.txt:396,搜「混合专家模型」) 与第 398 段(text/06-ch05.txt:398,搜「路由器」)。

  26. 出处:「第5章 注意力:引爆大模型的引擎」第 401 段(text/06-ch05.txt:401,搜「激活的参数只是」)。

  27. 出处:「第5章 注意力:引爆大模型的引擎」第 309 段(text/06-ch05.txt:309,搜「输入转输出」)。 原文:「今天它主要用在这类『输入转输出』边界清晰的任务上」, 并点名语音识别里的 Whisper 正是这种架构。

  28. 出处:「第5章 注意力:引爆大模型的引擎」第 515 段(text/06-ch05.txt:515,搜「关注开头和结尾」)。