技术笔记

Transformer 技术笔记

以 Gemma 2 27B 为解剖对象,从 KV cache 一路推到信息论。章节有编号,可直接引用;把光标移到标题上点 § 可复制章节号。

以 Gemma 2 27B 为解剖对象,从 KV cache 一路推到信息论、对齐和评测。

作者:Weigang He 最后更新:2026-10-22

适合谁:已经知道 Transformer 大致结构、想把每个数字都算清楚的读者。需要线性代数和概率基础,不熟的地方第 11 章有速查。

为什么是 Gemma 2:它是结构清晰、公开资料齐全的稠密模型,每个参数都能对上论文和 config.json。更新的架构选择(MoE、MLA、其他位置编码)在 0.5 和对应章节里对照。

怎么写成的:本文由作者与 Claude(Anthropic)多轮对话整理而成。具体数字和论文结论逐条对照原始论文、官方配置或数值实验核实,不确定的地方标"待核实",发现过的错误记在附录 A。欢迎指错。

阅读路线:零基础先读 1 → 2.1–2.3 → 3.1 → 5.1–5.3 → 6.1;关心推理部署读 9 → 2.5 → 2.11 → 9.9;关心训练与对齐读 10 → 12。章节有编号,可以直接按"4.7 节"引用。


0速查表:Gemma 2 27B 全部关键数字

0.1架构参数

项目 值 备注 出处
d_model 4608 HF 里叫 hidden_size 1.1
层数 46
Query heads 32 2.5
KV heads 16 GQA,算 KV cache 用这个 2.5
head_dim 128 不等于 4608/32 = 144 2.1
注意力内部宽度 4096 = 32 × 128 2.2
FFN 中间宽度 36864 论文报 73728(= 2×,含 gate 和 up) 3.1
词表 256000 公开权重的实际行数;论文报 256128 1.2
全局注意力跨度 8192 也是训练长度 2.9
滑动窗口 4096 局部层用,与全局层交替 9.1
位置编码 RoPE,rope_theta = 10000 最慢一对维度波长 5.4 万 token 2.8
Tied embedding 是 入口出口共用一张表 1.4
激活函数 GeGLU 3.1
Norm RMSNorm,每层 4 个 pre + post 都有 4.1

0.2参数拆解

组件 参数量 占比
FFN(46 × 509.6M) 23.44 B 86.1%
Attention(46 × 56.6M) 2.60 B 9.6%
Embedding(256000 × 4608) 1.18 B 4.3%
RMSNorm(185 × 4608) 0.85 M 0.003%
合计 27.23 B

官方口径:non-embedding = 26,047,480,320,embedding = 1,180,237,824。

单层明细:

矩阵 形状 宽度来源 参数量
W_Q 4608 × 4096 32 heads × 128 18.9 M
W_K 4608 × 2048 16 KV heads × 128 9.4 M
W_V 4608 × 2048 16 KV heads × 128 9.4 M
W_O 4096 × 4608 投影回 d_model 18.9 M
W_gate / W_up / W_down 4608 × 36864 各一 d_ffn,见 3.1 509.6 M
单层合计 566.2 M

K/V 只有 Q 的一半宽,因为 32 个 Q 头共用 16 组 KV——原因见 2.5。

0.3推理开销(A100 80GB,bf16)

项目 值 出处
权重显存 54.5 GB 9.1
KV cache / token 368 KiB 9.1
FLOPs / token 54.5 GFLOPs 9.3
读权重耗时 27.2 ms 9.4
算 1 token 耗时 0.17 ms 9.4
算力利用率 0.6% 9.4
剩余显存可放 ~6.8 万 token 9.1
满 8192 上下文单条 3.09 GB 9.1

0.4概念地图:五个词分别在哪一层

Attention / Transformer / encoder / decoder / autoregressive 不在同一个轴上,不是互相替代的选项。混淆几乎都源于把它们当成同一层的概念。

概念 属于哪一类 同轴上的替代品
Attention 计算机制(怎么混合信息) 卷积、循环、池化
Transformer 网络架构(用哪些积木搭) LSTM、CNN、Mamba
Encoder / Decoder 结构角色(在信息流里干什么) —
Autoregressive 生成方式 / 训练目标 掩码语言建模、扩散

层层搭建的关系:

Attention(机制)
   ↓ 配上 FFN、残差、归一化、位置编码
Transformer 层(架构)
   ↓ 按 mask 方式 + 有无 cross-attention 分工
Encoder 栈 / Decoder 栈(角色)
   ↓ 配上训练目标
自回归 LM / 掩码 LM / 序列到序列

每一层的选择都独立于其他层,所以能自由组合:

组合 例子
Attention 但不是 Transformer Bahdanau 2014——attention 挂在 RNN 上
自回归但不是 Transformer n-gram、RNN 语言模型、WaveNet
Transformer 但不自回归 BERT
Encoder 但不是 Transformer BiLSTM 编码器

历史顺序最能说明问题

年份 出现的东西
2003 神经自回归语言模型(Bengio)
2014 Encoder-decoder / seq2seq(Sutskever, Cho)
2014 Attention(Bahdanau,加在 RNN seq2seq 上)
2017 Transformer(Vaswani)

Attention 比 Transformer 早三年。 论文标题《Attention Is All You Need》的字面意思就是:seq2seq 里本来 RNN 和 attention 并存,这篇说把 RNN 扔掉、只留 attention 就够了。

所以 attention 是零件,Transformer 是整机——而且按 3.5,attention 只占 Gemma 2 参数的 9.6%,FFN 占 86%。

Encoder vs Decoder:真正的区别只有 mask

这是最大的误解点。Encoder 层和 decoder-only 层结构完全相同,唯一差别是注意力 mask(见 2.3):

双向(Encoder)            因果(Decoder)
    k₁ k₂ k₃ k₄               k₁ k₂ k₃ k₄
q₁  ■  ■  ■  ■            q₁  ■  ·  ·  ·
q₂  ■  ■  ■  ■            q₂  ■  ■  ·  ·
q₃  ■  ■  ■  ■            q₃  ■  ■  ■  ·
q₄  ■  ■  ■  ■            q₄  ■  ■  ■  ■

只有 seq2seq 里的 decoder 多一样东西:cross-attention(见 2.7)。

三大家族

Encoder-only Decoder-only Encoder-Decoder
代表 BERT GPT / Llama / Gemma T5、原始 Transformer、Whisper
self-attn mask 双向 因果 编码器双向,解码器因果
cross-attention 无 无 有
主要训练目标 掩码语言建模 自回归 自回归(仅解码器侧)
典型用途 理解、分类、检索 生成 翻译、语音转文本
KV cache 用不上 必需 解码器侧需要
输入输出词表 同一套 同一套 可以不同(见 1.5)

⚠️ "Decoder-only" 是个坏名字。 严格说 GPT 既没有 encoder 可对,也没有 cross-attention——它根本不"解码"任何东西。它真正继承自 seq2seq decoder 的只有因果 mask 这一件事。更准确的叫法是 causal LM。这个名字是历史包袱,但已经定型了。

Autoregressive 是第四个轴

定义纯粹是概率分解——概率论的链式法则,对任何联合分布都精确成立,跟是不是语言、是不是用神经网络无关:

$$p(x_1 \dots x_n) = \prod_{t} p(x_t \mid x_{<t})$$

符号 含义
$x_1,\dots,x_n$ 长度 $n$ 的 token 序列
$p(x_1\dots x_n)$ 整句话的联合概率
$x_{<t}$ 第 $t$ 个之前的所有 token,即 $x_1,\dots,x_{t-1}$
$p(x_t\mid x_{<t})$ 给定前文,下一个词是 $x_t$ 的条件概率

展开成 $n=3$ 更直观:

$$p(x_1,x_2,x_3) = p(x_1)\cdot p(x_2\mid x_1)\cdot p(x_3\mid x_1,x_2)$$

为什么这样拆不是简化,而是恒等式:先猜第一个词,再在"第一个已知"的条件下猜第二个,再在"前两个都已知"的条件下猜第三个……逐步的条件概率乘起来,就等于一次性猜中整句话的概率。跟"抽牌不放回"是同一个道理——第二张牌的概率要在"第一张已经抽走"的条件下算。

训练时让 $p_\theta(x_t\mid x_{<t})$(神经网络参数化)逼近真实分布,两边取 log、连乘变连加、取负号,就是 6.4 的 CE loss——同一公式的对数似然版本见 11.3。

它和因果 mask 的关系是:因果 mask 使自回归训练能并行——一次前向就能算出所有位置的 loss(teacher forcing),不用跑 n 遍。但两者不等价:

Gemma 2 27B 对号入座

维度 取值
机制 Self-attention(GQA 变体,见 2.5)
位置编码 RoPE(见 2.8)
架构 Transformer
角色 Decoder-only(无 cross-attention)
Mask 因果 + 局部层加 4096 滑动窗口
训练目标 自回归

为什么现在几乎全是 decoder-only

  1. 架构简单——一个栈,没有 cross-attention,没有两套词表,扩展和并行都好做
  2. 任务统一——翻译、问答、摘要都能写成"文本续写"
  3. 实证扩展性更好——同等算力下 scaling 表现更强

encoder-decoder 的优势(对输入做双向编码)大部分能靠"把输入放进 prompt"找回来,代价是输入只能被因果地看一遍。剩下还在用 encoder-decoder 的,主要是输入模态和输出模态本质不同的场景。

0.5Gemma 2 之外:同一位置上的其他选择

Gemma 2 是一个"标准"的稠密 decoder-only 模型。别的模型在下面几个位置上做了不同选择,每一行都是同一个零件的替代品,可以和其他行自由组合:

位置 Gemma 2 27B 的选择 其他选择 改了什么 出处
位置编码 RoPE,base 10000 大 base / PI / YaRN;ALiBi;NoPE;RoPE 与 NoPE 按层混用 能外推多长 2.8–2.10
K/V 怎么省 GQA-16 MHA、MQA、MLA KV cache 大小 2.5、2.11
FFN 一个稠密 GeGLU MoE(N 个专家选 k 个) 参数量 vs 每 token 计算量 3.6–3.7
微调方式 (发布的是全量训练的权重) 全量微调、LoRA、QLoRA 训练显存、能学多少新东西 10.9
部署精度 bf16 int8 / int4(GPTQ、AWQ、SmoothQuant) 每步读多少字节 9.9–9.10

前三行是架构层,建模时写进 config,换了就要重训(或付出微调代价"补票");"微调方式"是训练层,在训好的底座上做,不改结构(LoRA 合并后形状不变);最后一行是部署层,训好之后随时可换。这个分层见 2.5 那张表。

DeepSeek-V3 是这几行全换掉的例子:MLA + MoE(256 选 8 + 1 共享)+ YaRN 扩到 128K,671B 总参数、每 token 激活 37B,每 token KV cache 只有 68.6 KiB(Gemma 2 27B 是 368 KiB)。


第一部分:模型骨架

1基础概念

1.1d_model:贯穿始终的宽度

定义:描述一个 token 需要多少个数字。Gemma 2 27B 是 4608。

猫  →  [ 0.31 | -1.24 | 0.08 | 2.06 | ... | -0.55 | 1.37 ]
        └────────── 4608 个数 ──────────┘

关键性质:全程不变。

输入 [4608] → 第1层 → [4608] → ... → 第46层 → [4608] → 输出

层内部可以任意变宽变窄(FFN 撑到 36864 再压回来),但层间接口永远是 4608。原因是残差连接 输出 = 输入 + F(输入),两个东西相加长度必须一致。这条固定宽度的通道叫 residual stream(残差流)。

别名对照:d_model(论文)= hidden_size(HF)= n_embd(GPT-2/nanoGPT)。

易混点:d_model 是"每个词多厚",与序列长度无关。10 个词的句子是 10 × 4608 的表格,100 个词是 100 × 4608——行数随句子变,列数永远 4608。

规模参照:GPT-2 small 768 / Llama 2 7B 4096 / Gemma 2 27B 4608 / Llama 3 70B 8192。

1.2词表:256128 的含义

模型认的不是字也不是词,是一份训练前定死的清单,共 256000 个条目(论文报 256128,见下)。任何输入都要先被切成清单里的条目。

为什么走 subword 路线:

折中方案(Gemma 用 SentencePiece):

"the"              → 1 个 token
"tokenization"     → "token" + "ization"           2 个
"anthropomorphism" → "anthrop" + "omorph" + "ism"  3 个
"猫"                → 1 个
"asdkjfh"          → 一堆字节碎片(兜底)

词表里装了什么:完整常用词、词片(ing/tion)、单字符(汉字/假名/西里尔)、标点空格、256 个字节兜底、特殊控制符(<bos>/<eos>/<start_of_turn>)。

256128 还是 256000:Gemma 2 论文的参数表写的是 256128,但公开权重的 config.json(vocab_size)和官方博客打印出的 Embedding(256000, 4608) 都是 256000。256000 本身就能被 128 整除(= 2000 × 128),所以多出的 128 并不是为了对齐;它是什么,论文没有说明,待核实。下文公式里的词表大小沿用论文的 256128,换成 256000 后所有数字在文中保留的精度下都不变(例如 ln 256000 与 ln 256128 都是 12.45)。

大词表的权衡:

模型 词表
Llama 2 / Mistral 32,000
GPT-4 (cl100k) ~100,000
Llama 3 128,256
Gemma 2 256,000(论文报 256,128)

好处是同样文本切出的 token 更少(对中日阿等非英语尤其明显)→ 序列短、KV cache 省、8192 上下文装得下更多真实内容。

代价对小模型特别残酷:

Gemma 2 embedding 占总参数
27B 1.18 B 4.3%
9B 0.92 B 9.9%
2B 0.59 B 22.6%

1.3Embedding:查表,不是矩阵乘

"猫 在 睡觉"
   ↓ tokenizer(字符串 → 整数)
[ 12456, 3021, 88907 ]
   ↓ 去 256000 × 4608 的表里按行号取
[4608个数], [4608个数], [4608个数]

数学上等价于 one-hot × 权重矩阵,但 one-hot 里只有一个 1,乘出来必然是矩阵的第 k 行。所以实现上直接用数组下标取,≈ 0 FLOPs。

入口占 1.18B 显存,但不占算力。

Gemma 的一个小动作:查表后要乘以 √4608 ≈ 67.9 再送进第一层,为了让初始数值尺度与 RMSNorm 配合。

1.4tied embedding

定义:入口和出口共用同一个张量,不是"两张数值相同的表"。

model.lm_head.weight is model.model.embed_tokens.weight
# tied   → True
# untied → False

出口用它的转置:

$$\text{入口:}E[k] \qquad\longleftrightarrow\qquad \text{出口:}\text{logits} = h\,E^\top$$

三种判别方式:

方法 tied untied
config.json "tie_word_embeddings": true false
权重文件 没有 lm_head.weight 有
参数量 少 V × d 多 V × d

常见误解:"初始化成一样再各自训练"——那不叫 tied,那叫 untied 但初始化相同。tied 的关键是共享持续到训练结束:两处梯度加到同一个张量上(见 5.5)。

为什么说得通:入口问"这个 token 代表什么意思",出口问"我想说的意思最接近哪个 token"。同一套语义坐标系的两面。

现状(小模型 tie,大模型不 tie):

模型 tied
GPT-2 是
Llama 2 / 3.1 8B 否
Llama 3.2 1B / 3B 是(转向)
Qwen3 0.6B / 4B 是
Qwen3 8B 否
Gemma 2 全系 是

1.5输入输出词表能不能不同

先分清两件事:

说的是什么 常见吗
A. 两个矩阵 词表相同,权重表两张 很常见(untied)
B. 两套词表 输入认识的和输出能产生的是不同集合 罕见

decoder-only 几乎不可能是 B,因为自回归回灌:

第 t 步:   输出 token ID = 3021
              ↓ 回灌
第 t+1 步:  输入 token ID = 3021

两侧词表不一致,模型立刻精神分裂。这是结构决定的,不是设计选择。

B 出现在没有回灌的地方:

源文本 → [encoder 输入 embedding]  ← 这里可以独立
            ↓ cross-attention
      [decoder 输入 embedding]  ┐
            ↓                    ├ 必须同词表
      [decoder 输出 LM head]     ┘

实例:Helsinki-NLP OPUS-MT / Marian 的 MarianTokenizer 要求源语言和目标语言用不同的 SentencePiece 模型(早期版本切词规则分两套但 ID 字典共享,后来才加了可选的 target_vocab.json)。

作为对比,原始 Transformer 论文的英德翻译用的是共享的 37000 BPE 词表——同属拉丁字母,共享划算。

跨模态是 B 的极端形式:

模型 输入 输出
Whisper 梅尔频谱(无词表) 文本 token
LLaVA / Gemma 3 视觉版 文本 token + 图像 patch 向量(软 token,无 ID) 只有文本
MusicGen / Bark / VALL-E 文本 token 音频 codec token

反例很有启发:Chameleon、Emu3 把图像量化后塞进同一个词表——正因为统一了,才能像输出文字一样输出图像。想让模型生成某模态,该模态必须在输出词表里。

伪 B:logit masking。有些 token 只能进不能出(<bos>、Gemma 那 128 个占位符、约束解码),做法是把 logit 设成 −∞,词表还是同一套。

实际后果:投机解码(9.5)要求草稿模型和目标模型词表严格一致,所以各家会发布同词表的大小配对。词表是模型家族的接口标准,换掉它的代价远比换权重大。



2Attention

2.1head_dim 与 d_model 已经解耦

head_dim = d_model / n_heads 只是原始论文的约定(512/8=64),不是数学要求。

真正的形状约束只有两条:Q 和 K 的 head_dim 必须相同(点积要求);W_O 的输出必须是 d_model(残差要求)。中间那个宽度 n_h × d_head 完全自由。

Gemma 2 全系都不遵守约定:

型号 d_model heads d_model/heads 实际 head_dim 内部宽度
2B 2304 8 288 256 2048(窄)
9B 3584 16 224 256 4096(宽于 d_model)
27B 4608 32 144 128 4096(窄)

9B 那行说明这不是单向的"瓶颈设计",两个维度是各自独立调参的。

为什么 27B 选 128 不选 144:

  1. 硬件 — FlashAttention 等 kernel 通常只对 head_dim ∈ {64,128,256} 优化。144 = 16×9 带因子 3,要 pad 到 160/192,白白浪费
  2. KV cache 与 d_model 解耦 — KV cache ∝ n_kv × d_head,可以放大 d_model 而不让 cache 跟着膨胀
  3. d_model 是为别的事选的 — 4608 = 512×9,方便张量并行切分

实际后果(会算错):

head_dim 必须从 config 读,绝不能自己除。

趋势:Gemma 3 27B(5376/32 = 168 ≠ 128)、DeepSeek-V3 的 MLA(见 2.11)都解耦了。head_dim 锁在 128 附近由 kernel 决定,d_model 和 n_heads 各按容量和并行度独立调。

2.2先投影,再切头

"把 4608 切成 32 段"是错误的说法,正确流程:

x:  [ x₁ ... x₄₆₀₈ ]              ← 残差流
      ↓ 乘 4608 × 4096 的稠密矩阵 W_Q
q:  [ q₁ ... q₄₀₉₆ ]              ← 每个 q 都是全部 4608 个数的加权和
      ↓  ← 到这一步才切
    头1: q₁..q₁₂₈ ┊ 头2: q₁₂₉..q₂₅₆ ┊ ... ┊ 头32

切的是投影之后的 4096,不是原来的 4608。 第 1 个头看的 128 个数是全部 4608 个分量的 128 种加权组合,x 的每个分量都参与了每个头。

4096 < 4608 意味着压缩,不是截断:

更重要的是残差流本身没被削窄。残差流 = 残差流 + W_O(注意力输出),原有 4608 维信息一个没少,注意力只是加了一份活在 4096 维子空间里的贡献。

真正紧的瓶颈不在这:

瓶颈 压缩比
4608 → 4096 11%
每个头只有 128 维 4608 → 128,97%
GQA:32 个 Q 头共用 16 组 KV 一半 KV 被共享

换来了什么:每层省 7.1M 参数(46 层共 326M),KV cache 省 11%(414 → 368 KiB)。

2.3Softmax 归一化的轴

精确表述:对某一个头里的某一个 query,它对所有可见 key 的注意力之和 = 1。

从 q、k 到注意力权重,一共三步(第 h 个头,第 i 个位置的 query 看第 j 个位置的 key):

$$\underbrace{s^{(h)}_{ij} = \frac{q^{(h)}_i \cdot k^{(h)}_j}{\sqrt{d_{\text{head}}}}}_{\text{① 打分}} \qquad \underbrace{s^{(h)}_{ij} \leftarrow -\infty \;\;(j \text{ 不可见时})}_{\text{② mask}} \qquad \underbrace{A^{(h)}_{ij} = \frac{\exp(s^{(h)}_{ij})}{\sum_{j'} \exp(s^{(h)}_{ij'})}}_{\text{③ softmax}}$$

符号 含义 Gemma 2 27B
$q^{(h)}_i$ 第 i 个 token 在第 h 个头的 query 向量(2.2 投影、切头之后) 128 维
$k^{(h)}_j$ 第 j 个 token 在同一头(GQA 下是同一组,见 2.5)的 key 向量 128 维
$s^{(h)}_{ij}$ 打分(logit):缩放后的点积,任意实数 —
$\sqrt{d_{\text{head}}}$ 缩放因子 ⚠️ 用的是 $\sqrt{144} = 12$,不是 $\sqrt{128}$(见 A.3)
$A^{(h)}_{ij}$ 注意力权重:softmax 之后,非负、行和为 1 —
$j'$ 分母里的求和变量,遍历第 i 行所有可见的 key —

整张表写成矩阵就是 $S^{(h)} = Q^{(h)}K^{(h)\top}/\sqrt{d_{\text{head}}}$、$A^{(h)} = \text{softmax}(S^{(h)})$(逐行做),再乘 $V$ 得到输出 $A^{(h)}V^{(h)}$。本文统一用小写 $s_{ij}$ 表示打分、$A$ 表示注意力权重;9.7 沿用 FlashAttention 论文的记号,那里的 $S$ 就是这里的 $s_{ij}$ 排成的矩阵,$P$ 就是这里的 $A$。

每一步在干什么:

数值例子(下面那张表 q₃ 那一行是怎么来的;只有 4 个位置,q₃ 只能看 k₁~k₃):

k₁ k₂ k₃ k₄
原始点积 $q_3 \cdot k_j$ 4.0 0.0 17.4 (不可见)
① 除以 $\sqrt{144} = 12$ 0.333 0 1.450 —
② mask 0.333 0 1.450 $-\infty$
$\exp(\cdot)$ 1.396 1.000 4.263 0
③ 除以总和 6.659 0.21 0.15 0.64 0

对照:如果不除 $\sqrt{d}$,直接对 [4.0, 0, 17.4] 做 softmax,结果是 [0.0000015, 0.00000003, 0.999998]——几乎全部压在 k₃ 上,另外两个位置的梯度接近 0,这就是原论文说的"饱和区"。

⚠️ 实际代码不会直接算 $\exp(s_{ij})$:打分一大就会上溢。标准做法是每行先减去这一行的最大值再取指数(结果不变),9.7 的在线 softmax 就建立在这个技巧上。

三个细节:

  1. 包括自己 — q_i 和 k_i 那一项也在分母里,且权重往往不小
  2. "所有"要打折 — causal mask 下只能看 j ≤ i;Gemma 局部层还有 4096 窗口
  3. 头与头不竞争 — 32 个头各自有完整的 1.0 预算,一层里有 32 × t 行,每行独立等于 1

行随机,不是双随机:

        k₁     k₂     k₃     k₄
q₁     1.00    ·      ·      ·      → 行和 1.00 ✓
q₂     0.62   0.38    ·      ·      → 行和 1.00 ✓
q₃     0.21   0.15   0.64    ·      → 行和 1.00 ✓
q₄     0.30   0.09   0.11   0.50    → 行和 1.00 ✓
      ─────  ─────  ─────  ─────
列和   2.13   0.62   0.75   0.50    ← 无约束

含义:分配出去的注意力守恒,被别人关注的量不设限。

Attention sink:因为行和被强制为 1,模型没法"谁都不看"。不需要上下文时,那 1.0 必须找地方倒掉,于是自发倾泻到 BOS 或句首标点上。这不是 bug,是归一化约束的必然产物——也是 StreamingLLM 那类方法必须保留最前面几个 token 的原因。

2.4token mixing vs channel mixing

步骤 混合方向 可训练参数
xW_Q, xW_K, xW_V 跨特征 ✅
QKᵀ 跨位置 ❌
softmax 都不跨(逐行归一化) ❌
A·V 跨位置 ❌
·W_O 跨特征 ✅
FFN 三个矩阵 跨特征 ✅

所有参数都在做 channel mixing。跨位置的两步,一个参数都没有。

静态 vs 动态混合:

W_Q/W_K 学的不是混合权重,而是**"怎么算出混合权重"的规则**:

所以 attention 叫 data-dependent routing。

W_Q 和 FFN 矩阵的区别:结构上没有任何区别,都是 4608 × N 的稠密矩阵,都逐位置独立作用。区别 100% 在下游怎么用它的输出——FFN 的输出留在自己这个词里,W_Q 的输出拿去和别的词的 K 点积。

注意力矩阵 A 不是学出来的——它不存在于模型文件里,是每次前向临时算出又扔掉的。存盘的只有 W_Q/W_K/W_V/W_O。这也是 Transformer 能处理任意长度序列的原因:A 的尺寸是 t × t,参数量与 t 无关。

图形化(行=位置,列=特征):

自注意力:沿位置轴(竖着混)    全连接:沿特征轴(横着混)
      特征 →                        特征 →
  词1  ░░█░░                    词1  ░░░░░
  词2  ░░█░░                    词2  ░░░░░
  词3  ░░█░░                    词3  █████
  词4  ░░█░░                    词4  ░░░░░

严格说注意力内部大部分也是 position-wise 的——四个投影都逐位置独立,真正跨位置的只有 A·V。

2.5GQA:为什么 K/V 比 Q 窄一半

三种方案的对照:

方案 Q 头 KV 头 KV cache
MHA(多头,2017 原版) 32 32 100%
GQA(分组,Gemma 2 用) 32 16 50%
MQA(多查询) 32 1 3%

MHA 是每个 Q 头配一个专属的 K/V 头。MQA 走另一个极端,全部 Q 头共用 1 组。GQA 是中间路线:分成 16 组,每组 2 个 Q 头共享一组 K/V。

MHA          GQA(每 2 个 Q 头一组)
Q₁ Q₂ Q₃ Q₄       Q₁ Q₂    Q₃ Q₄
 │  │  │  │        ╲  ╱      ╲  ╱
K₁ K₂ K₃ K₄        KV₁       KV₂

投影矩阵的宽度直接跟着头数走:

$$W_Q \text{ 输出} = 32 \times 128 = 4096 \qquad W_K, W_V \text{ 输出} = \mathbf{16} \times 128 = \mathbf{2048}$$

所以 W_K/W_V 的参数量正好是 W_Q 的一半(9.4M vs 18.9M)。

这是架构决策,不是部署优化

这个层次差别最容易搞混:

什么时候定 能不能事后改
GQA / MLA(MLA 见 2.11) 建模时,写进 config ❌ 改了权重就报废
量化(见 9.9)/ FlashAttention / PagedAttention 部署时 ✅ 随便换
投机解码 / chunked prefill 运行时 ✅ 随便开关

n_kv_heads = 16 写进 config 的那一刻,W_K 的形状就是 4608 × 2048,从随机初始化的第一步起就是这个尺寸。它和 9.4 表里其他提升算术强度的手段不是一类东西——别的都能在训好的模型上加,GQA 必须一开始就选。

训练时的两个影响

① 参数量少了。 每层 W_K + W_V 从 MHA 的 37.7M 降到 18.9M,46 层共省 868M——这些参数从一开始就不存在,不是训完剪掉的。

② 梯度天然聚合。 MHA 里 K[0] 只服务 Q[0],梯度来源单一。GQA 里 K[0] 同时被 Q[0] 和 Q[1] 用,反向传播时两股梯度加到同一块权重上:

$$\frac{\partial L}{\partial W_K^{(0)}} = \left.\frac{\partial L}{\partial W_K^{(0)}}\right|_{Q_0} + \left.\frac{\partial L}{\partial W_K^{(0)}}\right|_{Q_1}$$

结构上和 tied embedding 那个 $g^{\text{in}} + g^{\text{out}}$ 是同一件事——共享权重 = 梯度求和(见 5.5)。

后果是这组 K/V 被训练成"对两个 Q 头都好用"的折中表示,而不是为单个头定制。这才是 GQA 真正的质量代价所在,也是它无法事后加装的原因:权重必须在这个约束下长出来。

例外:uptraining 可以低价补票

GQA 论文的核心贡献之一恰恰是——已训好的 MHA 模型可以改造成 GQA:

  1. 每组的多个 K/V 头取平均(mean-pool)合成一个
  2. 用约 5% 的原始预训练算力继续训一小段

论文报告这样恢复的模型质量接近从头训的 GQA。Llama 2 的 34B / 70B 走的就是这条路。

用 mean-pool 而不是随便挑一个头,正是为了保留组内那几个头的共同信息——和上面"折中表示"是同一个逻辑。

repeat_kv:16 头复制成 32 头

解码一个 token(历史长度 t)时的形状变化:

Q(现算)        [32, 1, 128]
K(从 cache 取) [16, t, 128]   ← 存的就是 16 份
                      ↓ repeat_kv,每份复制 2 遍
                 [32, t, 128]   ← 形状对齐
                      ↓
QKᵀ              [32, 1, t]

复制出来的是完全相同的数据,不携带任何新信息,纯粹为了让形状对上。因为 attention 是逐头独立计算的,Q 有 32 个头就要跑 32 次,每次都得有一个对应的 K[i]。

n_rep = 32 / 16 = 2,配对方式是相邻的 Q 头共享:

KV 头 服务的 Q 头
0 0, 1
1 2, 3
… …
15 30, 31

分工:存储 16 头(省的是这里),计算 32 头(和 MHA 一样)。

实际不会真的复制:repeat_kv 是 HuggingFace 参考实现的朴素写法。生产 kernel(FlashAttention、PagedAttention)直接让 2 个 Q 头读同一块 KV 显存,一次读入 SRAM 供两个头用——既不多占显存,还把 HBM 读取量真的减半了。所以优化实现里 GQA 的收益比朴素实现更大。

FLOPs 到底省不省

省,但很少。attention 核心(QKᵀ、A·V)确实不省,但投影那一步省了,因为 W_K/W_V 只有一半大:

每层每 token 的 QKV 投影
若用 MHA 113.2 MFLOPs
GQA-16 75.5 MFLOPs

46 层累计省 1.74 GFLOPs,占总量(56.2 → 54.5 GFLOPs)约 3%。

GQA 省约 3% 的 FLOPs,省 50% 的 KV cache。收益压倒性地在显存和带宽,但不是零。

2.6为什么甜点区落在 8~16 组

先说清楚:没有能预测出"8"的理论。 GQA 论文是先做实验再解释的。下面几条机制让这个数字显得合理,但不是推导——如果当初实验结果是 4 或 32,同样能编出自洽的故事。

不过其中有一条是硬约束,它解释了为什么下限卡在 8 而不是更低。

机制一:组内的注意力模式并没有被合并

最容易误解的地方。共享 K/V 之后,同组的两个 Q 头仍然有各自独立的 W_Q:

$$s_1 = q_1 \cdot k \qquad s_2 = q_2 \cdot k \qquad q_1 \neq q_2$$

所以它们算出来的注意力分布依然不同,各看各的。被牺牲的不是"能不能有不同的模式",而是"能在哪个子空间里匹配"。

用 2.4 的话说:W_Q 学的是"该问什么问题",W_K 学的是"该宣传自己是什么"。GQA 保留了每个头独立提问的能力,只是让同组的头面对同一份宣传词。

机制二:key 子空间的预算

把每层所有 K 投影的总维度加起来,和残差流宽度比:

方案 key 空间总维度 占 d_model (4608)
MHA (32) 4096 88.9%
GQA-16 2048 44.4%
GQA-8 1024 22.2%
MQA (1) 128 2.8%

MQA 为什么崩得明显,这一行就够了——全部 32 个头必须在同一个 128 维子空间里找匹配,而残差流有 4608 维,绝大部分信息在 K 侧根本无法被区分。

2048 维为什么够用,可以接回 8.3 的叠加:近似正交方向的容量按 $e^{d\varepsilon^2}$ 走。d 从 4096 减到 2048,容量是开平方而不是减半——如果原来能装 $10^{40}$ 个方向,现在是 $10^{20}$,对一层需要区分的特征数来说依然绰绰有余。

⚠️ 这个论证的前提是特征确实 packed 到接近 JL 上界,属于强假设。当直觉用,别当证明。

机制三:头本来就大量冗余

这可能是最实在的经验解释。有一整条线的研究表明多头注意力里大部分头是可裁的:

如果一层里真正做不同工作的头本来就只有十来个,那么给 32 个 Q 头配 16 组 K/V 根本不是约束——原本的多样性就没用满。

机制四:省的量按几何级数衰减

这是"甜点区必然存在"的原因,也是唯一能推出来的部分。KV cache 正比于组数,每次对半砍:

从 → 到 剩余 cache 本次新增节省
32 → 16 50% 50 个百分点
16 → 8 25% 25
8 → 4 12.5% 12.5
4 → 2 6.25% 6.25
2 → 1 3.1% 3.1

每砍一刀,收益减半。 而质量代价的走向正相反——前几刀几乎无感(机制三:冗余在被消耗),等冗余耗尽、机制二的子空间预算开始吃紧,代价就陡然上升。

一条几何衰减的收益曲线,一条先平后陡的代价曲线,必然有拐点。拐点的存在是可预测的,位置是经验的。

机制五:张量并行是硬地板

这条最实在,也最少被提。TP 切分是按头切的。如果 kv_heads < TP 并行度,同一个 KV 头就必须在多张卡上各存一份:

TP=8, kv_heads=8  →  每卡 1 组 KV        ✅ 内存真省了
TP=8, kv_heads=4  →  每组被 2 张卡复制    ❌ 总占用回到 8 组的水平

低于 TP 度之后,继续减 KV 头不再省任何内存。 而 TP=8 是当前的事实标准(单机 8 卡)。

所以 8 不是一个软性的质量权衡点,而是继续往下走收益直接归零的位置。Gemma 2 27B 取 16,还额外留出了 TP=16 的余地。

归纳

边界 卡在哪
上限(不用 32) 头本来就冗余,砍到一半白赚(机制三)
下限(不低于 8) 张量并行下再减不省内存(机制五)+ key 子空间开始不够(机制二)
拐点必然存在 收益几何衰减 vs 代价加速上升(机制四)
拐点恰好在 8 纯经验

2.7Cross-attention

一句话:Q 来自解码器,K/V 来自编码器。

自注意力里 Q、K、V 都从同一序列算出。cross-attention 唯一的改动就是把 K/V 的来源换掉:

$$\text{Self}: \; Q,K,V = xW_Q,\, xW_K,\, xW_V \qquad \text{Cross}: \; Q = \underbrace{y}_{\text{解码器}}W_Q, \;\; K,V = \underbrace{x}_{\text{编码器输出}}W_K, W_V$$

其余部分——softmax、多头、$W_O$、残差——一模一样。它不是新机制,只是同一个机制换了数据来源。

用 2.4 那套说法:$W_Q$ 学"目标端这个位置该问什么",$W_K$ 学"源端这个位置该宣传什么"。cross-attention 就是让译文去查原文。

三种注意力的对照(源长 $S$、目标长 $T$):

Q 来自 K/V 来自 注意力矩阵 mask
编码器自注意力 源 源 $S \times S$ 无(双向)
解码器自注意力 目标 目标 $T \times T$ 因果
交叉注意力 目标 源 $T \times S$ 无因果 mask

两个关键点:

  1. 注意力矩阵是长方形的——自注意力永远是方阵,cross-attention 一般不是
  2. 没有因果 mask——生成第 1 个词时就能看到整句原文,完全合理;因果性只约束目标端自己。(但仍需 padding mask,源句长短不一)

数据流

编码器(双向读完整源文)
   "The cat sat"
        ↓
   编码器输出 [S, d] ──────┐
                          │  一次算好 K/V,之后反复用
解码器每层三个子层:        ↓
   "猫" → 自注意力(因果) → 交叉注意力(Q 从这来) → FFN → "坐"

decoder 层有三个子层,比 decoder-only 多一个,所以每层多一套 $W_Q/W_K/W_V/W_O$。

还有个容易忽略的自由度:$W_K, W_V$ 把编码器的 $d_{model}$ 映射到解码器的头维度——两侧的 $d_{model}$ 可以不一样。Whisper 就利用了这点。

历史:cross-attention 才是原版

年份 事件
2014 Bahdanau——attention 诞生,就是 cross-attention(RNN 解码器查 RNN 编码器状态)
2017 Vaswani——self-attention 才被提出,把 attention 转向序列内部

Attention 最初的动机就是解决 seq2seq 的信息瓶颈:原来整句原文要压进一个固定向量,长句必然丢信息。也因此 cross-attention 矩阵有很强的可解释性——翻译模型里它近似就是词对齐表,画出来能看到 "cat" 对上"猫"。self-attention 的注意力图就没这么干净。

KV cache 的差别很大

缓存内容 随生成增长吗
解码器自注意力 已生成的 $T$ 个 token 的 K/V ✅ 每步 +1
交叉注意力 源序列的 $S$ 个 K/V ❌ 算一次,固定不变

编码器输出在解码开始前就定了,源端 K/V 整个生成过程算一次就够。HF 的 encoder-decoder 模型每层缓存 4 个张量(自注意力 K/V + 交叉注意力 K/V),后两个是静态的。

所以对"输入长、输出短"的任务,encoder-decoder 在 cache 上有真实优势——Whisper 把 30 秒音频编码一次,之后每个字都白嫖那份 K/V。换成 decoder-only,音频 token 会一直躺在不断增长的同一个 cache 里。

Decoder-only 怎么做到同样的事

直接拼接,靠因果 mask:

[原文 tokens] [分隔符] [译文 tokens]
 ←── 译文的每个位置都能回看这一段 ──→

功能等价,但两处不同:

  1. 原文只能被因果地看一遍,不能双向编码(除非用 prefix-LM mask:前缀双向、续写因果)
  2. 原文的 K/V 混在同一个不断增长的 cache 里,不再是独立的固定块

换来的是架构简单——一个栈、一套词表、没有两套 $d_{model}$ 要对齐。1.5 讲的"输入输出词表能不能不同",根源也在这:cross-attention 那条路上没有回灌,所以源端词表可以独立。

现在哪里还在用

模型 编码 解码
Whisper 音频频谱 文本
部分 VLM(如 Flamingo 系) 图像 文本
T5 / 翻译专用模型 源语言 目标语言

判断标准很实用:当输入不是"可以续写下去的同类东西"时,把它塞进同一个自回归序列就很别扭,这时 cross-attention 更自然。反过来,LLaVA 那类把图像投影成软 token 直接插进文本流的做法走的是 decoder-only 路线——两条路都能通。

2.8RoPE:把位置写成旋转角

一句话:RoPE 不往残差流里加任何东西,而是在算点积之前,把 q 和 k 按各自的位置转一个角度。转完以后,两者的点积只和"差了几个位置"有关。

先说为什么需要位置编码。 2.4 说过,跨位置的两步($QK^\top$、$A\cdot V$)一个参数都没有,四个投影又都逐位置独立。所以如果什么都不加,在双向注意力里把句子里的词打乱顺序,每个词得到的输出只是跟着换了位置,内容完全不变(因果 mask 会带进一点顺序信息,见 2.10)。"狗咬人"和"人咬狗"对它来说是同一件事。位置信息必须从外面塞进去。

两种塞法:

做法 代表
加在输入上(绝对位置) 第 m 个位置的 embedding 加上一个位置向量 $p_m$ 原始 Transformer 的正弦编码、GPT-2 的可学习位置表
加在注意力里(相对位置) 只改 q·k 的打分,不碰残差流 RoPE、ALiBi、T5 bias

Gemma 2、Llama、Qwen、DeepSeek 都用 RoPE。这也是 4.2 那句"Gemma 用 RoPE,没有加性位置编码"的出处。

机制:两两一组,各自旋转

把 128 维的 q 拆成 64 对 $(q_{2i}, q_{2i+1})$,每一对看成平面上的一个点。第 m 个位置的 q,第 i 对转 $m\theta_i$ 角:

$$\begin{pmatrix} q'_{2i} \\ q'_{2i+1} \end{pmatrix} = \begin{pmatrix} \cos m\theta_i & -\sin m\theta_i \\ \sin m\theta_i & \cos m\theta_i \end{pmatrix} \begin{pmatrix} q_{2i} \\ q_{2i+1} \end{pmatrix}$$

k 也一样,只是用它自己的位置 n。记作 $q'_m = R_m q$、$k'_n = R_n k$。

为什么点积只剩相对位置:旋转矩阵有两个性质,$R_m^\top = R_{-m}$(转回去),$R_{-m}R_n = R_{n-m}$(转两次 = 转角度之和)。于是

$$q'^\top_m k'_n = (R_m q)^\top (R_n k) = q^\top R_m^\top R_n\, k = q^\top R_{n-m}\, k$$

绝对位置 m、n 消掉了,只剩 $n-m$。(2.3 的打分还要再除以 $\sqrt{d_{\text{head}}}$,这是个常数,不影响这里的结论。)用二维平面想更直观:两个向量同时转同一个角度,夹角不变,点积不变;所以只有"两者各转了多少"的差会影响结果。

数值验证(随机 128 维 q、k,$\theta$ 按下式取):

(m, n) 相对距离 $q'^\top_m k'_n$
(10, 3) 7 3.81497
(1007, 1000) 7 3.81497
(7, 0) 7 3.81497

三者在 $10^{-12}$ 内相等。旋转也不改变向量长度($\|q'\| = \|q\|$),所以 RoPE 只动方向,不动 4.1 那套尺度。

频率怎么设

$$\theta_i = b^{-2i/d}, \qquad i = 0, 1, \dots, \tfrac{d}{2}-1$$

$d$ 是 head_dim(Gemma 2 27B 为 128),$b$ 叫 base(config 里的 rope_theta),原论文和 Gemma 2 都取 10000。(RoFormer 式 (15) 写成 $10000^{-2(i-1)/d}$、$i$ 从 1 起,和这里是同一组数;但它 §3.3 证远程衰减时又写成 $10000^{-2i/d}$,论文自己前后差了一位下标,不影响结论。)

这是一组几何级数,从转得最快到转得最慢排开。换成"转一整圈要走多少个 token"(波长 $\lambda_i = 2\pi/\theta_i$)更好理解:

第 i 对 $\theta_i$ 波长 $\lambda_i$(token) 能分辨什么
0 1 6.3 相邻几个词的先后
16 $10^{-1}$ 63 短语内
32 $10^{-2}$ 628 段落内
48 $10^{-3}$ 6,283 篇章
63 $\approx 1.2\times10^{-4}$ 54,410 只够当"远/近"的粗刻度

跟钟表一样:秒针分辨细节、时针分辨大范围,几根针合起来既精确又不重复。高频对负责近处的精细顺序,低频对负责远处的大致距离。

"远程衰减":RoFormer 论文(§3.4.3,用 Abel 变换)证明了 $q^\top R_{n-m} k$ 的一个上界随 $|n-m|$ 增大而下降,意思是距离越远,打分天然越弱。⚠️ 这是对上界的结论,不是说每一对 q、k 的分数都单调衰减;实际模型的注意力也会跨很远去找东西。

RoPE 在代码里在哪一步:在 2.2 投影、切头之后,点积之前,对 Q 和 K 做(不对 V 做)。因为它作用在 K 上,所以 KV cache 里存的是已经转好的 K。这一点到 2.11 MLA 那里会变成麻烦。

2.9RoPE 的长度外推:为什么超出训练长度就失效

一句话:训练时最慢的那几对维度连一圈都没转完,模型只见过它们的一小段角度。推理时序列一长,这些维度转到了没见过的角度,打分就乱了。各种扩展方法的本质,都是想办法让新长度下的角度落回训练时见过的范围。

问题出在低频维度

接 2.8 那张波长表。Gemma 2 27B 的训练长度是 8192:

维度对 波长 vs 8192 训练时见过的角度
第 0~49 对(高频、中频) 波长 < 8192 转过一圈以上,0~2π 全见过
第 50~63 对(低频,共 14 对) 波长 > 8192 没转满一圈;最慢那对只转到约 54°

高频维度不怕长:位置 9000 的角度和位置 900 的角度,模 2π 之后训练时都见过。低频维度不一样,位置超过 8192 时它会转到 54° 以外,这些角度在训练数据里从来没出现过。$W_Q$、$W_K$ 是在"低频维度只会落在 0°~54°"的前提下学出来的,现在前提被打破了。

YaRN 论文(§3.2)对这一点的表述是:有些维度的波长比预训练时见过的最大长度还长,这些维度在整个训练长度内都没转满一圈,所以它们实际上编码的是绝对位置而不是相对位置——这就是 RoPE 明明是相对编码、却外推不了的原因。PI 论文给的是另一个角度的解释:外推时注意力分数没有上界,可能"灾难性地"变大。两种说法指向同一件事:位置编码这个输入出了分布(out of distribution)。现象是困惑度在超过训练长度后陡然上升。

办法一:位置插值(Position Interpolation, PI)

Chen et al. 2023(Meta)的思路最直接:既然超出的角度没见过,那就把位置号压缩,让新长度塞回旧范围。目标长度 $L'$、训练长度 $L$:

$$f'(x, m) = f\!\left(x,\; \frac{mL}{L'}\right)$$

扩到 2 倍时,位置 16384 被当作 8192 来转,位置 1 被当作 0.5 来转。所有角度都落回见过的区间,代价是相邻 token 的角度差缩小了 $L'/L$ 倍。

论文结果:LLaMA 7B~65B 从 2048 扩到 32768,1000 步以内的微调即可。它还从理论上比较了两者:插值后注意力分数的上界比外推至少小约 600 倍。

⚠️ PI 的缺点也很直接:所有维度一视同仁地压缩。高频维度本来就不需要帮忙(见上表),被压缩后反而损失了分辨相邻 token 的能力。

办法二:NTK-aware 缩放(改 base)

⚠️ 出处是社区:Reddit r/LocalLLaMA 上用户 bloc97 的帖子(2023 年;具体月份待核实),后来被 YaRN 论文整理引用。

思路:不压位置号,改 base。设放大倍数 $s = L'/L$:

$$b' = b \cdot s^{d/(d-2)}$$

效果是高频几乎不变,低频压缩最多——正好对症。指数 $d/(d-2)$ 的作用是让最低频那对恰好被压缩 s 倍,和 PI 对齐(YaRN 附录 A.2 的推导);其余维度压缩得越来越少,最高频那对完全不动。Gemma 2 若想扩到 4 倍,base 从 10000 变成约 40890。

"NTK" 来自神经正切核理论(Neural Tangent Kernel)里"网络难以学习高频信号"的结论,用来论证不该压高频。名字有点唬人,实际操作就是改一个数。同一批社区作者还提出了 Dynamic NTK(emozilla):s 随当前序列长度动态变化,短序列完全不缩放。

办法三:YaRN

Peng et al. 2023 把前两种做法合起来,再加一个修正。两部分:

① NTK-by-parts:按波长分段处理。 设 $r = L/\lambda_i$(训练长度内第 i 对能转几圈):

区段 条件 处理
高频 转了很多圈($r > \beta$) 不动
低频 一圈都没转满($r < \alpha$) 完全按 PI 插值,频率除以 s
中间 $\alpha \le r \le \beta$ 两者线性过渡

写成公式是 $h(\theta_i) = (1-\gamma)\,\theta_i/s + \gamma\,\theta_i$,$\gamma$ 从 0(低频)线性升到 1(高频)。论文说 Llama 系列取 $\alpha = 1, \beta = 32$ 效果好。这比 NTK-aware 的"连续改 base"更精确地落实了"高频别动、低频要压"。

② 注意力温度。 插值后注意力分布会变"平",YaRN 在 2.3 的第 ① 步里多除一个温度 t,打分变成 $s_{mn} = q_m^\top k_n / (t\sqrt{d_{\text{head}}})$,对 LLaMA / Llama 2 的经验公式是

$$\sqrt{1/t} = 0.1\ln s + 1$$

s = 4 时约 1.14,s = 32 时约 1.35。

论文结果:和之前的方法比,少用约 10 倍 token(对比 Code Llama)、2.5 倍训练步数(对比 PI,400 步 vs 1000 步),是第一个把 Llama 2(7B/13B)有效上下文扩到 128K 的方法。DeepSeek-V2/V3 的 128K 长上下文就是用 YaRN 扩的(V2 取 $s=40, \alpha=1, \beta=32$),Qwen3 部署更长上下文时也用 YaRN。

办法四:训练时就放大 base

不等推理时补救,训练(或续训)时就把 base 调大,让低频维度转得更慢、训练长度内就够用:

模型 base 上下文 出处
Llama 2 / Gemma 2 10,000 4K / 8K config
Code Llama 1,000,000 训练 16K,测到 100K 仍有提升 Rozière et al. 2023
Llama 2 Long(RoPE ABF) 500,000 32K(7B/13B;34B/70B 训练长度为 16K) Xiong et al. 2023
Llama 3 500,000 8K config

base 从 10000 调到 500000,最慢那对的波长从 5.4 万变成约 256 万 token。

Llama 3.1 的做法是在 base 500000 之上再做一层分段缩放(config 里 rope_type: "llama3",factor: 8),从 8K 扩到 128K。按 transformers 的实现:

波长 处理
< 2048(= 8192 / high_freq_factor 4) 不动
> 8192(= 8192 / low_freq_factor 1) 频率除以 8,等于 PI
2048 ~ 8192 两者平滑过渡

思路和 YaRN 的 NTK-by-parts 一样,但没有温度项。

归纳

方法 改什么 高频 低频 要不要微调
直接外推 不改 正常 出分布 —
PI 位置号 × L/L' 被误伤 压回范围 需要(≤1000 步)
NTK-aware base ↑ 几乎不变 压回范围 可以不调,调了更好
YaRN 分段 + 温度 不变 压回范围 少量(~400 步)
训练时大 base base ↑↑ 不变 训练内就够 在训练阶段解决

所有 RoPE 扩展方法都在做同一件事:让推理时的旋转角落回训练时见过的范围;区别只在于"压谁、压多少"。

(这条路走得最远的是 LongRoPE(Ding et al. 2024):用搜索为每个维度找各自的缩放因子,宣称扩到 2048K token。)

⚠️ 困惑度不掉 ≠ 能用上长上下文。 上面这些方法主要用困惑度和"大海捞针"评估。RULER(Hsieh et al. 2024)用更难的多针检索、多跳追踪、聚合等任务测了 17 个模型:它们都标称支持 32K 以上,但只有一半在 32K 时还能保持令人满意的表现。位置编码只解决了"别出分布",模型能不能真的用好远处的信息,还取决于长文本训练数据。

2.10RoPE 之外:ALiBi 与 NoPE

一句话:ALiBi 把"距离越远、分数越低"直接写成线性惩罚,困惑度外推得好,但远处其实被压没了;NoPE 干脆不加位置编码,靠因果 mask 自己推断位置,小规模实验里长度泛化最好,大模型上还没被单独验证。主流仍是 RoPE + 2.9 的扩展方法,2025 年起的新趋势是 RoPE 层和 NoPE 层按层混用。

ALiBi:给远处的 key 扣分

Press et al. 2021(Train Short, Test Long,ICLR 2022)。不改 q、k,直接在打分上加一个和距离成正比的负偏置:

$$s_{ij} = \frac{q_i \cdot k_j}{\sqrt{d_{\text{head}}}} - m_h \cdot (i - j), \qquad j \le i$$

符号 含义
$i - j$ query 和 key 隔了几个位置
$m_h$ 第 h 个头的斜率,固定,不训练

($s_{ij}$ 就是 2.3 的打分,ALiBi 只在第 ① 步之后多减一项。论文写法是 $\text{softmax}(q_iK^\top + m\cdot[-(i-1),\dots,-2,-1,0])$,正文为简洁省略了 $\sqrt{d}$ 缩放;论文脚注说明偏置项不乘这个缩放因子,所以上式只缩放点积。)

斜率是一组几何级数:n 个头时从 $2^{-8/n}$ 开始,公比也是 $2^{-8/n}$。8 个头就是 $\tfrac12, \tfrac14, \dots, \tfrac1{256}$。斜率大的头只看眼前几个词,斜率小的头能看远——和 RoPE 的多频率是同一个"多把尺子"的思路。论文提到试过让斜率可训练,外推效果反而不好。

整个网络里不加任何位置向量,也不旋转,只多一次加法。

论文结果:1.3B 模型在 1024 长度上训练、在 2048 上测试,困惑度和直接在 2048 上训练的正弦编码模型相同,训练快 11%、显存省 11%(图 5 给的显存节省区间是 6%~11%)。BLOOM(176B)和 MPT 用的是 ALiBi。

ALiBi 外推得"好",好在哪、限度在哪

偏置随距离线性增长,远处的 key 在 softmax 之后几乎为 0。所以序列再长,远处的 token 对输出也几乎没影响,困惑度自然不会爆。

但这也是它的限度。Chi et al. 2022(ACL 2023)做了感受野分析:两个 token 离得远时,ALiBi 和窗口注意力几乎一样,它很可能根本没用上训练长度以外的信息。FIRE 论文(Li et al. 2023)的实验里,ALiBi 在长文本基准 SCROLLS 上得分最低。

ALiBi 的外推,是靠"不看远处"换来的。 困惑度不升,不等于模型用上了远处的信息。

NoPE:什么都不加

Kazemnejad et al. 2023(NeurIPS 2023)。decoder-only 模型完全不加位置编码,在他们的长度泛化任务上,比正弦、T5 bias、ALiBi、RoPE 这些显式编码都好。论文还证明了 NoPE 理论上既能表示绝对位置、也能表示相对位置,训练后学到的注意力模式最像 T5 的相对位置偏置。

没有位置编码,模型怎么知道顺序? 靠因果 mask。第 i 个 token 只能看见前 i 个,"能看见多少个"本身就随位置变。Haviv et al. 2022 更早观察到,去掉位置编码的因果语言模型依然和标准模型有竞争力,他们的猜想是:因果注意力让模型能推断出每个 token 前面有多少个 token。⚠️ 注意这只适用于因果 mask;双向注意力(BERT)不加位置编码就真的分不清顺序(见 2.8 开头)。

⚠️ NoPE 的限度:

混合路线:RoPE 管近处,NoPE 管远处

模型 做法 出处
Cohere Command A 滑动窗口注意力和全局注意力按 3:1 交替;窗口层用 RoPE,全局层不用位置编码 Command A 技术报告(2025),方案来自 Yang et al. 2025
Llama 4(iRoPE) 部分注意力层"不带位置编码",推理时对注意力做温度缩放以改善长度泛化;Scout 标称 1000 万 token Meta 官方博客(2025-04)

道理接 2.9:RoPE 出问题的是低频维度、也就是远距离。窗口层只看 4096 以内,走不到没见过的角度;全局层干脆不用位置编码,也就不存在"没见过的角度"。Yang et al. 报告这样做 KV cache 减少近 4 倍,长、短上下文都不输全局 RoPE 基线(这些是作者自报结果,短文本基准有涨有跌)。

Gemma 2 的局部/全局交替(9.1)是同一套骨架,只是它的全局层还带着 RoPE。

对比

位置信息在哪 额外参数 超出训练长度(困惑度) 用上远处信息 代表
正弦(2017) 加在输入上 0 差 差 原始 Transformer
可学习绝对位置 加在输入上 表长 × d 不能(超出表长没有向量) — GPT-2、BERT
T5 bias 打分上加可学习标量 每头 32 个桶,各层共享 中 中 T5
RoPE 旋转 q、k 0 差,但可扩展(2.9) 扩展 + 长文本训练后好 Llama、Gemma、Qwen、DeepSeek
ALiBi 打分上加线性惩罚 0 好 弱(远处被压没了) BLOOM、MPT
NoPE 不加,靠因果 mask 0 小规模实验好,也有上限 待核实(缺大模型证据) 混合架构的全局层

T5 bias 那行的细节:32 个桶按对数划分,超过 128 的距离全部归入同一个桶;每个头一套偏置,各层共享(Raffel et al. 2019)。正弦编码那行有个历史注脚:原论文选正弦,理由之一就是希望它"可能让模型外推到比训练时更长的序列"——后来的实验(如 ALiBi 论文)表明并没有做到。

位置编码只决定"超过训练长度时会不会出分布",不决定"模型能不能用好长上下文",后者主要靠长文本数据。

2.11MLA:把 KV cache 再压一个数量级

一句话:GQA 靠"几个头共用同一份 K/V"省 cache,MLA(Multi-head Latent Attention,DeepSeek-V2 提出)换了个思路:每个 token 只缓存一个 512 维的压缩向量,每个头的 K/V 都从这个向量现场还原出来。推理时再用矩阵结合律把"还原"这一步并进 Q 和 O 的投影里,所以实际上连还原都不用做。代价是一处 RoPE 的不兼容,需要额外开一条 64 维的小通道来补。

和 GQA 的根本区别

2.5 的 GQA 是共享:两个 Q 头读同一份 K/V,所以同组的头只能面对同一份"宣传词"(2.6 机制一)。MLA 是压缩:所有头共用一个低维的潜在向量,但每个头用自己的上投影矩阵从里面解出各自不同的 K 和 V。

GQA:   h ──W_K──→ [16 组 K] ──复制──→ 32 个头    缓存:16 组完整的 K/V
MLA:   h ──W_DKV──→ c (512 维) ──W_UK_i, W_UV_i──→ 128 个头各自的 K/V
                     ↑ 只缓存这个

机制一:低秩联合压缩

DeepSeek-V2 论文式 (9)~(11):

$$c_t^{KV} = W^{DKV} h_t, \qquad k_t^{C} = W^{UK} c_t^{KV}, \qquad v_t^{C} = W^{UV} c_t^{KV}$$

符号 含义 DeepSeek-V2/V3 取值
$h_t$ 第 t 个 token 的残差流输入 5120 / 7168 维
$c_t^{KV}$ 压缩后的潜在向量,唯一缓存的东西 $d_c = 512$($= 4d_h$)
$W^{DKV}$ 下投影(D = down) $d_c \times d$
$W^{UK}, W^{UV}$ 上投影(U = up),还原出全部头的 K、V $n_h d_h \times d_c$
$n_h, d_h$ 头数、每头维度 128、128

"联合"是指 K 和 V 从同一个 $c$ 还原,不是各压一份。Q 也做了类似的压缩($d_c' = 1536$),但论文说明那只是为了省训练时的激活显存,和 KV cache 无关。

机制二:权重吸收——推理时根本不还原

如果推理时真要先用 $W^{UK}$ 把 c 还原成 128 个头的 K,那省下的只是显存,计算一点没少。关键在于矩阵乘法的结合律。看第 i 个头的打分(先忽略 RoPE):

$$q_i^\top k_{j,i} = \big(W^{UQ}_i c_t^Q\big)^\top \big(W^{UK}_i c_j^{KV}\big) = c_t^{Q\top}\,\underbrace{\big(W^{UQ\top}_i W^{UK}_i\big)}_{\text{可以预先乘好}}\,c_j^{KV}$$

中间那个矩阵和 token 无关,部署前乘好即可。于是 query 直接被投影到 512 维的潜在空间,和缓存里的 c 直接点积,K 从来不需要显式算出来。V 那边同理,$W^{UV}$ 并进输出投影 $W^O$。论文附录 C 的说法是把 $W^{UK}$ 吸收进 $W^{UQ}$、把 $W^{UV}$ 吸收进 $W^O$。

机制三:解耦 RoPE——吸收为什么会被 RoPE 打断

回到 2.8 结尾那句"RoPE 作用在 K 上"。带上 RoPE 之后:

$$\big(R_t W^{UQ}_i c_t^Q\big)^\top \big(R_j W^{UK}_i c_j^{KV}\big) = c_t^{Q\top}\, W^{UQ\top}_i \,\underbrace{R_{j-t}}_{\text{随位置变}}\, W^{UK}_i\, c_j^{KV}$$

旋转矩阵夹在两个投影中间,而且随相对位置变化,没法预先乘成一个固定矩阵。论文原话的意思是:一个与当前 token 位置相关的 RoPE 矩阵会夹在 $W^Q$ 和 $W^{UK}$ 之间,而矩阵乘法不满足交换律。硬做的话,每生成一个 token 都得把整个前缀的 K 重新算一遍。

DeepSeek 的解法是把位置信息拆到一条单独的小通道(式 (14)~(17)):

$$q_{t,i} = [\,q_{t,i}^{C};\; q_{t,i}^{R}\,], \qquad k_{t,i} = [\,k_{t,i}^{C};\; k_t^{R}\,], \qquad k_t^R = \text{RoPE}(W^{KR} h_t)$$

部分 维度 带 RoPE? 能吸收? 缓存
$k^C$(内容) 128 / 头 否 ✅ 存 c(512 维,所有头共用)
$k^R$(位置) $d_h^R = 64$ 是 ❌ 单独存,所有头共用一份

于是每个 token 每层只缓存 $d_c + d_h^R = 512 + 64 = 576$ 个数。位置那一份 $k^R$ 是所有头共享的——它本身就是一个 MQA。(DeepSeek-V2/V3 用 YaRN 扩长上下文时,也只对这条 $k^R$ 通道做缩放,见 2.9。)

账:每 token 每层缓存多少个数

DeepSeek-V2 论文表 1($l$ = 层数,单位是元素个数,与存储精度无关):

方案 每 token 缓存 能力(论文评价)
MHA $2n_h d_h l$ 强
GQA $2n_g d_h l$ 中
MQA $2d_h l$ 弱
MLA $(d_c + d_h^R)\,l \approx \tfrac{9}{2}d_h l$ 更强

$576 = 4.5 \times 128$,相当于只有 2.25 组的 GQA。论文的说法是:cache 只相当于 2.25 组 GQA,性能却比 MHA 还强。

换成具体模型(bf16,每元素 2 字节):

模型 每层每 token 缓存元素 层数 每 token KV cache
Gemma 2 27B(GQA-16) $2 \times 16 \times 128 = 4096$ 46 368 KiB
DeepSeek-V3 若用 MHA $2 \times 128 \times 128 = 32768$ 61 3.81 MiB
DeepSeek-V3(MLA) 576 61 68.6 KiB

V3 的总参数是 Gemma 2 27B 的 25 倍,每 token 的 KV cache 却只有它的 1/5.4;和同尺寸 MHA 比是 1/57。这就是"再压一个数量级"的意思。(68.6 KiB 和 DeepSeek 自己在 ISCA 2025 论文里给的 70.272 KB 一致,后者按 1 KB = 1000 B 计。)

⚠️ 那个 93.3% 不全是 MLA 的功劳。 DeepSeek-V2 摘要说相对 DeepSeek 67B "KV cache 减少 93.3%"。但论文同时提到部署时把 KV cache 的每个元素平均压到 6 bit。按两者的 config 自己算(推论,论文没有这样拆):

每 token 元素数 字节
DeepSeek 67B(95 层,GQA-8) 194,560 389,120(bf16)
DeepSeek-V2(60 层,MLA) 34,560 25,920(6 bit)

只看元素个数,减少 82.2%;再算上 6 bit 量化,减少 93.3%。所以 93.3% 应该是 MLA + KV 量化 合起来的结果。

MLA 的质量真的不输 MHA 吗

论文附录 D 的消融:

实验 结论
D.1:7B 稠密模型,1.33T token MHA 明显强于 GQA 和 MQA(MMLU:MQA 37.9 / GQA-8 41.2 / MHA 45.2)
D.2:小 MoE(~16B)和大 MoE(~250B) MLA 比 MHA 好,cache 只有 MHA 的 14% 和 4%(MMLU:48.7 → 50.0;57.5 → 59.0)

⚠️ 不是每项都赢:小 MoE 上 C-Eval MLA 略低(51.6 → 50.9)。到 V3 报告里,措辞也收成了"与标准 MHA 性能相当"。所以稳妥的说法是和 MHA 打平或略好,而不是全面超越。

为什么压缩比共享更好:一个表达力的论证

TransMLA(Meng et al. 2025)证明了:在 KV cache 相同的前提下,任何 GQA 都能写成 MLA,反过来不行。直觉是 GQA 的 K 必须对组内每个头一模一样,而 MLA 只要求所有头的 K 都落在同一个 512 维子空间里,每个头可以取不同的线性组合。GQA 是 MLA 的一个特例(上投影矩阵取成"复制"的那种)。

接 2.6 机制二的说法:GQA 砍的是 key 子空间的总维度;MLA 砍的是缓存的维度,但每个头看到的 key 仍然各不相同。

代价:推理变成算力密集

吸收之后,128 个 Q 头全都和同一个 576 维的 c(以及共享的 $k^R$)做点积——推理时的形态相当于一个 head_dim 很大的 MQA(这是从上面公式推出的结构,不是论文原话)。每个头每步要做 576 维而不是 128 维的点积,于是:

它属于架构层,但可以"补票"

2.5 那张表把 MLA 和 GQA 都放在"建模时定"。MLA 也有和 GQA uptraining 类似的补票路线:

方法 做法 报告结果
MHA2MLA(Ji et al. 2025) 部分维度保留 RoPE + 对 K、V 联合做 SVD 初始化 只用原数据量 0.3%~0.6% 微调;Llama2-7B 的 KV cache 减少 92.19%,LongBench 只降 0.5%
TransMLA(Meng et al. 2025) 把 GQA 模型等价改写成 MLA 后再压缩 LLaMA-2-7B 压掉 93% KV cache,8K 长度推理加速 10.6 倍,需约 6B token 微调恢复

⚠️ 以上都是作者自报结果,尚未见独立复现。

归纳

MHA GQA MLA
怎么省 — 头之间共享 K/V 所有头共用一个压缩向量
每个头的 K 各不相同 组内相同 各不相同
和 RoPE 直接兼容 直接兼容 要拆出一条解耦通道
解码瓶颈 带宽 带宽 偏向算力
Gemma 2 / DeepSeek-V3 每 token cache — 368 KiB 68.6 KiB

GQA 是"少存几份",MLA 是"存一份压缩包,用的时候连解压都省掉"。 能省掉解压靠的是矩阵结合律;唯一挡路的 RoPE,被拆成了一条 64 维的旁路。


3FFN

3.1GeGLU 的三个矩阵

原始 Transformer(2017):

$$\text{FFN}(x) = \text{ReLU}(xW_1)\,W_2 \qquad \text{两个矩阵}$$

Gemma 2:

$$\text{FFN}(x) = \big(\underbrace{\text{GELU}(xW_{gate})}_{\text{门}} \odot \underbrace{xW_{up}}_{\text{值}}\big)W_{down} \qquad \text{三个矩阵}$$

⊙ 是逐元素相乘。多出来的"门"用来动态决定每个通道放行多少。

两点注意:

⚠️ 73728 vs 36864:论文表格里 27B 的 Feedforward dim 写 73728,是把 gate 和 up 两个并行投影加在一起报的(2 × 36864);HF config 的 intermediate_size 是单个投影的 36864。看到门控结构(GeGLU/SwiGLU)时,论文报的 FFN 维度要留意是不是已经乘了 2。

gate / up / down 分别在干嘛

GeGLU(Gemma)和 SwiGLU(Llama)是同一个结构,只是把 GELU 换成 Swish/SiLU:

矩阵 角色 非线性?
W_up x 投影成"要写入的内容" 无
W_gate x 投影成"每个通道该开多大",过 GELU 后变成软性阀门 有(GELU)
W_down 把"阀门 × 内容"压回 d_model,写回残差流 无
        ┌── W_gate ──→ [GELU] ──┐
        │                       ⊙ ──→ W_down ──→ FFN(x)
   x ───┴── W_up ────────────────┘

⊙ 左边是 gate(36864 维,每个数经过 GELU 后大致落在"关"到"原样放行"之间),右边是 up(36864 维,未经非线性的原始内容)。逐元素相乘之后,content 里没被对应通道 gate 打开的部分直接被乘成接近 0——这就是"门"字的来源。W_down 把这 36864 维再投影回 4608,和原始 x 相加写回残差流(见 4.7)。

3.2FFN 是一张 key-value 查找表

先把"按列/行拆开"这一步讲清楚,它不是比喻,是矩阵乘法定义的直接展开。 用简化的两矩阵版本 FFN(x) = act(xW₁)W₂ 举例:xW₁ 是 x(1×4608)乘一个 4608×36864 的矩阵,结果是 36864 个数——按矩阵乘法的定义,第 i 个数恰好就是 x 和 W₁ 第 i 列的点积。把这一列单独记作 kᵢ:

$$(xW_1)_i = x \cdot k_i$$

同样,act(xW₁) 这 36864 个数再乘 W₂(36864×4608)得到最终输出,而矩阵乘法本身就是"每一行乘一个系数、再全部加起来"——W₂ 的第 i 行(记作 vᵢ)恰好被第 i 个激活值加权求和:

$$\text{act}(xW_1)\,W_2 = \sum_{i=1}^{36864} \text{act}(x\cdot k_i)\cdot v_i$$

整理成下面这个形式:

$$\boxed{\text{FFN}(x) = \sum_{i=1}^{36864} \underbrace{\text{act}(x \cdot k_i)}_{\text{匹配度}} \cdot \underbrace{v_i}_{\text{写入内容}}}$$

为什么这就是"查表":把 x·kᵢ 想成"x 跟第 i 个模式的匹配程度"——两个向量方向越接近,点积越大。act(GELU/ReLU)的作用是过滤:匹配不上的(点积为负或很小),act 直接压成 0;匹配上的,act 放行。所以每一项 act(x·kᵢ)·vᵢ 要么是 0(这次没参与),要么是"匹配强度 × vᵢ"(把 vᵢ 这份内容按匹配强度加进输出)。8 个神经元的示意(真实是 36864 个):

神经元 i act(x·kᵢ)(匹配强度) 贡献
1 0.02 ≈0,无论 v₁ 是什么都乘没了
2 0.05 ≈0
3 0.91 命中,v₃ 按 0.91 加进输出
4 0.01 ≈0
5 0.03 ≈0
6 0.78 命中,v₆ 按 0.78 加进输出
7 0.02 ≈0
8 0.01 ≈0

每个中间神经元就是一个 (key, value) 对:

是什么 存在哪
k_i(键) 模式探测器 — "当前状态像不像 XX" W_gate/W_up 的第 i 列
v_i(值) 匹配上就往残差流写这个 W_down 的第 i 行

这也是为什么单个神经元经常能被解读出"人能看懂的模式"(Geva et al. 2021 逐个检查发现浅层对应句法、深层对应语义主题,见附录 D):它就是一个专职的模式探测器,命中了就往外写一段固定内容。

规模:36864 槽/层 × 46 层 = 1,695,744 个记忆槽,每槽 3 个 4608 维向量,1.7M × 13824 = 23.4B ✓ 正好是 FFN 参数量。

与 attention 的对偶:

$$\text{Attention}(x) = \sum_j \alpha_j v_j \qquad\qquad \text{FFN}(x) = \sum_i \beta_i v_i$$

Attention FFN
key/value 从哪来 当前上下文算出来 训练时学好的权重
有多少个 随句长变(t 个) 固定 36864 个
权重归一 softmax,和为 1,竞争 逐元素激活,不竞争
检索什么 刚才说过的话 训练语料里的世界

attention 是对上下文的检索,FFN 是对训练数据的检索。

3.3非线性的两种类型

激活函数(ReLU/GELU) Softmax
位置 FFN 中间 attention 权重、最终输出层
逐元素? ✅ 每个数独立处理 ❌ 要看整行所有数
目的 变换特征 归一化成概率
输出约束 无 每行和 = 1,全为正

什么是线性,什么是非线性

一个函数 f 是线性的,当且仅当同时满足:

$$f(a+b) = f(a) + f(b) \qquad(\text{可加性}) \qquad\qquad f(c\cdot a) = c\cdot f(a) \qquad(\text{齐次性})$$

矩阵乘法 y=Wx 天生满足这两条——这是矩阵乘法自带的分配律,对任何矩阵 W 都成立:W(a+b)=Wa+Wb,W(ca)=cWa,不需要额外证明。

为什么两层线性等于一层:把两层串起来 y=W₂(W₁x),矩阵乘法满足结合律,括号可以随便挪:

$$y = W_2(W_1x) = (W_2W_1)x = Wx \qquad W = W_2W_1 \text{ 就是另一个矩阵}$$

不管中间插几层线性层,效果都只是某一个矩阵——堆 46 层纯线性层,全部乘在一起还是一个矩阵,深度对函数的表达能力没有任何贡献。这是"为什么必须有非线性"的第一层原因。

非线性到底破坏了什么:非线性就是不满足上面可加性那条的函数。用 ReLU 代入具体数字:

算式 结果
取 a=1, b=−1 a+b 0
先加再过 ReLU ReLU(a+b) = ReLU(0) 0
先过 ReLU 再加 ReLU(a)+ReLU(b) = 1+0 1

0 ≠ 1,可加性不成立——ReLU 不是线性函数。正因为这条等式不成立,ReLU(以及 GELU、softmax)没法被提前合并成一个矩阵,每插入一次非线性,函数族就真正变大了一圈,而不是原地打转。

几何上:线性只能拉伸,非线性才能折叠。线性变换(旋转、缩放、切变)有一条铁律:原点不动,直线还是直线,平行线还是平行线——堆多少层线性变换,空间顶多被拉伸旋转压扁,永远不会"打折"。但很多真实的分类边界恰恰是弯的,经典例子是 XOR:

x₁ x₂ 类别
0 0 A
0 1 B
1 0 B
1 1 A

把 x₁ 当横轴、x₂ 当纵轴画出这四个点,A 类落在左下和右上两个对角,B 类落在左上和右下两个对角——任何一条直线,两侧都会同时踩到 A 和 B,平面上不存在能分开它们的直线。但如果先经过一次非线性"折叠"(隐层在干的事),把同类的点拉到一起、异类的点推开,折叠后的空间里一条直线就够用了。这正是"万能近似"直觉的来源:非线性负责折叠、线性负责拉伸组合,理论上能拼出任意复杂的决策边界;没有非线性,不管多少层线性层加起来,能表达的东西永远只是"一次拉伸+旋转"那么多。

整个 block 的非线性清单:

组件 非线性
RMSNorm 有(除以自身范数)
QKᵀ → softmax 有(softmax + Q、K 都来自 x,本身二次)
FFN 有(GELU + 门控相乘)
全部权重矩阵 无,纯线性

带参数的部分全是线性的,非线性全在不带参数的地方。

3.4为什么必须交替

去掉 FFN 只堆纯注意力,输出会双指数级塌缩成秩 1(Dong et al. 2021, Attention is not all you need),所有 token 表示趋同。拆成三步看这是怎么发生的。

第一步:attention 的输出本质是加权平均。见 2.3,softmax 保证每行权重和为 1、全部非负——这正是"加权平均"的定义。一个 token 新的表示,是它自己和其他 token 的 value 向量按某种权重混合出来的,混合结果不可能比参与混合的向量更"极端",只会落在它们中间。

第二步:反复平均会把差异越抹越平。关键直觉:平均是一种收缩——两个数取平均,结果一定比这两个数原本的差距更近;反复平均,差距会越缩越小。46 层纯注意力,等于对同一批向量反复做加权平均 46 次,每做一次,token 之间残留的差异就被削掉一部分。

第三步:差异归零 = 矩阵的秩塌缩成 1。秩衡量的是一组向量里"真正不同的方向"有几个。如果 t 个 token 的表示两两之间的差异都被磨掉,最后所有行都变成同一个方向上的(近似)倍数——这个 t×d 矩阵的秩就塌缩到了 1。此时不管序列里原本有多少个不同的 token,模型能读出的信息只剩"一个平均方向",谁是谁已经分不清了。

⚠️ "双指数"具体多快:普通的指数衰减是"每层固定打个折",比如每层剩 90%,46 层后是 0.9⁴⁶≈0.008,已经很小;论文证明的塌缩比这更狠——收缩的比例本身也在随层数加速变小,数学形式接近 exp(−exp(层数)),也就是"指数的指数"。这是一个已证明的上界,不是拍脑袋的类比,具体推导见原论文。

FFN 的非线性和残差连接正是阻止塌缩的东西——FFN 逐位置独立处理(不做跨 token 的平均),非线性又能把被拉近的表示重新推开;残差连接则保证每层都有一条不经衰减的直通路径(见 5.4)。"交替使用"不是随意选择,是必需的。

3.5FFN 才是大头

参数占比
FFN 86.1%
Attention 9.6%

FFN : Attention ≈ 9 : 1。Transformer 论文叫《Attention Is All You Need》,但真正装参数的是那个平平无奇的 MLP。

原因是宽度:FFN 中间层 36864 是 d_model 的 8 倍(4 倍 × gate/up 并行),attention 内部宽度只有 4096,还不到 d_model。

这也是为什么 MoE(见 3.6)、剪枝、量化(见 9.9)的研究都盯着 FFN 下手——那里才是肉。

3.6MoE:把一个 FFN 拆成很多个,每个 token 只走几个

一句话:MoE(Mixture of Experts)把每层的一个大 FFN 换成 $N_E$ 个 FFN(专家),再加一个路由器,每个 token 只送给打分最高的 k 个专家。参数量随 $N_E$ 涨,每个 token 的计算量只随 k 涨。

接 3.2 的查找表视角最好理解。 FFN 是 36864 个 (key, value) 记忆槽,3.2 那张表里每次真正"命中"的只是少数,其余槽位的激活接近 0,算了也白算。MoE 把这个观察推到结构层面:把槽位分成很多组,每组一个专家,先猜哪几组会命中,只算那几组。

结构

              ┌→ 专家 1 (FFN) ─┐
              ├→ 专家 2 (FFN) ─┤
x ──→ 路由器 ─┼→   ...         ├─ 按门控权重加权求和 ──→ 输出
  (选 top-k)  ├→ 专家 N_E (FFN)┤
              └  只有被选中的 k 个真的计算

$$\text{MoE}(x) = \sum_{i \in \text{TopK}(s(x),\,k)} g_i(x)\cdot \text{FFN}_i(x), \qquad s(x) = \text{softmax}(x W_r)$$

符号 含义
$W_r$ 路由器,一个 $d \times N_E$ 的矩阵,给每个专家打分
TopK 选出分数最高的 k 个专家
$g_i$ 门控权重,一般是被选中专家的分数(Mixtral 对选中的 k 个再做一次 softmax,DeepSeek-V3 用 sigmoid 打分后在选中的专家间归一化)

Attention、归一化、残差都不变,只有 FFN 被换掉。这和 3.5 的"那里才是肉"对得上:参数大头在 FFN,扩容也就扩那里。

演化

模型 专家数 每 token 激活 总参数 激活参数 出处
Shazeer et al. 2017 最多数千(分层 MoE) k(带噪声 top-k) MoE 层最多 137B — LSTM 时代
GShard(2020) 2048 2 600B — 翻译
Switch-C(2021) 2048 1 1.6T — T5 系
Mixtral 8x7B(2024) 8 2 47B 13B
DeepSeek-V3(2024) 256 路由 + 1 共享 8 + 1 671B 37B
Qwen3-235B-A22B(2025) 128 8 235B 22B 无共享专家

Mixtral 的总参数是 47B 而不是 8×7B=56B,原因是只有 FFN 被复制成 8 份,attention、embedding 等参数各层只有一套(这是按结构推算的,论文只给了 47B / 13B 两个数)。

路由器是怎么学的

路由器 $W_r$ 和其他权重一起端到端训练,梯度经 $g_i$ 流回 $W_r$:哪个被选中专家的输出让 loss 降得多,它的分数就被推高。⚠️ TopK 这一步不可导,没被选中的专家拿不到这个 token 的梯度,路由器也得不到"如果当时选了别的专家会怎样"的信号。这正是下一节负载均衡问题的根源。

Shazeer 2017 的做法是在打分上加可学习幅度的高斯噪声再取 top-k(noisy top-k gating),让没被选中的专家也有机会被试到。

DeepSeek 的两个结构改动(DeepSeekMoE,Dai et al. 2024):

改动 做法 目的
细粒度切分 把 N 个专家每个切成 m 份,变成 mN 个小专家,激活数同比例变成 mK 计算量不变,可选的组合数暴增,专家分工更细
共享专家隔离 单独留出几个专家,每个 token 都过 存通用知识,路由专家不必各自重复存一份

Qwen3 MoE 则明确不用共享专家,说明这一条还不是共识。

和推理的关系见 9.4:FLOPs 按激活参数算,显存和读权重的带宽按总参数算,所以 MoE 小 batch 解码特别吃亏。

3.7负载均衡:为什么路由会塌,以及怎么防

一句话:路由器有"富者愈富"的倾向,几个专家吃掉大部分 token,其余专家饿死。传统做法是加辅助损失惩罚不均衡,代价是干扰主任务;DeepSeek-V3 改成给每个专家一个只影响"选谁"、不进 loss 的偏置,按负载调。

塌缩是怎么发生的

Shazeer et al. 2017 的原话大意是:这种不均衡会自我强化,被偏爱的专家训练得更快,于是更容易被门控网络选中。和 5.5 的稀疏梯度是同一个逻辑:没被选中就没梯度,没梯度就不进步,不进步就更不会被选中。

层面 后果
模型质量 大半专家形同虚设,等于白付了参数
系统 专家分布在不同 GPU 上(专家并行),热门专家所在的卡排长队,其余卡空转

办法一:辅助负载均衡损失

Switch Transformer 的版本最常见($N_E$ 个专家,一个 batch 有 T 个 token):

$$\mathcal{L}_{\text{aux}} = \alpha \cdot N_E \cdot \sum_{i=1}^{N_E} f_i \cdot P_i, \qquad f_i = \frac{1}{T}\sum_{x} \mathbb{1}\{\arg\max p(x) = i\}, \qquad P_i = \frac{1}{T}\sum_{x} p_i(x)$$

符号 含义
$f_i$ 这个 batch 里实际被分给专家 i 的 token 比例
$P_i$ 路由器给专家 i 的平均概率
$\alpha$ 系数,论文全文取 $10^{-2}$(扫过 $10^{-1}$ 到 $10^{-5}$)

为什么要两个量相乘:$f_i$ 来自 argmax,不可导;$P_i$ 来自 softmax 的平均,可导。乘起来后梯度只经 $P_i$ 流动,$\partial\mathcal{L}/\partial P_i = \alpha N_E f_i$——实际接 token 越多的专家,路由器给它的概率被压得越狠。完全均匀时 $\sum f_iP_i = N_E\cdot\frac{1}{N_E}\cdot\frac{1}{N_E} = \frac{1}{N_E}$,乘上 $N_E$ 正好等于 $\alpha$,这就是那个 $N_E$ 的作用:让损失值不随专家数变化。

更早的版本:Shazeer 2017 用"重要性"(每个专家收到的门控权重之和)的变异系数平方当损失;GShard 用的是同样"不可导的计数 × 可导的平均门控"的乘积结构。

⚠️ 代价:这个损失和语言建模无关,它的梯度会和主任务梯度打架。$\alpha$ 大了伤质量,小了压不住塌缩。

办法二:容量因子(capacity factor)

即使有辅助损失,单个 batch 里还是会有专家超载。每个专家设一个上限:

$$\text{专家容量} = \frac{\text{batch 内 token 数}}{N_E} \times \text{容量因子}$$

容量因子 = 1 表示刚好平均分;1.25 就留 25% 余量。超出容量的 token 被丢弃(token dropping):这一层不处理它,直接经残差连接原样传到下一层。

这是硬件逼出来的设计:GPU 上张量形状要预先固定,每个专家的输入缓冲区必须是固定大小。DeepSeek-V2 把这个思路放到设备级:每个 token 最多发往 3 张卡(device-limited routing),另加设备级、通信级两个均衡损失,训练时按设备容量丢 token。

办法三:DeepSeek-V3 的无辅助损失均衡

Wang et al. 2024 提出,DeepSeek-V3 采用。给每个专家一个偏置 $b_i$,只在选 top-k 时加上:

$$g'_{i,t} = \begin{cases} s_{i,t}, & s_{i,t} + b_i \in \text{TopK}\big(\{s_{j,t} + b_j\},\, K_r\big) \\ 0, & \text{否则} \end{cases}$$

注意门控值用的仍是原始分数 $s_{i,t}$,偏置只决定选谁,不影响加权多少,也不进 loss。

每个训练步结束后按负载调偏置:超载的专家 $b_i$ 减 γ,欠载的加 γ。DeepSeek-V3 取 γ = 0.001(前 14.3T token),最后 500B token 设为 0。

辅助损失 偏置调节
怎么起作用 往总 loss 里加一项 只改"选谁"
干扰主任务梯度 有 没有
怎么调 梯度下降 固定步长的反馈规则(像一个恒温器)

Wang et al. 的原话大意是:辅助损失太大会引入不可忽视的干扰梯度,损害模型性能。他们在 1B、3B 规模上用 MaxVio(最大负载超出平均负载的比例)衡量均衡度,偏置法在均衡和困惑度上都更好。

DeepSeek-V3 的其他配套:

设计 取值
路由打分 sigmoid(而非 softmax),选中的 8 个再归一化
序列级辅助损失 仍保留,系数 α = 0.0001(极小),防单条序列内极端不均衡
节点限制 每个 token 最多发往 4 个节点
token dropping 训练和推理都不丢

⚠️ 一个容易想到的替代方案是专家选 token(Expert Choice,Zhou et al. 2022):反过来让每个专家挑自己最想要的 k 个 token,天然完全均衡。但专家要看到整批 token 才能挑,包括未来的 token,作者自己在局限一节承认它不能直接用于自回归生成,Wang et al. 也指出它会破坏因果约束。所以 decoder-only 大模型基本还是 token 选专家。

负载均衡的难点在于:均衡是系统的要求,不是建模的目标。 把它塞进 loss 就会和建模目标打架;DeepSeek-V3 的做法是把它从 loss 里拿出来,交给一个不走梯度的反馈规则。

稳定性的另一个技巧:router z-loss(ST-MoE,Zoph et al. 2022):

$$L_z = \frac{1}{B}\sum_{i=1}^{B}\Big(\log\sum_{j=1}^{N_E} e^{x_j^{(i)}}\Big)^2$$

惩罚路由器 logits 的 log-sum-exp,把 logits 压小,系数取 0.001。动机是数值越大、舍入误差越大(论文指出 bf16 的舍入误差最坏可比 float32 大 65536 倍),路由器 logits 一大就容易引发不可恢复的训练不稳——和 9.7 的"减最大值防溢出"同属数值问题。Switch Transformer 的对策更直接:只在路由器内部用 float32。


4归一化与残差流

4.1LayerNorm 公式逐项拆解

$$\text{LN}(x) = \gamma \odot \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta$$

对一个 token 的向量 $x \in \mathbb{R}^{4608}$:

项 是什么 形状
$\mu = \frac{1}{d}\sum_i x_i$ 这 4608 个数的均值 标量
$\sigma^2 = \frac{1}{d}\sum_i (x_i-\mu)^2$ 同一批数的方差 标量
$x - \mu$ re-centering:平移到均值 0 向量
$\div\sqrt{\sigma^2+\epsilon}$ re-scaling:缩放到标准差 1 —
$\epsilon$ 数值保护,典型 $10^{-6}$ 标量
$\gamma$ 可学习的逐维缩放,初始 1 4608
$\beta$ 可学习的逐维偏移,初始 0 4608

$\epsilon$ 不是摆设:若某 token 的 4608 个数恰好全相等,$\sigma = 0$,直接除零。

⚠️ 先澄清归一化到底约束了什么。$\mu$、$\sigma$ 是对一个 token 的 4608 个数求的,所以约束只有两条标量条件:

$$\sum_{i=1}^{d} \hat x_i = 0, \qquad \|\hat x\| = \sqrt{d}$$

这是对整个向量的约束,不是对每一维各自的约束。 单看第 3 维在不同 token 上是什么分布,LayerNorm 完全没管。反例:

token 原始 归一化后
A $[1,\ 5,\ 3]$ $[-1.225,\ 1.225,\ 0]$
B $[5,\ 1,\ 3]$ $[1.225,\ -1.225,\ 0]$

第 1 维取到 $\mp1.225$(方差很大),第 3 维两次都是 $0$(方差为零)——两维分布完全不同。所以说"每维被压成同样的分布"是错的;沿 batch 轴逐维标准化的是 BatchNorm,不是 LN。

那 $\gamma$ 在干什么:归一化把整个向量的总幅度锁死成 $\sqrt d$——这是一份全局预算。$\gamma$ 是 4608 维的向量(不是标量),决定这份预算怎么在各维度间分配:

归一化之后:  [ ?, ?, ?, ..., ? ]      ← 总长度被锁成 √d
                ↓ 乘 γ(逐维)
              [ 大, 小, 中, ..., 大 ]   ← 决定各维在残差流里的增益

用 4.7 Pre-LN 那段的话说:$\gamma$ 控制这一层往残差流写入的东西的形状和强度。这也解释了 Gemma 为什么把 $\gamma$ 初始化为 0(写成 $1+\gamma$)——默认"不改变分配"。

⚠️ 关于"能恢复成恒等映射"这个常见说法

代入 $\gamma = \sigma$、$\beta = \mu$ 确实得到恒等:

$$\sigma \cdot \frac{x-\mu}{\sigma} + \mu = (x-\mu) + \mu = x$$

但这个论证有漏洞——$\gamma$ 和 $\sigma$ 根本不是一回事:

是什么 什么时候确定
$\sigma$ 当前这个 token 算出的标准差 每个 token 都不同,前向时现算
$\gamma$ 训练学到的固定参数 所有 token 共用一组

$\gamma = \sigma$ 只能对某一个特定 token 成立;换个 token,$\sigma$ 变了而 $\gamma$ 没变,恒等就不成立。

准确的说法:LN 能恢复的是"全局平均意义上"的尺度,不是逐 token 的原始尺度。逐 token 的那个 $\sigma$ 被永久丢弃了,$\gamma$ 找不回来。

那归一化到底改变了什么

⚠️ 先排除一个常见误解:残差流本身从来没有被归一化过。被 norm 处理的只是送进支路的那份拷贝——

x ─┬────────────────────────────→ (+) ── x'   ← 主干:从未被 norm 碰过
   │                               ↑
   └─→ LN ─→ F ─→ [post-norm] ────┘           ← 支路:norm 在这里

这正是本节后面"Pre-LN 的代价"那段的前提:因为没东西压主干,$\|x_L\|$ 才会按 $\sqrt L$ 涨,末尾才需要补 final norm。

归一化真正保证的是:每一层的支路 $F$ 拿到的输入,幅度恒定为 $\sqrt d$(这就是 RMSNorm 的 0 次齐次性质)。对照来看:

支路 $F$ 拿到的输入幅度 后果
没有归一化 跟着 $\|x_l\|$ 走,逐层漂移,可能爆炸也可能消失 $F$ 的权重要去适应一个移动的靶子
有归一化 恒定 $\sqrt d$,再由 $\gamma$ 显式缩放 $F$ 面对稳定输入,写进残差流的增量受控

这是一次解耦。norm 把"幅度"这个自由度从 $F$ 手里夺走,交给 $\gamma$:

谁决定方向 谁决定幅度
无 norm $F$ 的权重 $F$ 的权重(同一批参数)
有 norm $F$ 的权重 $\gamma$(独立参数,有自己的梯度)

没有 norm 时,幅度是一长串运算的涌现产物——没有任何一个参数"负责"它。想调小第 30 层的贡献?只能去动 $F$ 里的矩阵,但那些权重同时决定着输出的方向,两件事纠缠在一起。

有 norm 时,模型在训练中会明确地问"这一层该往传送带上写多重的东西",然后把答案存进 $\gamma$。

区别是:每层贡献的幅度从"训练的副作用"变成了"训练的目标"。

一个可验证的推论:如果这说法成立,训练完的 $\gamma$ 分布就该携带信息——各层学到的值不该雷同。事实确实如此,不同层的 norm 权重差别很大,深层往往学出更小的值("我这层少写一点"),而且这个分布可以直接当剪枝依据——$\gamma$ 接近 0 的层贡献本就微弱,剪掉损失小。

⚠️ 关于 weight decay:$\gamma$ 的价值在于尺度成了显式参数,你可以选择约束它、也可以选择不约束——而不是说实践中真的对它施加了 decay。恰恰相反,主流训练代码通常把 norm 参数排除在 weight decay 之外(no_decay = ['bias', 'norm', ...]),因为标准写法下 $\gamma$ 初始化为 1,往 0 拉等于抹掉这层输出。Gemma 的 $(1+\gamma)$ 参数化从根上解决了这个冲突(见本节后面)。

一个硬证据:如果 $\gamma$、$\beta$ 真是可有可无的补丁,RMSNorm 应该把它们一起砍掉。但事实是它砍掉了 $\beta$,保留了 $\gamma$——Zhang & Sennrich 消融发现 $\beta$ 可以不要,$\gamma$ 不行。逐维缩放是必需的,逐维偏移不是。

4.2几何图像:投影与缩放

用 3 个数代替 4608 个,取 $x = [1, 5, 3]$:

步骤 结果
$\mu = (1+5+3)/3$ 3
$x - \mu$ $[-2,\ 2,\ 0]$
$\sigma^2 = (4+4+0)/3$ 2.667,$\sigma = 1.633$
除 $\sigma$ $[-1.225,\ 1.225,\ 0]$

输出向量的长度(各分量平方和开根):$\sqrt{1.5+1.5+0} = \sqrt3 = 1.732 = \sqrt{d}$

换几组输入试:

输入 输入长度 输出 输出长度
$[1, 5, 3]$ 5.92 $[-1.225, 1.225, 0]$ 1.732
$[10, 50, 30]$ 59.2 同上 1.732
$[101, 105, 103]$ 178.0 同上 1.732

输入长度差 30 倍,输出长度全都一样。 几何上是两步截然不同的操作:

LayerNorm 的两步:左为减 μ 的垂直投影(方向改变),右为除 σ 的沿原方向缩放(方向不变)
LayerNorm 的两步:左为减 μ 的垂直投影(方向改变),右为除 σ 的沿原方向缩放(方向不变)
步骤 几何操作 方向
减 μ 垂直投影到"分量和为 0"的超平面 ❌ 改变
除 σ 沿自身方向缩放到半径 $\sqrt d$ 的球面 ✅ 不变

⚠️ 常见误解:除 σ 不是投影。投影是垂直压到某个平面上(只有减 μ 是),除 σ 只是沿着向量自己的方向伸缩。LayerNorm 会改方向,全是第一步干的——这也是它和 RMSNorm 的唯一实质差别。

为什么 $\mathbf{1}$ 垂直于那个超平面:点积就是求和。

$$[a,b,c] \cdot [1,1,1] = a+b+c = 0 \;\Longrightarrow\; \text{垂直}$$

$\mathbf 1$ 这个方向代表"所有分量一起变大变小",也就是整体的直流偏置。LayerNorm 认为它不重要,扔掉。

"落在球面上"是什么意思:球面就是到原点距离相等的所有点(二维叫圆,4608 维还叫球面)。关键在于不管输入是什么,输出长度永远是同一个数 $\sqrt d$,所以所有可能的输出都落在同一个球面上,只是方向不同。

因为第一步已经把向量压到超平面里了,第二步只在这个平面内改长度。所以最终输出落在平面与球面的交集上:3 维时是一个圆,4608 维时是个 4607 维球面。(RMSNorm 没有第一步,输出直接落在整个 4608 维球面上。)

长度为什么恰好是 $\sqrt d$

$$\|\hat x\|^2 \;\overset{\text{①}}{=}\; \sum_i \frac{(x_i-\mu)^2}{\sigma^2} \;\overset{\text{②}}{=}\; \frac{d\sigma^2}{\sigma^2} \;\overset{\text{③}}{=}\; d$$

① 代入定义:$\hat x_i = \frac{x_i-\mu}{\sigma}$,长度平方就是各分量平方和。

② 关键一步:$\sigma$ 是标量,可以提到求和外;而分子那个求和恰好是方差乘 $d$——

$$\sigma^2 = \frac{1}{d}\sum_i (x_i-\mu)^2 \quad\Longrightarrow\quad \sum_i (x_i-\mu)^2 = d\,\sigma^2$$

③ 约分:$\sigma^2$ 上下抵消,得 $\|\hat x\| = \sqrt d$。

看穿了其实是同义反复:$\sigma$ 就是"到均值的典型距离",而 $\|x-\mu\| = \sqrt d \cdot \sigma$。除以 $\sigma$ 等于用向量自己的长度去量自己(再乘个 $\sqrt d$),结果当然固定。那个 $\sqrt d$ 因子纯粹来自方差定义里的 $\frac1d$——它把求和摊成了平均。

代回 $[1,5,3]$ 验证:$\sum(x_i-\mu)^2 = 4+4+0 = 8$,而 $d\sigma^2 = 3 \times 2.667 = 8$ ✓,故 $\|\hat x\|^2 = 8/2.667 = 3 = d$ ✓

RMSNorm 的版本更直接——分子分母是同一个求和,只差 $\frac1d$:

$$\|\hat x\|^2 = \sum_i \frac{x_i^2}{\text{RMS}^2} = \frac{\sum_i x_i^2}{\frac1d\sum_i x_i^2} = d$$

这也印证了 $\text{RMS}(x) = \|x\|/\sqrt d$。

$\sqrt{4608} \approx 67.9$——这个数在 1.3 出现过。查表取出的原始 embedding 长度只有 1 左右,而残差流上每层加进来的东西都在 67.9 量级;乘 $\sqrt{4608}$ 就是把起点抬到同一量级,免得词本身的信息在第一层就被冲掉。

(2017 原论文给的理由是匹配加性位置编码的幅度;Gemma 用 RoPE 没有加性位置编码,所以理由变成残差流的尺度对齐。数值都是 $\sqrt d$,动机不同。)

4.3RMSNorm

$$\text{RMSNorm}(x) = \gamma \odot \frac{x}{\text{RMS}(x)}, \qquad \text{RMS}(x) = \sqrt{\frac{1}{d}\sum_i x_i^2 + \epsilon}$$

LayerNorm RMSNorm
减均值(re-centering) ✅ ❌
除标准差(re-scaling) ✅ ✅
可学习缩放 γ ✅ ✅
可学习偏移 β ✅ ❌

RMS = Root Mean Square(均方根),名字是倒着念的计算步骤:平方 → 平均 → 开根。它和标准差的唯一区别是减不减 $\mu$,所以 $\mu=0$ 时两者相等。另外 $\text{RMS}(x) = \|x\|/\sqrt d$,只和向量长度差一个常数因子。

恒等关系:当 $\mu = 0$ 时 $\sigma^2 = \frac1d\sum x_i^2 = \text{RMS}(x)^2$——RMSNorm 就是 μ 恰好为 0 时的 LayerNorm。4608 维下 $\mu$ 本来就接近 0,两者数值很接近。

为什么砍得掉:Zhang & Sennrich 2019 消融发现收益几乎全来自 re-scaling。直觉上说得通——让训练崩掉的是幅度爆炸或消失,不是均值漂移。

省了什么

参数:每个 norm 是一个 4608 维的 $\gamma$ 向量(RMSNorm 没有 $\beta$)。Gemma 2 共有 185 个 norm:

$$185 = \underbrace{46 \times 4}_{\text{每层 4 个}} + \underbrace{1}_{\text{final norm}} \qquad 185 \times 4608 = 852{,}480 \approx 0.85\text{M}$$

每层 4 个是因为 pre + post 都有(见 4.7),标准 Transformer 只有 2 个。最后的 +1 是 final norm——Pre-LN 结构里残差流本身从没被归一化过(按 $\sqrt L$ 一路涨),送进 LM head 前必须收一次。若用 LayerNorm 多一个 $\beta$,就是 1.70M。

时间:LN 要过两遍数据(先扫一遍求 $\mu$,再扫一遍用 $\mu$ 求 $\sigma^2$),RMSNorm 只要一遍平方和。而在 memory-bound 的世界里,遍数就是时间。

为什么 norm 是 memory-bound:用 9.4 那个算术强度衡量——每读一个字节能做多少次浮点运算。对一个 4608 维向量做 RMSNorm:

项 量
读入 $x$(bf16) 9,216 B
写出结果 9,216 B
总字节 18,432 B
平方和 + 缩放,约 3 次运算/元素 ~13,824 FLOPs

$$\text{算术强度} = \frac{13{,}824}{18{,}432} \approx \mathbf{0.75}$$

A100 的临界点约 156,差了 200 倍——完全卡在带宽上。作为对比,同层的 FFN 矩阵乘算术强度在几百到几千,是妥妥的 compute-bound。

所以单看 FLOPs,LN 比 RMSNorm 只多"求一次均值",占比小到可忽略;但瓶颈根本不在 FLOPs,少读一遍数据 ≈ 省一半时间。

(实际实现中 LN 常用 Welford 算法或 $E[x^2]-E[x]^2$ 技巧压成一遍,但后者数值稳定性差;即使都是一遍,LN 仍要多维护一个累加器、多做一次减法。)

一个反直觉的推论:norm 只占全模型 0.003% 的参数,FLOPs 占比同样微不足道,但实际耗时占比远高于此。这正是 kernel fusion 存在的理由——把 norm 和相邻矩阵乘融合进一个 kernel,让数据在 SRAM 里就地处理,省掉一次 HBM 往返。FlashAttention、Liger Kernel 这类优化的收益大量来自这里。

4.4雅可比与 0 次齐次

(本节要用商法则和外积,见 11.1、11.2。)

先说符号:$x$ 是输入(进 norm 之前),$\hat x$ 是输出(归一化之后)。帽子 $\hat{\ }$ 表示"经过处理的版本",用同一个字母是故意的——提示这是同一批数据的前后两态。

x  = [ 1,  5,  3 ]        ← 输入,没帽子
        ↓ LayerNorm
x̂ = [-1.225, 1.225, 0]   ← 输出,有帽子

⚠️ 帽子在文档别处含义不同:5.2 的 $\hat y$ 是模型预测值,5.6 的 $\hat m, \hat v$ 是偏差修正后的矩估计。共同点只有"某种处理后的版本"。

雅可比是什么

$$J_{ij} = \frac{\partial \hat x_i}{\partial x_j}$$

读法:第 $j$ 个输入变一点点,第 $i$ 个输出变多少。

普通导数是一个数对一个数。但 norm 是 $d$ 个数进、$d$ 个数出,要问的不是一个问题而是 $d \times d$ 个——排成矩阵就是雅可比。行 = 哪个输出(下标 $i$),列 = 哪个输入(下标 $j$):

对 $x_1$ 求导 对 $x_2$ 求导 对 $x_3$ 求导
$\hat x_1$ 怎么变 $J_{11}$ $J_{12}$ $J_{13}$
$\hat x_2$ 怎么变 $J_{21}$ $J_{22}$ $J_{23}$
$\hat x_3$ 怎么变 $J_{31}$ $J_{32}$ $J_{33}$

为什么必须是矩阵,不能压成向量:因为 norm 的输出互相纠缠。$\hat x_1$ 不只依赖 $x_1$——它要除以 $\sigma$,而 $\sigma$ 是全部 $d$ 个数一起算的。动一下 $x_2$,$\hat x_1$ 也会变,非对角线元素非零。

对比逐元素操作(如 ReLU):$\hat x_1$ 只看 $x_1$,非对角线全是 0,雅可比退化成对角阵,实现上只存对角线即可。norm 不能这么省——这正是 4.1 那个"约束是对整个向量的,不是对每一维各自的"在反向传播里的体现。

推导:三条依赖路径

动一下 $x_j$,通过三条路影响 $\hat x_i = \frac{x_i-\mu}{\sigma}$:

路径 说明 对应最终公式哪一项
① 直接 只有 $i=j$ 时分子里的 $x_i$ 才动 $I$
② 经过 $\mu$ 均值是全体算的,任何 $x_j$ 动它都动 $\mathbf{1}\mathbf{1}^\top$
③ 经过 $\sigma$ 同上 $\hat x\hat x^\top$

下面分五步走完。(为清晰起见略去 $\epsilon$,它是 $10^{-6}$ 量级的防零项,对推导无影响。)

第 1 步:$\dfrac{\partial \mu}{\partial x_j} = \dfrac{1}{d}$

把求和写开:

$$\mu = \frac{1}{d}\big(x_1 + x_2 + \dots + x_j + \dots + x_d\big)$$

对 $x_j$ 求导时只有第 $j$ 项活下来,其余都是常数:

$$\frac{\partial \mu}{\partial x_j} = \frac{1}{d}\cdot 1 = \frac{1}{d}$$

第 2 步:$\dfrac{\partial (x_k - \mu)}{\partial x_j} = \delta_{kj} - \dfrac{1}{d}$

这是后面反复要用的零件。分两块:

$$\frac{\partial x_k}{\partial x_j} = \delta_{kj} = \begin{cases} 1 & k = j \\ 0 & k \ne j\end{cases}$$

这个记号叫 Kronecker delta,就是"只有下标相同才为 1"的紧凑写法。配上第 1 步:

$$\frac{\partial (x_k-\mu)}{\partial x_j} = \delta_{kj} - \frac{1}{d}$$

⚠️ 注意这对所有 $k$ 都非零——即使 $k \ne j$ 也有个 $-\frac1d$。这就是"动一个输入,影响所有输出"的根源,也是雅可比非对角线非零的直接来源。

第 3 步:$\dfrac{\partial \sigma}{\partial x_j} = \dfrac{\hat x_j}{d}$

先对 $\sigma^2$ 求导,外层是平方,用复合函数求导:

$$\frac{\partial \sigma^2}{\partial x_j} = \frac{1}{d}\sum_k 2(x_k-\mu)\cdot\underbrace{\frac{\partial (x_k-\mu)}{\partial x_j}}_{\text{第 2 步}} = \frac{2}{d}\sum_k (x_k-\mu)\Big(\delta_{kj}-\frac{1}{d}\Big)$$

把括号拆开,分成两个求和:

$$\frac{2}{d}\Bigg[\underbrace{\sum_k (x_k-\mu)\,\delta_{kj}}_{\text{(A)}} \;-\; \frac{1}{d}\underbrace{\sum_k (x_k-\mu)}_{\text{(B)}}\Bigg]$$

(A):$\delta_{kj}$ 只在 $k=j$ 时为 1,整个求和塌缩成一项,得 $x_j - \mu$。

(B):这一项恒等于 0——

$$\sum_k (x_k-\mu) = \sum_k x_k - d\mu = d\mu - d\mu = 0$$

因为 $\sum_k x_k = d\mu$ 就是均值的定义。这是整个推导最关键的化简。

于是 $\frac{\partial \sigma^2}{\partial x_j} = \frac{2}{d}(x_j-\mu)$。再从 $\sigma^2$ 回到 $\sigma$,左边同样用复合函数求导:

$$2\sigma\,\frac{\partial \sigma}{\partial x_j} = \frac{2}{d}(x_j-\mu) \quad\Longrightarrow\quad \frac{\partial \sigma}{\partial x_j} = \frac{x_j-\mu}{d\,\sigma} = \frac{1}{d}\cdot\underbrace{\frac{x_j-\mu}{\sigma}}_{=\;\hat x_j} = \frac{\hat x_j}{d}$$

归一化后的向量自己出现在了导数里——这就是最终公式里 $\hat x\hat x^\top$ 的来源。

第 4 步:套商法则

商法则是求分式导数的规则。设 $f = \frac{u}{v}$,其中 $u$ 和 $v$ 都随 $x$ 变:

$$\left(\frac{u}{v}\right)' = \frac{u'v - uv'}{v^2}$$

它不是独立规则,是乘法法则 + 链式法则推出来的。把除法写成乘法 $\frac uv = u\cdot v^{-1}$:

$$\big(u v^{-1}\big)' = u'v^{-1} + u\cdot\underbrace{(-v^{-2}v')}_{\text{链式法则}} = \frac{u'}{v} - \frac{uv'}{v^2} = \frac{u'v-uv'}{v^2}$$

那个减号的直觉:分子变大 → 分式变大(同向,加);分母变大 → 分式变小(反向,减)。比如 $\frac63=2$,分子涨到 7 得 2.33,分母涨到 4 得 1.5——分母的影响天然是反的。

为什么这里必须用商法则:因为分子和分母都随 $x_j$ 变。若 $\sigma$ 是常数,直接 $\frac{u'}{\sigma}$ 就行;但第 3 步算出 $\frac{\partial \sigma}{\partial x_j} \ne 0$,分母自己也在动。

对号入座:

商法则 我们的
$u$ $x_i - \mu$
$u'$ $\delta_{ij} - \frac1d$(第 2 步)
$v$ $\sigma$
$v'$ $\frac{\hat x_j}{d}$(第 3 步)

$$\frac{\partial \hat x_i}{\partial x_j} = \frac{\big(\delta_{ij} - \tfrac1d\big)\sigma - (x_i-\mu)\cdot\frac{\hat x_j}{d}}{\sigma^2}$$

然后是纯代数整理。拆成两项:

$$= \frac{\big(\delta_{ij}-\frac1d\big)\sigma}{\sigma^2} - \frac{(x_i-\mu)\cdot\frac{\hat x_j}{d}}{\sigma^2}$$

第一项上下约掉一个 $\sigma$;第二项把 $\sigma^2$ 拆成 $\sigma\cdot\sigma$,其中一个和 $(x_i-\mu)$ 凑成 $\hat x_i$:

$$= \frac{\delta_{ij}-\frac1d}{\sigma} - \frac{1}{d\,\sigma}\cdot\underbrace{\frac{x_i-\mu}{\sigma}}_{=\;\hat x_i}\cdot\,\hat x_j$$

提出公因子 $\frac1\sigma$:

$$\boxed{\;\frac{\partial \hat x_i}{\partial x_j} = \frac{1}{\sigma}\Big(\delta_{ij} - \frac{1}{d} - \frac{1}{d}\hat x_i\hat x_j\Big)\;}$$

第 5 步:写成矩阵

逐元素 矩阵 第 $(i,j)$ 位是
$\delta_{ij}$ $I$ 对角线 1,其余 0
$\frac1d$(常数,与 $i,j$ 无关) $\frac1d\mathbf{1}\mathbf{1}^\top$ 全部都是 $\frac1d$
$\frac1d\hat x_i\hat x_j$ $\frac1d\hat x\hat x^\top$ 外积,$\frac1d\hat x_i\hat x_j$

$$J^{LN} = \frac{1}{\sigma}\Big(I - \tfrac{1}{d}\mathbf{1}\mathbf{1}^\top - \tfrac{1}{d}\hat x\hat x^\top\Big)$$

$\mathbf 1 = [1,1,\dots,1]^\top$ 和自己做外积,每个元素都是 $1\times1=1$,所以 $\frac1d\mathbf{1}\mathbf{1}^\top$ 只是"每个位置都减 $\frac1d$"的紧凑写法。

RMSNorm:同样流程,少一步

$$r = \sqrt{\frac{1}{d}\sum_k x_k^2}, \qquad \hat x_i = \frac{x_i}{r}$$

没有 $\mu$,第 1、2 步整个跳过——分子的导数直接就是 $\delta_{ij}$。求 $r$ 的导数(对应第 3 步):

$$r^2 = \frac{1}{d}\sum_k x_k^2 \;\Longrightarrow\; 2r\frac{\partial r}{\partial x_j} = \frac{2x_j}{d} \;\Longrightarrow\; \frac{\partial r}{\partial x_j} = \frac{x_j}{d\,r} = \frac{\hat x_j}{d}$$

形式和 $\sigma$ 完全一致(尽管 $\hat x_j$ 的定义不同,这里没减 $\mu$)。代入商法则:

$$\frac{\partial \hat x_i}{\partial x_j} = \frac{\delta_{ij}\cdot r - x_i\cdot\frac{\hat x_j}{d}}{r^2} = \frac{1}{r}\Big(\delta_{ij} - \frac{1}{d}\hat x_i\hat x_j\Big)$$

$$J^{RMS} = \frac{1}{r}\Big(I - \tfrac{1}{d}\hat x\hat x^\top\Big)$$

缺的那一项 $\frac1d\mathbf{1}\mathbf{1}^\top$ 来自"分子里的 $-\mu$",具体说是第 2 步那个 $-\frac1d$。不减均值,这一项就不存在。

数值验证

$x = [1,5,3]$,$d=3$,$\mu=3$,$\sigma=1.633$,$\hat x = [-1.225,\ 1.225,\ 0]$:

量 数值微分 公式
$\partial\mu/\partial x_j$ $[0.3333,\ 0.3333,\ 0.3333]$ $1/d = 0.3333$ ✓
$\partial\sigma/\partial x_j$ $[-0.4082,\ 0.4082,\ 0]$ $\hat x_j/d$ ✓
$\partial r/\partial x_j$ $[0.0976,\ 0.4880,\ 0.2928]$ $\hat x_j/d$ ✓
$\sum_k(x_k-\mu)$ $0.0$ 恒为 0 ✓

完整雅可比的数值微分与公式最大误差 $3.5\times10^{-10}$,纯浮点噪声。

几何含义

项 数学来源 几何含义
$I$ 直接依赖 原样传
$-\frac1d \mathbf{1}\mathbf{1}^\top$ 经过 $\mu$ 扣掉沿 $\mathbf 1$ 的分量
$-\frac1d \hat x\hat x^\top$ 经过 $\sigma$ 扣掉沿 $\hat x$ 自身的分量

减号意味着扣除:梯度里"想让整体一起变大"($\mathbf 1$ 方向)和"想让向量变长"($\hat x$ 方向)这两个分量会被抹掉。因为输出对这两件事本来就不敏感(4.2 那三组输入输出相同),改了也没用。

而 $\frac1\sigma$ 这个前置系数,就是 4.7 讲 Post-LN 梯度衰减时那个关键因子的出处。

两个实用事实

① 实际实现从不显式构造这个矩阵。 $4608 \times 4608$ 存下来要 42 MB(fp32),而且没必要——$J^\top g$ 可以用几个向量点积算出来,$O(d)$ 而非 $O(d^2)$。这个公式是用来理解的,不是用来算的。

② 这两个雅可比都是对称矩阵($I$、$\mathbf{1}\mathbf{1}^\top$、$\hat x\hat x^\top$ 全对称),所以 $J^\top = J$,转置是空操作。但概念上不能省——写通用反向传播代码时不知道遇到的算子对不对称。

0 次齐次

$$\text{RMSNorm}(c \cdot x) = \text{RMSNorm}(x) \qquad \text{对任意 } c > 0$$

一般定义:$f(cx) = c^k f(x)$ 称 $k$ 次齐次。$k=0$ 时 $c^0=1$,输出不变——"对尺度完全免疫"的正式说法。

这个性质关键在于:Pre-LN 结构里残差流长得再大,进入支路时都会被拉回同一尺度,$F$ 内部的权重永远面对幅度稳定的输入。

⚠️ LayerNorm 不是 0 次齐次——它对缩放和平移都免疫,但平移免疫不叫齐次性。

4.5只有 RMSNorm 保方向

以 $x=[1,5,3]$ 为例(方向 = 归一化成单位向量后的结果):

结果 方向
输入 $[1,\ 5,\ 3]$ $[0.169,\ 0.845,\ 0.507]$
RMSNorm $[0.293,\ 1.464,\ 0.878]$ $[0.169,\ 0.845,\ 0.507]$ ← 一模一样
LayerNorm $[-1.225,\ 1.225,\ 0]$ $[-0.707,\ 0.707,\ 0]$ ← 转了 61°

LayerNorm 的减均值是垂直投影,投影必然改方向。所以它不保留正负(输入全正、输出有负)、不保留比例($5/1=5$ 变成 $1.225/(-1.225)=-1$)。

它真正保留的是差值之间的比例:

$$\frac{x_i - x_j}{x_k - x_l} \text{ 不变} \qquad\text{因为}\quad \hat x_i - \hat x_j = \frac{x_i - x_j}{\sigma}$$

$\mu$ 在减法中消掉,$\sigma$ 是公因子。排序也保留(仿射变换单调)。

抹掉 保留
RMSNorm 尺度 方向(完整)
LayerNorm 尺度 + 沿 $\mathbf 1$ 的偏移 排序、差值比例

这是 RMSNorm 一个不常被提的优势:不只是省一半计算,还是更温和的算子——只动幅度,不碰方向。

4.6Gemma 的 (1+γ) 参数化

写法 初始值 weight decay 把参数拖向 0 意味着
标准 $\gamma \odot \hat x$ $\gamma = 1$ 缩放 → 0,这一层输出被抹掉
Gemma $(1+\gamma) \odot \hat x$ $\gamma = 0$ 有效系数 → 1,退回恒等映射

数学等价,但第二种明显更合理。实际后果:读 Gemma 权重时 input_layernorm.weight 全在 0 附近(0.03、−0.01 这种),Llama 则在 1 附近。两者都正常,不知道这点很容易以为加载错了。

4.7Pre-LN vs Post-LN

⚠️ 先澄清一个记号冲突:本节的 "Pre-LN / Post-LN" 指的是归一化层放在哪个位置,与用哪种 norm 无关。这是学界通用叫法——Llama 用 RMSNorm,照样被称为 "Pre-LN 架构";Gemma 2 同理。

但文档别处的 "LN" 是窄义,特指 LayerNorm(与 RMSNorm 对立),比如 4.1 的 $\text{LN}(x)$ 和 4.4 的 $J^{LN}$ vs $J^{RMS}$。

写法 含义
Pre-LN / Post-LN 位置,任何 norm 都适用
$\text{LN}(x)$、$J^{LN}$ LayerNorm 本身,与 RMSNorm 对立

想避开歧义时可以说 pre-norm / post-norm,本节下文混用两种写法,指的是同一件事。

(下面推导 Post-LN 梯度衰减时用的是 $J^{LN}$,因为 2017 年的经典 Post-LN 确实用 LayerNorm;换成 RMSNorm 结论不变,只是雅可比少一项。)

$$\text{Post-LN}: x_{l+1} = \text{LN}\big(x_l + F(x_l)\big) \qquad \text{Pre-LN}: x_{l+1} = x_l + F\big(\text{LN}(x_l)\big)$$

公式 用在哪
Post-LN(2017 原版) x ← LN(x + F(x)) 原始 Transformer、BERT
Pre-LN(现代标准) x ← x + F(LN(x)) GPT、Llama,几乎所有现代 LLM

看着只是括号位置不同,后果很大。对 $x_l$ 求导:

$$\text{Pre-LN}:\quad \frac{\partial x_{l+1}}{\partial x_l} = \underbrace{I}_{\text{精确的恒等}} + J^F_l J^{LN}_l$$

$$\text{Post-LN}:\quad \frac{\partial x_{l+1}}{\partial x_l} = \underbrace{J^{LN}_l}_{\text{挡在外面}} \cdot \big(I + J^F_l\big)$$

链到 46 层:

$$\text{Pre}: \prod_l (I + J_l) = I + \sum_l J_l + \dots \;\Longrightarrow\; \textbf{永远有一项纯 } I$$

$$\text{Post}: \prod_l \big[J^{LN}_l (I + J^F_l)\big] \;\Longrightarrow\; \textbf{46 个 LN 雅可比横在路上}$$

接回 5.4 的齿轮比喻:Pre-LN 那根传动比为 1 的直通轴是真的直通,Post-LN 的直通轴上串了 46 级齿轮。

"直通轴"具体指什么:Pre-LN 展开连乘后,

$$\prod_{l}(I + J_l) = \underbrace{I}_{\text{纯直通}} + \sum_l J_l + \sum_{l<k} J_lJ_k + \dots$$

第一项是纯粹的 $I$——它来自残差里那个孤零零的 $x_l$,求导得 1,不带任何系数。梯度可以完全不经过任何 $F$、任何 LN,直接从顶层落到底层。哪怕中间 46 层把梯度全衰减成 0,这条路照样送达。

Post-LN 展开则是:

$$\prod_l \Big[J^{LN}_l\big(I + J^F_l\big)\Big] = J^{LN}_{46}(\dots)\,J^{LN}_{45}(\dots)\cdots$$

$I$ 还在括号里,但外面被 $J^{LN}$ 乘住了。每一项都至少含 46 个 $J^{LN}$ 因子,没有任何一项是纯 $I$——梯度必须穿过 46 道门,一道都躲不掉。

而且这些门是减速的——$J^{LN}$ 前置系数是 $\frac1\sigma$,而 Post-LN 送进 LN 的正是 $x_l + F(x_l)$ 这个会按 $\sqrt L$ 增长的和。于是深度越大 → $\sigma$ 越大 → $\frac1\sigma$ 越小 → 梯度被压得越狠,46 层累乘,底层收到的信号可能小几个数量级。($J^{LN}$ 那两个减法项还会抹掉梯度沿 $\mathbf 1$ 和沿 $\hat x$ 的分量,单层影响不大,累积起来就不好说。)

这不是纸上推演。Xiong et al. 2020 实测:Post-LN 训练初期顶层梯度巨大、底层微弱,差距悬殊;Pre-LN 各层梯度范数大致均匀。所以 Post-LN 必须用学习率 warmup——开头用极小的学习率慢慢升,因为初期那个不平衡状态下正常学习率会直接把模型炸掉。Pre-LN 可以直接去掉 warmup,这是该论文的核心结论之一。

替经典 Post-LN 说句公道话:因为 LN 套在加号外面,整个和每层都被压回固定尺度,所以它没有 $\sqrt L$ 膨胀问题(下一段就讲这个),深层的相对贡献不会被稀释。有研究认为经典 Post-LN 真训得起来的话表征质量更好,只是"训得起来"太难,所以大家选了更好训的 Pre-LN。

梯度通路和残差流尺度,经典 Post-LN 和 Pre-LN 恰好各占一头。 这是一笔真实的交易,不是 Pre-LN 单方面更优。

Pre-LN 的代价:残差流膨胀

$$x_{l+1} = x_l + F(\text{LN}(x_l))$$

没有任何东西归一化 $x_l$ 本身。 支路输出因为输入被归一化过,幅度大致恒定(记作 $c$),于是每层都往流上加一个差不多大的向量,而且从来没人拿走。

为什么是 $\sqrt L$ 而不是 $L$:若 46 个向量方向完全一致,长度就是简单累加 $46c$。但 4608 维空间里随机两个向量几乎必然接近垂直(8.3 叠加那节的同一个性质),而垂直向量相加走的是勾股定理:

两个垂直、长度都是 c 的向量相加:
     │
   c │╲   合成长度 = √(c² + c²) = √2·c ≈ 1.41c,不是 2c
     │ ╲
     └──────
        c

推广到 $L$ 个互相近似垂直的向量,平方相加所以开根号:

$$\|x_L\|^2 \approx \|x_0\|^2 + Lc^2 \quad\Longrightarrow\quad \|x_L\| \approx \sqrt{L}\,c$$

(和随机游走走 $L$ 步、期望距离 $\sqrt L$ 是同一个道理。)

层 残差流长度(以 $c$ 为单位)
1 1.0
4 2.0
16 4.0
46 6.8

注意增长在变慢——第 1→4 层长了一倍,第 16→46 层才长 70%。

危害不是数值溢出(bf16 范围足够),而是相对贡献被稀释:

$$\frac{\text{第 } l \text{ 层加进来的量}}{\text{已有的量}} = \frac{c}{\sqrt{l}\,c} = \frac{1}{\sqrt{l}}$$

第几层 贡献占残差流的比例
1 100%
4 50%
16 25%
46 15%

越深的层越推不动表示——每层"用力"一样,但要推动的东西越来越重。深度被浪费了。

这和"pre-LN 模型的深层可以大量剪枝而几乎不掉性能"是同一现象的两面:它们本来就没在残差流上留下多少痕迹。这也是为什么末尾必须补一个 final norm——跑到最后长度是 $6.8c$,直接送进 LM head 尺度太大。

⚠️ Gemma 2 的 "post" 不是经典 Post-LN(注意它用的是 RMSNorm,但 Pre/Post 说的是位置,见本节开头)

x = x + post_attn_norm( Attn( input_norm(x) ) )
x = x + post_ffn_norm(  FFN(  pre_ffn_norm(x) ) )

norm 加在支路输出上,不是加在和上。 这个区别是决定性的:

归一化的位置 残差直通轴
经典 Post-LN (2017) $\text{LN}(x + F(x))$ ❌ 被挡住
Gemma 2 $x + \text{LN}(F(\text{LN}(x)))$ ✅ 完全干净

所以 Gemma 2 两个好处都拿:恒等路径分毫未损(Pre-LN 的梯度优势),同时每层贡献幅度被 LN 锁死、由 $\gamma$ 显式控制。

⚠️ 但 Gemma 的 post-norm 不继承经典 Post-LN 的那个好处

前面说经典 Post-LN"没有 $\sqrt L$ 膨胀问题",这条对 Gemma 不成立。区别在于 LN 套在加号的哪一边:

公式 LN 套在 残差流会涨吗 直通轴
经典 Post-LN $\text{LN}(x + F(x))$ 加号外面 ❌ 每层压回去 ❌ 被挡住
Gemma 的 post-norm $x + \text{LN}(F(\dots))$ 加号里面 ✅ 照涨 $\sqrt L$ ✅ 干净

Gemma 的残差路径依然没被归一化,流照样按 $\sqrt L$ 涨。它的 post-norm 管的只是支路那份贡献——让每层写进去的东西有界且可学习控制,而不是任由 $F$ 的权重漂移把某层输出撑爆。

Gemma 的 post-norm 锁住每层贡献的幅度,让增长可预测;它不消除增长。

所以三种设计的账是这样的:

梯度直通轴 残差流尺度
经典 Post-LN ❌ ✅ 不涨
Pre-LN ✅ ❌ 涨 $\sqrt L$
Gemma 2 ✅ ❌ 涨 $\sqrt L$,但每层增量受控

Gemma 拿的是 Pre-LN 那一头,额外加了对每层贡献幅度的控制——它没有回到经典 Post-LN 的收益。

因为流本身没被归一化,最后还必须补一个 final norm 才能送进 LM head——这就是 $46 \times 4 + 1 = 185$ 里的那个 +1。

4.8为什么不用 BatchNorm

BN 沿 batch 轴算统计量:对第 $i$ 个特征,用这一批所有样本的第 $i$ 维求 μ、σ。五条理由按重要性排:

① Per-sample vs per-batch——训练推理必须一致(最根本)

BN 训练时用当前 batch 的统计量,推理时用累积的滑动平均,两套行为。而 LLM 推理时 batch 可能是 1(本地)也可能是 256(云端),还会因 continuous batching 动态变化。LN 完全不看 batch,batch=1 和 batch=256 结果逐比特相同。

② 序列长度可变

BN 要为每个位置维护统计量,但 batch 里句子长短不一:位置 5 有 64 个样本,位置 4000 可能只剩 2 个,靠后位置的统计量噪声极大,padding 还会污染。若改成沿 (batch, 序列) 一起算,又会把未来位置的信息泄漏到过去,破坏因果性。

③ 分布式训练的通信开销

BN 需要跨设备 all-reduce 同步统计量。Gemma 2 有 185 个 norm,每步就是 185 次 all-reduce。LN 是纯本地计算,零通信。

④ NLP 的 batch 统计量本身没有意义

视觉里一个 channel(如"边缘检测器")在一批图片上的统计量有物理含义。NLP 里同一 batch 中一个 token 是"的"、另一个是"量子力学"——它们第 $i$ 维的均值方差代表什么?Shen et al. 2020(PowerNorm)实测发现 Transformer 里 BN 的 batch 统计量方差远大于 CV,这正是它表现差的直接原因。

⑤ 小 batch 下退化

BN 在小 batch 下噪声大、性能掉。而 LLM 训练常因显存限制用极小的 per-device batch(靠梯度累积凑)。

BN 让样本之间产生耦合,LN 不会。 而语言模型从训练到部署,batch 的构成和大小一直在变——任何依赖 batch 的东西都是负担。


第二部分:训练

5梯度与反向传播

5.1梯度是什么

梯度 = 对每个参数给出的方向指示:该往哪调、调多少。

本章及后续用到的求导法则、雅可比、内积等,第 11 章有速查。

假设某参数 w = 0.5,loss = 3.0:

w = 0.500  →  loss = 3.000
w = 0.501  →  loss = 3.002   ← 更错了

梯度 ≈ (3.002 − 3.000) / 0.001 = +2

读法:梯度为正 → 增大 w 会更错 → 往反方向调。

新 w = 0.5 − 学习率 × 2 = 0.5 − 0.0001 × 2 = 0.4998

这就是梯度下降:永远朝梯度的反方向走。

梯度 含义
+2.0 调大会更错 → 往小调
−2.0 调大会变好 → 往大调
0 调它没有任何影响 → 不动
+0.001 有影响但很小 → 轻轻调

梯度和参数形状完全一样,272 亿参数就有 272 亿个梯度。

5.2链式法则:斜率相乘

$$\frac{\partial L}{\partial w_1} = \frac{\partial L}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial b} \cdot \frac{\partial b}{\partial a} \cdot \frac{\partial a}{\partial w_1}$$

齿轮比喻:轴A 转 1 圈 → 轴B 转 3 圈 → 轴C 转 6 圈。总传动比 = 3 × 2 = 6。你不需要知道齿轮长什么样,把每级的比值乘起来就行。

汇率比喻:1 美元 = 7 人民币,1 人民币 = 20 日元 → 1 美元 = 140 日元。∂L/∂w₁ 读作"w₁ 这个单位换算成 loss 的单位,汇率是多少"。

贯穿本章的例子

后面 5.3~5.5 都用这一个例子,它是一个迷你残差块——把第 3、4 章那套结构缩到标量:

$$\hat y = \underbrace{x}_{\text{残差直连}} + \underbrace{w_2\cdot\text{ReLU}(w_1 x)}_{\text{支路 }F(x)}, \qquad L = (\hat y - y)^2$$

        ┌─────────────── 残差直连 ────────────────┐
        │                                        ↓
   x ───┴──[×w₁]──> a ──[ReLU]──> b ──[×w₂]──> c ─(+)─> ŷ ──> L=(ŷ−y)²

取 $x=2,\; w_1=0.5,\; w_2=3$,目标 $y=4$。

前向:

量 算式 值
$a$ $w_1 x = 0.5 \times 2$ 1.0
$b$ $\text{ReLU}(1.0)$ 1.0
$c$ $w_2 b = 3 \times 1$ 3.0
$\hat y$ $x + c = 2 + 3$ 5.0
$L$ $(5-4)^2$ 1.0

反向(从 loss 倒着走):

步骤 依据 累积梯度
$\partial L/\partial \hat y = 2(\hat y - y)$ 平方求导 $+2.0$
$\partial L/\partial c$ 加法原样传 $+2.0$
$\partial L/\partial x$(走残差) 加法的另一份 $+2.0$ ← 直通
$\partial L/\partial w_2 = g_c\cdot b$ 乘法,取另一个因子 $\mathbf{+2.0}$
$\partial L/\partial b = g_c\cdot w_2$ 乘法 $+6.0$
$\partial L/\partial a$ ReLU,$a>0$ 放行 $+6.0$
$\partial L/\partial w_1 = g_a\cdot x$ 乘法 $\mathbf{+12.0}$
$\partial L/\partial x$(走支路) 乘法 $+3.0$
$\partial L/\partial x$ 合计 两路相加 $\mathbf{+5.0}$

数值验算(改动量取 $10^{-6}$,中心差分):

量 数值微分 解析
$\partial L/\partial x$ 5.000000 5.0 ✓
$\partial L/\partial w_1$ 12.000000 12.0 ✓
$\partial L/\partial w_2$ 2.000000 2.0 ✓

关于起点 $\partial L/\partial \hat y = 2(\hat y-y)$:令 $u=\hat y-y$,$L=u^2 \Rightarrow \partial L/\partial u = 2u$,而 $\partial u/\partial \hat y = 1$($y$ 是固定标签),连乘得 $2(5-4)=+2$。

这是整条链的起点——只有它能直接算出来,其余全靠它往回乘。

⚠️ 注意最后三行:$x$ 的梯度有两个来源,支路 3.0 + 残差 2.0 = 5.0。如果去掉残差连接,$x$ 只能拿到 3.0。这个 2.0 就是 5.3 要讲的"直通",也是 5.4 里残差能救深层网络的全部原理。

5.3为什么必须倒着走

算 ∂L/∂w₁ 需要 ∂L/∂a,它需要 ∂L/∂b,它需要 ∂L/∂ŷ。只有 ∂L/∂ŷ 能直接算,所以必须从终点起步。这就是 "back" 的来历。

⚠️ 先澄清"上游/下游"——这两个词跟着梯度走,不跟着数据走:

前向(数据流):  输入 ──────────────────→ loss
反向(梯度流):  输入 ←────────────────── loss
                  ↑                        ↑
               这边是"下游"            这边是"上游"
术语 指哪边 具体是什么
上游梯度 靠近 loss $\partial L/\partial(\text{本层输出})$,从后面传过来的
下游梯度 靠近输入 $\partial L/\partial(\text{本层输入})$,本层要往前传的

所以"往下游传" = 往输入方向传 = 传给更靠前的层。谁先拿到梯度谁是上游。

这是个真实存在的术语冲突:同一层说"下游",讨论数据时指靠近 loss 那边,讨论梯度时指靠近输入那边。严谨的写法会直接说"传给输入侧"避开歧义。

这也解释了 5.4 那个"梯度消失"为什么危害底层——底层在梯度流的最下游,前面每一级衰减都会累积到它身上。

每个节点的通用规则

每个节点收到上游梯度 $g$ 之后只做两件事:① 算出该给自己参数的梯度,② 算出该往下游传的梯度。规则不用背,全部是链式法则 $\frac{\partial L}{\partial \text{输入}} = g \cdot \frac{\partial \text{输出}}{\partial \text{输入}}$ 的直接结果——关键只是求出那个局部导数。

① 乘法 $y = wx$

$$\frac{\partial y}{\partial x} = w, \qquad \frac{\partial y}{\partial w} = x$$

所以传给输入的是 $g\cdot w$,给参数的是 $g\cdot x$。

口诀:乘法节点的梯度,是"另一个因子"。

直觉:$y = wx$ 里 $w$ 增加 $\delta$,$y$ 就增加 $x\delta$——$x$ 越大,同样改动 $w$ 造成的影响越大。所以 $x$ 大的地方参数梯度也大(这也是输入不做归一化会出问题的原因之一)。

例子里:$\partial L/\partial w_1 = g_a \cdot x = 6 \times 2 = 12$,而 $\partial L/\partial w_2 = g_c \cdot b = 2 \times 1 = 2$。同样的上游信号,$w_1$ 拿到的梯度大 6 倍,就因为它面对的输入更大。

② 加法 $y = a + b$

$$\frac{\partial y}{\partial a} = 1, \qquad \frac{\partial y}{\partial b} = 1$$

两条路都乘 1,所以 $g$ 原样各传一份,不缩不放。

加法节点是梯度的"分发器":来多少,两边各给多少。

③ ReLU

$$\frac{\partial}{\partial x}\max(0,x) = \begin{cases} 1 & x > 0 \\ 0 & x < 0\end{cases}$$

所以要么原样通过,要么归零。这就是 5.4 会讲的"死区"——一旦某个神经元长期落在负半轴,它前面所有层都收不到经过它的梯度。

④ 扇出(fan-out):一个值被用到多处

⚠️ 这条最容易漏,但它是残差连接的关键。

前面三条都是"一个输出"的情况。但残差里的 $x$ 同时去了两个地方——直连和支路。这时:

$$\frac{\partial L}{\partial x} = \underbrace{\frac{\partial L}{\partial x}\bigg|_{\text{路径1}}}_{\text{残差}} + \underbrace{\frac{\partial L}{\partial x}\bigg|_{\text{路径2}}}_{\text{支路}}$$

多条路径的梯度要相加。 这是全微分法则:$x$ 通过每条路径都影响了 $L$,总影响是各路之和。

回到 5.2 那个例子:$3.0 + 2.0 = 5.0$,数值微分验证过。

一个漂亮的对偶:

前向 反向
加法(两个值合成一个) 复制(一份梯度发给两边)
复制 / 扇出(一个值用到两处) 加法(多份梯度汇总)

前向的加法和扇出,在反向里正好互换。

汇总表

操作 传给输入 给参数
$y = wx$ $g\cdot w$ $g\cdot x$
$y = a+b$ $g$ 和 $g$(原样各传一份) —
ReLU $g$ 或 $0$(看输入正负) —
一个值用到多处 各路梯度相加 —
$Y = XW$(矩阵版乘法) $GW^\top$ $X^\top G$

为什么残差能救深层网络

现在可以说清楚了,它靠的是②和④两条规则配合:

$$\frac{\partial}{\partial x}\big[x + F(x)\big] = \underbrace{1}_{\text{②:加法原样传}} + \underbrace{\frac{\partial F}{\partial x}}_{\text{支路}}$$

那个 1 是无条件的。 无论 $F$ 内部把梯度衰减成什么样(ReLU 死区归零、权重很小、层数很深),扇出规则保证这两份要相加,而其中一份恒等于 $g$ 本身。

用例子里的数字说:

$\partial L/\partial x$
无残差(只有支路) 3.0
有残差 3.0 + 2.0 = 5.0

假如支路的权重极小,比如 $w_1 = w_2 = 0.01$,支路那份会衰减到 $2\times10^{-4}$——但残差那份仍然是 2.0,一分不少。这就是 5.4 要展开的内容。

为什么最后一行带转置

多维情况下,"传动比"是雅可比矩阵(见 4.4),传梯度就是乘它:

$$g_{\text{输入}} = J^\top g_{\text{输出}}$$

转置的原因是下标对不上。链式法则给出:

$$\frac{\partial L}{\partial x_j} = \sum_i \frac{\partial L}{\partial \hat x_i}\cdot\frac{\partial \hat x_i}{\partial x_j} = \sum_i (g_{\text{out}})_i\, J_{ij}$$

求和跑的是 $i$,也就是 $J$ 的第一个下标(行)。而标准矩阵乘向量 $(Av)_j = \sum_k A_{jk}v_k$ 求和跑的是第二个下标(列)。要让两者一致,就得把行列换过来——这就是转置。

形状检查是最快的判断法。函数 $\mathbb{R}^n \to \mathbb{R}^m$:

量 形状
$J$ $m \times n$(行=输出,列=输入)
$g_{\text{out}}$ $m$ 维
$g_{\text{in}}$ $n$ 维

要从 $m$ 维得到 $n$ 维,只能是 $(n \times m)\times(m \times 1)$——只有 $J^\top$ 的形状对。

更本质的理由:前向时 $J$ 把输入的扰动映射成输出的扰动,$\delta\hat x = J\,\delta x$。而 loss 的变化从两边看:

$$\delta L = \langle g_{\text{out}},\ J\delta x\rangle = \langle J^\top g_{\text{out}},\ \delta x\rangle$$

对比定义 $\delta L = \langle g_{\text{in}},\ \delta x\rangle$,即得 $g_{\text{in}} = J^\top g_{\text{out}}$。

$J$ 正向搬运"变化量",$J^\top$ 反向搬运"敏感度"。 它们是同一个线性映射的两面(数学上叫伴随算子)。

所以凡是反向传播,几乎都带转置——上表 Y = XW 那行的 GWᵀ 和 XᵀG 都是这个道理。

5.4连乘带来的三个问题

情况 齿轮上的样子 后果
某级传动比 = 0 齿轮脱开 整条链归零,前面的层完全学不到
每级都 < 1 逐级减速 0.9^50 ≈ 0.005 → 梯度消失
每级都 > 1 逐级加速 1.1^50 ≈ 117 → 梯度爆炸

第一行就是 ReLU 死区。

残差连接 = 一根直通轴:

$$\frac{\partial}{\partial x}\big(x + F(x)\big) = \underbrace{1}_{\text{直通}} + \frac{\partial F}{\partial x}$$

     ┌────── 传动比 1,直连 ──────┐
     │                            ↓
x ───┴──> [ 46 级齿轮组 F ] ─────(+)───> 输出

不管中间怎么衰减,总有一根传动比为 1 的轴直达底层。把 46 级串联的连乘,变成了"1 + 一点点"的连乘。

用 5.2 那个例子实测

拿同一个残差块 $\hat y = x + w_2\text{ReLU}(w_1x)$,只改支路权重,看 $\partial L/\partial x$ 的两个来源:

场景 $w_1$ $w_2$ 支路那份 残差那份 残差占比
正常 0.5 3.0 $3.0$ $2.0$ 40%
权重极小 0.01 0.01 $-0.0004$ $-4.0$ 99.99%
ReLU 死区 −1.0 3.0 $0$(精确) $-4.0$ 100%

(绝对值不同是因为前向输出变了,看比例。)

第二行是梯度消失的缩影:支路衰减了四个数量级,残差那份一分没少。 第三行更极端:ReLU 把支路彻底掐断(精确的 0),梯度只能靠残差走——而它照样送达。

这就是 46 层能训起来的全部原因。

5.5梯度的稀疏与稠密

定义:说的是梯度矩阵里有多少个 0。稀疏 = 绝大多数元素严格为 0;稠密 = 几乎都非 0。

入口(查表)为什么稀疏:链式法则的铁律——没参与前向计算的参数,梯度必然是 0。这批数据里"猫"没出现过,那行从没被读取过,梯度严格等于 0(不是"很小",是数学上精确的 0)。

梯度矩阵(入口侧)
行 0      [ 0  0  0  ...  0 ]  ← 没出现
行 2      [ ●  ●  ●  ...  ● ]  ← 猫,出现了 ✅
  ⋮
行 256127 [ 0  0  0  ...  0 ]

约 92% 的行整行全 0

出口(LM head)为什么稠密:softmax 分母是 Σ exp(s_j),每一行都在分母里。任何一行变一点,所有概率都跟着变。所以每行都有非零梯度。

tied 之后两股梯度叠加:

第 k 行收到的梯度 = 入口那份 + 出口那份

$$\frac{\partial \mathcal{L}}{\partial E_k} = \underbrace{g_k^{\text{in}}}_{k \in \mathcal{B}} + \underbrace{g_k^{\text{out}}}_{\forall k}$$

入口(稀疏):

$$g_k^{\text{in}} = \sum_{t\,:\,x_t = k} \frac{\partial \mathcal{L}}{\partial h_t^{(0)}}$$

出口(稠密):

$$g_k^{\text{out}} = \sum_{t}\big(p_{t,k} - y_{t,k}\big)\,h_t^{\text{final}}$$

正确答案那行 y=1,括号为负 → 把 E_k 往 h 方向拉;其余 y=0,括号为正 → 往反方向推。一拉,25.6 万推。

行 入口梯度 出口梯度 实际更新
猫(在输入里) ✅ ✅ 两份叠加
吉尔吉斯斯坦 ❌ ✅ 只有出口那份

工程价值:稠密存梯度要 1.18B × 4 = 4.72 GB,稀疏只存 2 万个非零行只要 0.37 GB(省 92%)。这就是 nn.Embedding(sparse=True) 的用途——但一旦 tied,出口的稠密梯度把矩阵填满,稀疏优化直接失效。这是 tied embedding 一个不太被提及的隐性成本。

⚠️ 梯度是 0 不代表参数不动:Adam 有动量(上一步的累积还在),weight decay 也是无差别施加的。罕见 token 就是这样既学不到东西又持续被衰减。

整个 Transformer 里只有 embedding 入口这一处梯度是稀疏的。 稀疏梯度的根源永远是同一个:查表操作。

5.6优化器

SGD:w ← w − η·g。三个问题:

  1. 尺度差异巨大 — embedding 层梯度可能是 1e−2,深层是 1e−6。同一个 η 下前者炸、后者不动
  2. 噪声大 — 每步只看一个 mini-batch,方向抖
  3. 地形难走 — 峡谷型曲面上来回横跳

动量(解决 2、3):

$$m \leftarrow \beta m + (1-\beta)g \qquad w \leftarrow w - \eta m$$

用梯度的滑动平均。像有质量的球滚下山:抖动被抵消,一致方向被累积。

Adam(再解决 1):

$$ \begin{aligned} m &\leftarrow \beta_1 m + (1-\beta_1)\,g &&\text{一阶矩:方向} \\ v &\leftarrow \beta_2 v + (1-\beta_2)\,g^2 &&\text{二阶矩:尺度} \\ w &\leftarrow w - \eta \cdot \frac{\hat m}{\sqrt{\hat v} + \epsilon} \end{aligned} $$

精髓在那个除法:√v 大致就是梯度的典型大小,除掉之后每步实际位移都在 ±η 附近,与梯度绝对大小无关。所以梯度差 4 个数量级的参数能以相近速度前进。

典型 β₁=0.9, β₂=0.95。m̂, v̂ 是偏差修正,补偿初始化为 0 造成的前期偏小。

AdamW(LLM 的实际选择):

$$w \leftarrow w - \eta\left(\frac{\hat m}{\sqrt{\hat v}+\epsilon} + \lambda w\right)$$

λw 是权重衰减。Adam 原版把它混进梯度,会被那个除法一起缩放掉;AdamW 把它解耦出来单独加。

5.7训练显存账

项目 精度 字节/参数
权重 bf16 2
梯度 bf16 2
主权重副本 fp32 4
Adam m fp32 4
Adam v fp32 4
合计 16

Gemma 2 27B:27.2B × 16 = 435 GB——还没算激活值。

一张 A100 只有 80 GB。所以必须靠 ZeRO / FSDP 把状态切碎分散到几十张卡。

"推理能跑"和"训练能跑"完全是两个量级:推理 27B 只要 54 GB 权重,训练 400+ GB 起步。

这也是 8-bit Adam、Adafactor、Muon 存在的理由——核心卖点几乎都是压缩那两份状态。另一条路是根本不训练全部参数:LoRA 冻住原权重、只训练一个低秩增量,这张表里除"权重"外的各行几乎全部消失(见 10.9)。

FLOPs 对照:

场景 FLOPs
解码 1 token 2P
batch = B 解码一步 2PB
prefill S 个 token 2PS
训练(fwd + bwd) 6P / token

训练的 6 = 前向 2 + 反向 4(反向要算对输入的梯度和对权重的梯度,各一遍)。


第三部分:损失函数与信息论

6交叉熵

6.1公式与直觉

$$L = -\sum_{k=1}^{256128} y_k \log p_k$$

(softmax、似然、one-hot 的基础见 11.3。)

y 是 one-hot 时(正确项 1,其余 25.6 万项 0),整个求和塌缩成一项:

$$\boxed{L = -\log p_{\text{正确答案}}}$$

只看模型给正确 token 的概率,取对数,加负号。

给正确答案的概率 loss
100% 0
90% 0.11
50% 0.69
10% 2.30
1% 4.61
→ 0 → ∞

斩钉截铁地答错,惩罚是无穷大。 这逼模型永远保留一点不确定性。

6.2y 是什么

y 是真实答案写成的概率分布。模型输出 p 是 25.6 万维分布,真实答案只是一个 token ID——必须先把答案也写成分布才能比较。

真实答案: "睡觉" (ID=3021)
     ↓
y = [0, 0, ..., 1, ..., 0]
              ↑ 第 3021 位

y 不一定是 one-hot——这是关键。CE 通式对任何目标分布都成立:

场景 y 长什么样
普通预训练 one-hot [0,0,1,0,...]
标签平滑 [0.0001, 0.0001, 0.9, ...]
知识蒸馏 大模型的完整分布 [0.01, 0.6, 0.3, ...]
多答案都对 [0, 0.5, 0.5, 0, ...]

蒸馏时求和不塌缩,25.6 万项全参与。

6.3塌缩是不是故意设计的

不是设计出来的,是恰好碰上的。

信息论定义交叉熵 H(p,q) = −Σ p log q     ← 1948 年,与机器学习无关
        ↓ 拿来当分类 loss
        ↓ 分类任务的标签恰好是确定的
    one-hot → 求和塌缩成一项

0 × log p = 0 让其余项自动消失,这是数学结论,不是设计意图。但红利巨大:

loss = -sum(y[k]*log(p[k]) for k in range(256128))  # 25.6 万次运算
loss = -log_probs[correct_id]                        # 1 次索引

而且不需要把 one-hot 向量物化出来——所以 F.cross_entropy 第二个参数收的是整数 ID,不是 one-hot 矩阵。跟 embedding "查表而非矩阵乘"是同一个把戏:one-hot 遇上求和,必然退化成索引。

⚠️ 但塌缩只在前向:

参与项数
前向算 loss 1 项
反向算梯度 全部 256128 项

因为梯度是 p_k − y_k,其余每项都是 p_k ≠ 0。loss 只看一项,梯度动全部。

6.4为什么是这个公式

① 极大似然:

$$\max \prod_t P(w_t \mid w_{<t}) \;\xrightarrow{\text{取 log 变加法,取负变最小化}}\; \min \sum_t \big(-\log P(w_t)\big)$$

CE 不是被"发明"的 loss,是极大似然在离散分布上的必然形式。

② 替代品都不行:

正确答案概率 平方误差梯度 CE 梯度
0.001(错得离谱) ≈ 0 ❌ 接近 −1 ✓
0.5 中等 中等
0.999(答对了) ≈ 0 ≈ 0 ✓

③ 求导干净:

$$\frac{\partial L}{\partial \text{logit}_k} = p_k - y_k$$

log 的导数 1/p 恰好抵消 softmax 的导数 p(1−p)。这不是巧合——softmax 和 CE 属于同一个数学家族(指数族 + 自然联结函数),配对设计的。

工程细节:代码里几乎不会先算 softmax 再取 log(exp 容易上溢/下溢),都用融合的 log_softmax 或 F.cross_entropy。那个函数自带 softmax——手动 softmax 一次再喂进去是新手最常见的 bug。

7信息论

7.1熵:从编码讲起

香农 1948 年的问题:传一条消息,最少需要多少位? 答案取决于概率。

天气 概率 等长编码 变长编码
晴 1/2 00 0
阴 1/4 01 10
雨 1/8 10 110
雪 1/8 11 111

变长平均长度 = ½(1) + ¼(2) + ⅛(3) + ⅛(3) = 1.75 bit,比等长的 2 bit 省 12.5%。

香农定理:概率为 p 的事件,理论最短码长就是 −log₂ p 位。

概率 −log₂p
1/2 1 bit
1/4 2 bit
1/8 3 bit
1 0 bit(必然发生,不用传)
→ 0 → ∞

为什么是对数:概率减半 → 候选数量翻倍 → 只需多 1 位区分。

熵 = 最优编码的平均长度:

$$H(p) = -\sum_k p_k \log p_k = \sum_k \underbrace{p_k}_{\text{权重}} \times \underbrace{(-\log p_k)}_{\text{码长}}$$

这就是一个普通的加权平均,和算平均分同构。负号纯粹因为 log(小于1的数) 是负的,翻正而已。

熵在测不确定性:

分布 熵
0.25, 0.25, 0.25, 0.25 2.00(最难猜)
0.5, 0.25, 0.125, 0.125 1.75
0.9, 0.05, 0.03, 0.02 0.62
1, 0, 0, 0 0(必然,不携带信息)

两个极端:均匀分布时熵最大 = log₂N(25.6 万种 → 17.97 bit);确定时熵为 0。

技术细节:0 log 0 按极限约定为 0——不可能发生的事不贡献信息量。这正是 one-hot 下 CE 塌缩的同一机制。

7.2交叉熵:用错概率去编码

如果你以为四种天气各占 1/4,用了等长的 2 bit 编码,但真实分布是 1/2, 1/4, 1/8, 1/8:

平均长度 = ½(2) + ¼(2) + ⅛(2) + ⅛(2) = 2.0 bit,比最优的 1.75 多 0.25。

$$H(p, q) = -\sum_k \underbrace{p_k}_{\text{真实概率,决定权重}} \log \underbrace{q_k}_{\text{你以为的概率,决定码长}}$$

唯一区别就是 log 里面是 p 还是 q。

$$H(p) = -\sum p_k \log p_k \qquad\qquad H(p,q) = -\sum p_k \log q_k$$

所以 H(p) = H(p,p)——熵就是"自己对自己"的交叉熵,猜得完全正确时的下限。

三个性质(这就是 CE 能当 loss 用的全部理由):

  1. H(p,q) ≥ H(p) 永远成立
  2. 等号仅当 q = p
  3. 多出的部分叫 KL 散度:

$$\underbrace{H(p,q)}_{\text{实际花费}} = \underbrace{H(p)}_{\text{理论下限}} + \underbrace{D_{KL}(p\|q)}_{\text{猜错的罚款}}$$

天气例子:2.0 = 1.75 + 0.25。

为什么最小化 CE ≡ 最小化 KL:H(p) 只跟数据有关,模型改不了。one-hot 下 H(p) = 0,此时 CE 和 KL 数值上完全相等;蒸馏时目标分布是软的、H(p) ≠ 0,就必须分清。

7.3单位与困惑度

信息论用 log₂(bit),机器学习用 ln(nat,因为求导干净):

$$1 \text{ nat} = 1.443 \text{ bit}$$

困惑度:

$$\text{PPL} = e^{L}$$

含义是"模型的迷茫程度相当于在多少个选项里瞎猜"。

阶段 CE (nat) 困惑度
随机初始化 ln 256128 = 12.45 256,128
训练早期 ~6 ~400
训练完成 ~2 ~7

从 25.6 万降到 7——整个预训练做的就是这一件事。

7.42.89 bit/token 的含义

CE = 2 nat ÷ 0.6931 = 2.885 bit

$$2.89 \text{ bit} \iff \text{平均 } p = 2^{-2.89} = 13.5\%$$

对比基准:

编码方式 bit/token
定长编码 17.97(= log₂256128)
只用词频(一元模型) ~10
LLM 2.89

相比不用任何统计知识的定长编码,压缩了 6.2 倍。这 15 位的差距全部来自"模型读懂了上文"。

换算成每字符(英文约 4.5 字符/token):

$$2.89 \div 4.5 \approx 0.64 \text{ bit/字符}$$

方法 bit/字符
ASCII 原文 8
gzip ~2.5
xz / bzip2 ~2
香农 1951 年测人类 0.6 ~ 1.3
现代 LLM ~0.6-0.8

平均值掩盖了巨大差异:

token 上文 概率 码长
国 "中华人民共和" 99.9% 0.001 位
的 "今天" 30% 1.7 位
生僻人名 无线索 0.01% 13.3 位

模型的价值在于把绝大多数 token 压到接近 0 位——语言里大量内容是可预测的冗余。

7.5压缩即智能

配上算术编码,模型立刻变成可用的压缩器:

压缩端                        解压端
─────────                    ─────────
模型预测下个 token 的分布  →  模型预测同样的分布
用这个分布编码真实 token   →  用分布 + 码流解出 token
                              解出来喂回去,继续

关键在两端跑同一个模型、看到同样上文,必然得到同样分布。

⚠️ 必须说清的 caveat:这个账没算模型本身(54 GB)。要成立需满足之一:收发双方已各有一份模型;压缩的数据量远大于模型体积;或用在线自适应方案(从随机初始化边压边训)。

loss 曲线为什么会平:

$$\underbrace{\text{模型的 loss}}_{H(p,q)} = \underbrace{\text{语言固有的不确定性}}_{H(p)} + \underbrace{\text{模型还没学会的部分}}_{D_{KL}}$$

训练能消掉的只有第二项。loss 趋于平坦不是学不动了,而是在逼近语言本身的熵。

8知识存储在哪

8.1为什么是 FFN

见 3.2——FFN 就是一张 (key, value) 查找表。attention 里没有任何持久内容可存,它的参数只负责"怎么算路由";FFN 的参数才是内容本身。加上 FFN 占 86% 的参数。

实证:

8.2容量:2 bit / 参数

Allen-Zhu & Li 2024(Physics of Language Models 3.3)用合成事实三元组做受控实验,结论是每参数约 2 bit 的知识容量(前提是每条知识在训练中出现约 1000 次),量化到 int8 也不变,量化到 int4 降到约 0.7 bit/参数。

$$27.2\text{B} \times 2\text{ bit} = 54.4\text{ Gbit} = 6.8\text{ GB 的知识}$$

这个数字很有意思:模型文件是 54 GB(每参数 16 位),但只装 6.8 GB 知识——用 16 位承载 2 位的信息量。

int8 无损符合直觉(8 位远大于 2 位)。但 int4 也有 4 位、同样大于 2 位,容量却掉了 65%——只比较"位数"和"信息量"解释不了量化损失,还要看量化方法能不能找准信息存在哪。这一点展开在 9.10。

⚠️ 保留:这是在合成事实上测的容量上限,不能直接推广到推理能力、语法、风格。另一个常被引用的数字是 Morris et al. 2025 的 ~3.6 bit/参数,但它测的是记忆随机比特串的容量,和这里的知识容量不是同一个量(见 9.10)。两者合起来,说"每参数几个 bit 的量级"更稳妥。

8.3叠加(superposition)

问题:残差流只有 4608 维,正交方向最多 4608 个。世界上的概念远不止。

答案:不要求正交,只要求近似正交。Johnson–Lindenstrauss 引理的推论——d 维空间能塞进指数级多的两两夹角余弦小于 ε 的向量:

$$\text{可容纳的近似正交方向数} \sim e^{d\varepsilon^2}$$

d = 4608 时这个数天文级。代价是任意两方向间有一点串扰。

为什么串扰不致命:特征是稀疏的,任意时刻只有极少数概念激活。"埃菲尔铁塔"和"食蚁兽"共享维度不要紧,因为几乎不同时出现。

可观察后果:神经元是多义的(polysemantic)——单个神经元会同时对"学术引用""韩语文本""DNA 序列"响应。不是模型糊涂,是它在同一批维度上叠放了多个特征。

形式化见 Elhage et al. 2022(Anthropic,Toy Models of Superposition)。稀疏自编码器(SAE)就是拆包工具——投影到几万维的稀疏空间,把叠在一起的特征分离成单义的。

8.4幻觉是解压伪影

训练语料(几十 TB)
      ↓ 有损压缩
FFN 权重(54 GB,装 ~7 GB 知识)
      ↓ 检索
生成时的输出

跟 JPEG 一模一样——高压缩率下图片会出现原本不存在的色块,模型也会"检索"出符合统计规律但事实上不存在的答案。

这解释了:

被迫的有损压缩,就是泛化的来源。 如果容量无限,模型只会背下全部语料,什么也学不会。正是"存不下"逼着它提炼可复用的结构——那些结构,我们管它叫理解。


8.5统一视角:谁在增删信息

把前面各章串起来,整个 Transformer 可以看成一条容量固定的信道,各部件在上面读写:

$$x_{l+1} = x_l + F_l(x_l)$$

信道宽度 $d = 4608$ 恒定不变(见 1.1)。所有部件的行为,都可以按"它增加信息、删除信息、还是重排信息"来分类。

部件 对信息做了什么 可逆吗
残差流 只读不删的共享内存 —
线性投影($W_Q$、FFN 矩阵) 重排,理论上不增不减 满秩时可逆
归一化 删除(尺度、偏移) ❌
激活函数 删除(负半轴信息) ❌ 大部分
Attention 搬运(跨位置复制) ❌

反直觉的事实:带参数的部件(线性层)不增删信息,不带参数的部件(norm、softmax、激活)才是真正丢信息的地方。

这和 2.4 那张表"参数全在做 channel mixing,跨位置的两步没有参数"是同一个观察的另一面。

归一化:主动丢弃两个自由度

4.1 讲了几何图像,用信息论重述就是有损压缩,而且丢的是指定的东西:

$$\underbrace{4608 \text{ 个自由度}}_{\text{输入}} \;\xrightarrow{\;\text{LN}\;}\; \underbrace{4606 \text{ 个自由度}}_{\text{输出}} + \underbrace{\gamma, \beta}_{\text{学出来的 } 2 \times 4608}$$

丢掉的两个是"整体偏移"和"整体尺度"。关键在于这两个自由度对下游任务几乎无信息——它们主要携带"这个 token 经过前面几十层后碰巧被放大了多少",属于训练动力学的痕迹,不是语义。

归一化是一个信息瓶颈,但它瓶掉的是噪声维度,同时把该维度的控制权交给一个可学习参数。

这就是 4.1 那句"从副作用变成目标"的信息论版本。RMSNorm 只丢一个(尺度),保留偏移——更轻的瓶颈,这也解释了为什么砍掉 re-centering 几乎无损。

残差流:为什么必须是加法

从信息角度看,$x + F(x)$ 和 $F(x)$ 的差别是根本性的。

串行 $x_{l+1} = F(x_l)$:每层都可能删信息,且删了就永久没了。$L$ 层之后信息量单调递减——这是数据处理不等式的直接后果:

$$I(\text{输入}; x_L) \le I(\text{输入}; x_{L-1}) \le \dots \le I(\text{输入}; x_0)$$

残差 $x_{l+1} = x_l + F(x_l)$:原信息始终在场。第 40 层若需要第 1 层的某个原始特征,它还在流上。

所以残差流的角色是一块所有层共享的、只增不减的黑板。8.3 的叠加正是在这块黑板上发生:4608 维要容纳远超 4608 个特征,靠近似正交 + 稀疏。

加法是最优选择,因为它是唯一同时满足三条的操作:

  1. 保留原信息(可逆地叠加)
  2. 允许新信息写入
  3. 反向传播时传动比恰好 1(见 5.4)

但黑板会变拥挤——4.1 算的 $\sqrt L$ 增长,信息论上是信噪比问题:

$$\frac{\text{新写入}}{\text{已有内容}} = \frac{c}{\sqrt{l}\,c} = \frac{1}{\sqrt l}$$

第 46 层写进去的东西只占 15%,它的信号被前面 45 层淹没。深层不是没能力,是没带宽。

Attention:唯一的跨位置信道

它不创造信息,只从别处复制。 $\text{softmax}(QK^\top)V$ 是 $V$ 的凸组合——输出必然落在 $V$ 张成的凸包内,不可能产生 $V$ 里没有的东西。

① 路由是数据相关的。 普通网络的连接固定,attention 的混合权重 $A$ 每次前向现算——信息流的拓扑本身是输入的函数。这是 Transformer 区别于 CNN/RNN 的核心。

② 注意力分布的熵就是检索的确定性:

注意力分布 熵 含义
集中在 1 个 token ≈ 0 精确检索,像查表
均匀分布在 $t$ 个上 $\log t$ 等于平均池化,没检索到东西

训练好的模型里多数头的注意力熵很低——它们学会了精确寻址。

③ Attention sink 是熵的强制支出。 2.3 讲过行和必须为 1,模型没法"谁都不看"。信息论上这是 softmax 强加的归一化约束——你必须花掉这一份概率质量,BOS 那个 sink 就是信息的垃圾桶。

与 FFN 的信息论对偶(3.2 那个对偶的重述):

从哪取信息 容量
Attention 当前上下文 随 $t$ 增长,无损(原文还在)
FFN 训练语料的压缩副本 固定 ~2 bit/参数,有损

RAG 有效的原因就在这一行——把有损的参数化记忆换成无损的上下文检索。8.4 的幻觉是 FFN 侧的解压伪影,attention 侧不会有(原文就在上下文里)。

激活函数:故意的不可逆

最反直觉的一个——激活函数的价值恰恰在于它删信息。

$y = Wx$ 若 $W$ 满秩,可完全反解出 $x$,信息量不变。所以 $W_2(W_1x) = (W_2W_1)x$,46 层线性 = 1 层线性(见 3.3):堆多少层都不增加表达能力,因为每层只是在重排同一份信息。

ReLU 把负半轴全映射到 0——不可逆,无法从输出反推输入是 $-3$ 还是 $-7$。但正因这个丢弃,模型才能表达"如果……就……":

"当这个特征为正时才传递"是一个决策,而决策必然意味着丢弃另一条分支的信息。

线性变换只能旋转和拉伸空间,非线性才能折叠空间。 折叠让原本远离的点靠在一起(不可逆),这正是分类、抽象、泛化的几何基础。

丢什么 保留什么
ReLU 负半轴(硬截断) 正半轴原样
GELU 负半轴软性衰减 保留一点负值信息,梯度处处存在
Softmax 绝对尺度($\text{softmax}(x)=\text{softmax}(x+c)$) 相对差异,且指数放大
GeGLU 的 $\odot$ —— 不丢,而是二次交互

最后一行值得注意:门控相乘不是在丢信息,是在创造新信息($x_ix_j$ 这样的交叉项在线性变换里根本不存在)。这是 GeGLU 强于 ReLU 的一个来源,和"非线性"是两回事。

串起来:训练目标就是压缩

回到 7.5。整个架构的每一部分都在服务同一个目标——把语料编码得更短:

CE loss = 每 token 需要多少 bit
    ↓ 要降低它,必须更准地预测下一个词
    ↓ 要更准地预测,必须
    ├── 从上下文取信息   → Attention(无损,容量随 t 增长)
    ├── 从记忆取信息     → FFN(有损,~2 bit/参数)
    ├── 组合与决策       → 激活函数(丢弃换取表达力)
    ├── 信息的载体       → 残差流(只增不减的共享黑板)
    └── 保持信道可用     → 归一化(丢掉噪声维度,稳住尺度)

8.4 那个结论现在有了更完整的形态:

容量有限 → 被迫有损压缩 → 只能存规律不能存原文 → 这既是泛化的来源,也是幻觉的来源。

一个统一的判据:这套架构里几乎每个设计,都可以问同一个问题——它在信道上增加信息、删除信息、还是重排信息? 而"什么时候该删"往往比"怎么加"更能解释设计动机。归一化删噪声维度、激活删分支、softmax 删绝对尺度、GQA 删 KV 的冗余副本——Transformer 的精妙很大程度上在于它删得准。


第四部分:推理工程

9显存与算力

9.1KV cache

为什么存:自回归生成时,新 token 的 Query 要和前面所有 token 的 Key/Value 做注意力。不缓存就得每步重算一遍历史。

$$\text{bytes/token} = 2_{(K,V)} \times \text{layers} \times \textbf{kv\_heads} \times \text{head\_dim} \times \text{每元素字节数}$$

Gemma 2 27B:

$$2 \times 46 \times 16 \times 128 \times 2 = 376{,}832 \text{ B} = \textbf{368 KiB}$$

⚠️ 必须用 kv_heads(16),不是 n_heads(32)——GQA 的全部意义就是让多个 Q 头共享同一组 KV。用 32 等于把 GQA 的收益抹掉,结果正好翻倍。

A100 80GB 实际能放多少:

项目 占用
模型权重(bf16) ≈ 54.5 GB
剩余可用 ≈ 25.5 GB
每 token 368 KiB
实际能放 ≈ 6.8 万 token

Gemma 2 上下文上限是 8192,所以这不是"一条 6.8 万长的序列",而是并发 batch 总量——单条满 8192 约占 3.09 GB,大概能同时跑 8 条。

滑动窗口还能再省:Gemma 2 局部/全局层交替(各 23 层),局部层窗口只有 4096,超窗部分那 23 层不用留。长上下文下 cache 实际增长速率约为一半,单条满 8192 从 3.09 GB 降到约 2.3 GB。

9.2为什么必须缓存

第 t 步的计算量
有 cache 前向 1 个 token,约 2 × 参数量
无 cache 前面 t 个全部重算,约 2 × 参数量 × t

生成 N 个 token 累加,从 O(N) 变成 O(N²)。prompt 1000 + 生成 1000,平均每步重算约 1500 个 token,总计算量约是有 cache 的 1500 倍。

反直觉的点:解码阶段是带宽瓶颈(见 9.4),所以重算的前几十个 token 其实"免费"(反正卡在等数据),但 t 一大就彻底压到算力上了。

1 层也要存:这里容易混淆两个轴。KV cache 存的是时间轴(历史 token),层数只是个倍数。

            token1  token2  token3   ← 时间轴:cache 存在的理由
  layer 1  →  K,V     K,V     K,V
  layer 2  →  K,V     K,V     K,V    ← 层轴:只是把量乘以 L

即使只有 1 层,生成第 100 个 token 时仍需要前 99 个的 K/V。只是从 368 KiB 降到 8 KiB/token。

什么时候真的不用存:

场景 原因
训练 / prefill / 一次性前向 整个序列同时可见,算完即用,不跨步
只生成 1 个 token 没有"下一步"要复用
RNN / Mamba / 线性注意力 历史被压缩进固定大小的状态,不随长度增长

最后一行才是真正绕开 KV cache 的路子,代价是压缩必然有损,长程精确检索比不过完整 attention。

9.3为什么是 2 × 参数量 FLOPs

解码时每层本质是矩阵-向量乘。对 y = Wᵀx:

$$\text{FLOPs} = 2 \times n_{in}n_{out} = 2 \times (\text{该矩阵的参数量})$$

关键在每个权重恰好被用到一次。

Gemma 2 27B 验算:2 × 26.0B = 52.1 GFLOPs(主干)+ 2 × 1.18B = 2.4 GFLOPs(LM head)≈ 54.5 GFLOPs

哪些没算进去:

9.4带宽瓶颈与算术强度

54 GFLOPs 决定不了速度:

数值
A100 bf16 算力 312 TFLOPs → 0.17 ms
每步读 54.5 GB 权重 @ 2 TB/s 27.2 ms

差 150 倍。算力利用率约 0.6%。

算术强度(FLOP/byte):bf16 下每参数 2 字节做 2 FLOPs,强度 = 1。A100 需要约 156 才能打满算力。

batch 算术强度 状态
1 1 严重带宽瓶颈
32 32 仍偏带宽
156 156 临界点
256 256 算力瓶颈

batch 到 B 时 FLOPs 变成 2PB 而权重仍只读一次,强度升到 B——这就是 continuous batching 的全部意义。也正因为 batch 要开大,KV cache 的显存占用才成了真正的瓶颈。

整个推理优化领域的主线就是提高算术强度:

手段 怎么改善强度
增大 batch 权重读一次,服务 B 个请求
投机解码 权重读一次,产出多个 token
量化(int8/int4) 直接减少要读的字节数(见 9.9)
GQA / MLA 减少 KV cache 的读写量(见 2.5、2.11)

MoE 是往相反方向走的(结构见 3.6)——每个 token 只激活一部分专家,FLOPs 降了但权重总量没降,算术强度更低。所以 MoE 在小 batch 下解码效率特别难看,必须靠大 batch 才划算。这也是 MoE 主要出现在云端而非本地部署的原因。Mixtral 论文自己也说 MoE 更适合能把算术强度做上去的批量场景;DeepSeek-V3 报告提到解码时每个专家分到的 batch 通常不超过 256 个 token,瓶颈在访存而非计算。

⚠️ MLA 是这张表里的一个例外:吸收权重之后,它的解码 kernel 反而可能是算力瓶颈(见 2.11 末尾)。

9.5投机解码

立论基础:权重读一遍的时间够算好多个 token。

1 个 token 5 个 token
读权重 54.5 GB → 27.2 ms 54.5 GB → 27.2 ms(一模一样)
算 0.17 ms 0.87 ms
合计 27.4 ms 28.1 ms

多算 4 个 token,只多花 0.7 ms。

数学原因:单 token 是矩阵-向量乘,K 个 token 是矩阵-矩阵乘。FLOPs 涨 K 倍,权重读取量完全不变。

流程:

① 草稿模型(比如 1B)自回归生成 5 个候选
② 大模型一次前向,同时验证这 5 个位置
③ 逐个判断接受还是拒绝
④ 从第一个被拒的位置截断,重新采样一个

输出分布严格不变——这是它不算偷工减料的原因。接受规则:

$$\text{以概率} \min\left(1, \frac{p(x)}{q(x)}\right) \text{接受}$$

被拒时从残差分布重新采样:

$$\tilde{p}(x) = \frac{\max(0,\; p(x) - q(x))}{\sum_{x'}\max(0,\; p(x') - q(x'))}$$

可证明得到的 token 边缘分布精确等于直接从 p 采样。不是"效果差不多",是数学上完全相同。 草稿模型再烂也只影响速度不影响质量(Leviathan et al. / Chen et al. 2023 独立提出,标准拒绝采样技巧)。

加速比:设接受率 α、草稿长度 K,每轮期望产出

$$\mathbb{E}[\text{tokens}] = \frac{1 - \alpha^{K+1}}{1 - \alpha}$$

(K+1 是因为 5 个全接受时,大模型那次前向顺带算出了第 6 个位置的分布,白送一个。)

α = 0.75, K = 5 → 期望 3.29 个。总耗时 ≈ 28.1(验证)+ 5(起草)= 33.1 ms

$$\frac{33.1}{3.29} = 10.1 \text{ ms/token} \quad\text{vs}\quad 27.4 \text{ ms/token} \;\Longrightarrow\; \textbf{2.7 倍}$$

三个限制:

  1. 词表必须完全一致(见 1.5)——p 和 q 要在同一概率空间比较
  2. 草稿要又快又像——太大则起草成本吃掉收益,太小则接受率低。接受率与内容强相关:代码/套路化文本高,诗歌/创造性内容低
  3. ⚠️ batch 一大加速就消失——投机解码是拿 FLOPs 换延迟,平均只留下 3.29 个,其余纯浪费。batch 小时算力闲着不心疼,batch 大时算力已打满,浪费就是实打实的损失

投机解码是延迟优化,不是吞吐优化。

变体:

方法 草稿从哪来
标准 独立的小模型
Medusa 给大模型加额外输出头,直接预测 t+2, t+3
EAGLE 在隐状态层面起草而非 token 层面,接受率显著更高
n-gram / prompt lookup 不用模型,直接从上文抄重复片段

最后一个在改代码、摘要、RAG 里特别好使——这类任务输出大量在复制输入,零成本且接受率高。

9.6激活显存与 chunked prefill

推理时激活用完即扔(没有反向传播),所以峰值只需装下一层。

单层激活清单(bf16):

张量 形状 每 token 字节
层输入 hidden t × 4608 9,216
RMSNorm 输出 t × 4608 9,216
Q t × 4096 8,192
K t × 2048 4,096
V t × 2048 4,096
注意力分数 QKᵀ 32 × t × t 64t ← 二次
softmax 后 32 × t × t 64t
A·V t × 4096 8,192
W_O 输出 + 残差 t × 4608 9,216
gate t × 36864 73,728
up t × 36864 73,728
W_down 输出 t × 4608 9,216

两个大头:

  1. FFN 中间层 — gate 和 up 必须同时存在(要逐元素相乘),合计 147 KB/token,比其他所有项加起来还多
  2. 注意力分数矩阵 — 唯一二次增长的:t=8192 时单层 4.3 GB

但 FlashAttention 让第二个大头消失了——分块计算 + online softmax,从不把完整的 t×t 矩阵写进 HBM,分数在 SRAM 里算完就丢,只保留归一化统计量(算法逐行拆解见 9.7)。所以那两行在实际实现中不存在,二次项被消掉。

同理 FFN 也可沿序列维分块,那 147 KB/token 被压成与 t 无关的常数。

总账:

方案 每 token 显存
常驻 KV cache(46 层全存) 368 KiB
重算峰值(1 层,FlashAttention) ~200 KB
重算峰值(+ FFN 分块) ~50 KB

差别来源一句话:KV cache 要给 46 层每层留一份 K/V,重算只需当前这一层的。

这不是假想,prefill 就是它。上表就是 prefill 的峰值显存,解释了一个常见现象:KV cache 明明装得下,长 prompt 却在 prefill 阶段 OOM。

解法是 chunked prefill——把 8192 的 prompt 切成 16 块依次跑,激活峰值降到 1/16,KV cache 不变。vLLM、TensorRT-LLM 默认开这个。

与训练的对照:

$$\text{推理峰值} = 1 \text{ 层} \qquad\qquad \text{训练峰值} = 46 \text{ 层} \times \text{batch}$$

gradient checkpointing 的做法是前向只保留每层输入,中间全扔,反向要用时就地重算——这和"不用 KV cache 就得重算"是完全同一笔交易,拿计算换显存。区别只是一个发生在推理的时间轴上,一个发生在训练的层深上。

9.7FlashAttention:分块与在线 softmax

记号提醒:本节沿用论文写法,和 2.3 的对应关系如下。

本节(FlashAttention 论文) 2.3 / 本文其他地方 含义
$N$ $t$ 序列长度
$d$ d_head = 128 每个头的维度
$S$,元素 $s_{ij}$ $s_{ij}$ 缩放后的打分
$P$ $A$ softmax 后的注意力权重
大写带下标 $S_{ij}$、$\tilde P_{ij}$ — 第 i 个 Q 块 × 第 j 个 K 块的小矩阵(不是单个数)

只看一个头,所以省略 2.3 的上标 $(h)$。

先定位问题。标准注意力三步(softmax 本体见 2.3):

$$S = \frac{QK^\top}{\sqrt d} \quad\to\quad P = \text{softmax}(S) \quad\to\quad O = PV$$

(论文正文和 Algorithm 1 为了简洁把 $\frac{1}{\sqrt d}$ 省掉了,写成 $S = QK^\top$;带 mask 和 dropout 的 Algorithm 2 才把它写成缩放常数 $\tau$,"通常取 $1/\sqrt d$"。省掉它不影响算法:等价于 Q 事先乘好 $1/\sqrt d$。下文沿用论文的省略写法。)

Q、K、V 都是 $N \times d$,而中间产物 S、P 是 $N \times N$。关键在 N ≫ d:Gemma 2 的 head_dim 只有 128,序列却动辄 8192——$8192 \times 8192$ 的打分矩阵比 Q、K、V 本身大 64 倍。

慢的不是计算,是搬运。朴素实现要把这个 N×N 矩阵完整写进 HBM、再读出来做 softmax、再读一遍去乘 V——和 9.4 是同一件事,只是主角从权重换成了中间矩阵。GPU 内存分三层,越快的越小:

层级 是什么 带宽 容量
SRAM GPU 芯片内部的高速缓存 19 TB/s ~20 MB
HBM 平时说的"显存" 1.5 TB/s 40 GB
DRAM CPU 内存 12.8 GB/s >1 TB

SRAM 比 HBM 快约 13 倍,但装不下 N×N。FlashAttention 的目标(论文标题里的 IO-Awareness,IO 感知):重排计算顺序,让 N×N 矩阵从头到尾不落地 HBM。

FlashAttention 总览:左为 GPU 内存金字塔,中为分块双重循环示意,右为 GPT-2 上五个 kernel 融合成一个后的耗时对比
FlashAttention 总览:左为 GPU 内存金字塔,中为分块双重循环示意,右为 GPT-2 上五个 kernel 融合成一个后的耗时对比

图源:Dao et al. 2022,FlashAttention,Figure 1。

核心思路 = 切块(tiling)。Q 沿行方向切成小块,K、V 也切成小块。外层循环取一块 K/V 搬进 SRAM,内层循环再取一块 Q 搬进来,打分、softmax、乘 V 全在 SRAM 里对小块做完,只把结果写回 HBM。图中间的橙色小方块就是驻留 SRAM 的当前块,虚线框 "Compute Block on SRAM" 是全部计算发生的地方。

右侧柱状图是收益:PyTorch 朴素实现在 GPT-2 上的注意力约 17 ms,拆成 Matmul、Dropout、Softmax、Mask、Matmul 五个独立 kernel(GPU 程序调用),段与段之间都要经 HBM 一进一出;FlashAttention 把五步融合成一个 kernel(fused kernel),约 2 ms。

拦路虎:softmax 是"全行运算"。切块后每次只能看到一行分数的一小段,而 softmax 的分母要对整行求和。解决它要先复习数值稳定技巧:

$$A_{ij} = \frac{e^{s_{ij} - m}}{\sum_{j'} e^{s_{ij'} - m}}, \qquad m = \max_{j'} s_{ij'}$$

这就是 2.3 的第 ③ 步,只是对第 i 行先求出最大值 m,每个分数都减掉它再取指数——数学上完全等价(分子分母同乘 $e^{-m}$),但指数最大只到 $e^0 = 1$,永不上溢。于是一行 softmax 只由两个统计量决定:行最大值 m,和减完最大值后的指数和 ℓ(就是分母)。

在线(online)softmax:这两个统计量可以分块滚动更新——看到新块时,把旧统计量换算到新的最大值基准下再合并。这是整个算法的数学地基,下面逐行看。

FlashAttention 算法伪代码(Algorithm 1),红框标出四处 HBM 读写:Load K/V 块、Load Q/O/ℓ/m 块、Write O、Write ℓ/m
FlashAttention 算法伪代码(Algorithm 1),红框标出四处 HBM 读写:Load K/V 块、Load Q/O/ℓ/m 块、Write O、Write ℓ/m

图源:Dao et al. 2022,FlashAttention,Algorithm 1;红框为本文所加的标注。

符号约定:

符号 含义
$M$ SRAM 容量(能装多少个数)
$B_r, B_c$ 块的行数 / 列数(r = row,c = column)
$T_r, T_c$ Q 方向 / K 方向各切多少块
$O$ 输出矩阵,逐块累加出来
$\ell \in \mathbb{R}^N$ 每行 softmax 的分母(指数和)
$m \in \mathbb{R}^N$ 每行迄今见过的最大分数,初始 $-\infty$
$\tilde{m}, \tilde{P}, \tilde{\ell}$ 波浪号 = 只看当前块算出的"局部量"

第 1 行(定块大小):$B_c = \lceil M/4d \rceil$(⌈⌉ 是向上取整)。除以 4d 是因为 SRAM 要同时装 4 个宽度为 d 的块:$K_j, V_j, Q_i, O_i$。

第 2–4 行(初始化与切块):O 全 0;ℓ 全 0(还没累加过任何指数);m 全 $-\infty$(还没见过任何分数)。Q、O、ℓ、m 按行切成 $T_r$ 块,K、V 切成 $T_c$ 块。

第 5–8 行(双重循环 + 装载):外层循 K/V 块 j(Load 进 SRAM),内层循 Q 块 i(把 $Q_i, O_i, \ell_i, m_i$ 也 Load 进来)。之后 9–12 行全部 on-chip。

第 9–10 行(小块打分 + 局部 softmax 半成品):

$$S_{ij} = Q_i K_j^\top \in \mathbb{R}^{B_r \times B_c}$$

这是 N×N 大矩阵里的一小格。然后取局部行最大值 $\tilde{m}_{ij}$,算 $\tilde{P}_{ij} = \exp(S_{ij} - \tilde{m}_{ij})$(逐元素),再求局部行和 $\tilde{\ell}_{ij}$。注意 $\tilde{P}$ 还没除分母——真正的分母要等所有块看完才知道。

第 11 行(合并统计量,在线 softmax 的心脏):

$$m_i^{\text{new}} = \max(m_i, \tilde{m}_{ij}), \qquad \ell_i^{\text{new}} = e^{m_i - m_i^{\text{new}}}\,\ell_i + e^{\tilde{m}_{ij} - m_i^{\text{new}}}\,\tilde{\ell}_{ij}$$

旧的和是按旧最大值减出来的,新的局部和是按局部最大值减出来的,基准不同不能直接相加;各乘 $e^{\text{旧基准} - \text{新基准}}$ 换算到同一基准再加——像把美元和日元都先换成人民币再求总额。

第 12 行(同样的换算更新输出):

$$O_i \leftarrow \text{diag}(\ell_i^{\text{new}})^{-1}\Big(\text{diag}(\ell_i)\, e^{m_i - m_i^{\text{new}}}\, O_i + e^{\tilde{m}_{ij} - m_i^{\text{new}}}\, \tilde{P}_{ij} V_j\Big)$$

四步:旧输出乘回旧分母(还原成未归一化的加权和)→ 换算基准 → 加上本块贡献 $\tilde{P}_{ij}V_j$ → 除以新分母重新归一化。(diag(ℓ) 表示每行各乘/除自己的 ℓ 值。)

第 13 行:把 $\ell_i, m_i$ 写回 HBM,供下一轮外层循环继续累加。全部块走完,O 与标准注意力逐位一致——这是精确算法,不是近似。

用 4 个数验证在线合并。某一行的完整分数是 [1, 3 | 2, 5],切成两块:

步骤 m ℓ
看完块 1 [1, 3] 3 $e^{-2} + e^{0} = 1.135$
块 2 [2, 5] 的局部量 5 $e^{-3} + e^{0} = 1.050$
按第 11 行合并 5 $e^{3-5} \times 1.135 + e^{0} \times 1.050 = 1.203$
对照:一次算整行 5 $e^{-4} + e^{-2} + e^{-3} + e^{0} = 1.203$ ✓

每行只用记两个数,就能分块滚出精确的 softmax。

总账:

标准注意力 FlashAttention
N×N 矩阵 完整读写 HBM 多次 从不落地,SRAM 里算完就丢
额外显存 $O(N^2)$ $O(N)$(只存 O、ℓ、m)
kernel 数 5 个独立 1 个融合
结果 精确 同样精确

省的是 IO 不是 FLOPs(重算反而略多),但瓶颈本来就在 IO——所以净赚。这正是 9.6 里"二次项被消掉"的出处。

9.8FlashAttention-2:把外层循环换到 Q

v2(2023)比 v1 又快约 2 倍,主要动作只有一个:内外循环对调——外层循 Q,内层循 K/V。为什么这么改收益巨大:

Q 方向是"各干各的"的独立维度,K/V 方向是"必须累加"的归约维度。并行要沿独立维度切,归约应留在每个工人内部串行做。v1 恰好放反了。

先看清依赖结构。输出的第 t 行 = Q 的第 t 行 + 全部 K/V。所以不同 Q 块之间完全独立、可同时算;不同 K/V 块的贡献则要累加进同一组 $O_i, \ell_i, m_i$——这是归约(reduction),有先后依赖,还共享同一组累加器。

改考卷的比喻:每个学生的总分 = 所有题目得分之和。v1 是"外层循题目"——每道题都要把全班成绩单挨个取出、加一笔、放回;v2 是"外层循学生"——拿起一个学生的卷子一口气改完所有题,总分一次写上。学生之间毫无瓜葛,可以分给不同老师同时改,零冲突。

这决定了 GPU 吃不吃得满。三个术语:

术语 是什么
SM GPU 内部的"小工厂",A100 有 108 个,同时开工才吃满算力
thread block 分发给 SM 的最小任务包,一个包进一个工厂
warp 任务包内部的一小队线程(32 个)
v1:  并行 = (batch, head)          包内: 外循 K/V、内循 Q   ← 归约在外层,拆不动
v2:  并行 = (batch, head, Q 块)    包内: 只循 K/V           ← 归约收进包内,天然安全

附带的大红利:输出不再反复搬。v1 里同一个 $O_i$ 要被"Load—改—Write"$T_c$ 次(算法图第 8、12、13 行);v2 里一个任务包全程把 $O_i, \ell_i, m_i$ 留在寄存器/SRAM 滚动累加,扫完全部 K/V 才写回一次。

同一个道理在 warp 尺度重演:v1 包内各 warp 分摊 K/V 切片,算出的是同一批输出行的部分和,最后要经共享内存同步合并;v2 各 warp 分摊 Q 的行,各管各的、零通信。

v1(外循 K/V) v2(外循 Q)
并行度 batch × 头数 batch × 头数 × Q 块数
O 的 HBM 写回 每个 Q 块 $T_c$ 次 每个 Q 块 1 次
warp 协作 同步合并部分和 零通信

v2 另有两个小优化:分母 $\text{diag}(\ell)^{-1}$ 从每步做一次推迟到最后只做一次(GPU 上非矩阵乘运算的吞吐远低于矩阵乘);统计量从存 m、ℓ 两个变成只存一个 logsumexp。v3(2024)是 Hopper 架构(H100)专属的异步流水 + FP8,思想不变。三代论文见附录 D,以及 papers/README.md 的 E.2 节。

9.9量化:GPTQ、AWQ、SmoothQuant

一句话:量化就是把 16 位的权重(有时连激活一起)四舍五入成 8 位或 4 位。直接四舍五入在大模型上会崩,因为有少数"离群"的通道特别大。三种主流方法各自对付一种问题:GPTQ 用输入的相关性把舍入误差补偿到还没量化的权重上;AWQ 按激活大小找出重要的通道、先放大再量化;SmoothQuant 把激活里的离群值"搬"到权重上,让 W8A8 变得可行。

为什么要量化:接 9.4

解码是带宽瓶颈,速度几乎完全由"每步要读多少字节的权重"决定。Gemma 2 27B(按 2 TB/s 带宽算):

精度 每参数位数 权重大小 每步读权重
bf16 16 54.5 GB 27.2 ms
int8 8 27.2 GB 13.6 ms
int4(group 128) 约 4.16 约 14.2 GB 约 7.1 ms

int4 那行多出的 0.16 位是每 128 个权重共用的一个 fp16 缩放因子和一个 4 位零点(GPTQ 论文的存法)。单 batch 解码时,权重字节数减半,速度大致翻倍——这是量化和 9.4 那张表里其他手段的区别:它直接砍分母。

两种量化对象

量化什么 省什么 难点 代表
只量化权重(W4A16 等) 权重存成 int4,计算前还原成 fp16 显存、带宽 低位数下的精度 GPTQ、AWQ
权重 + 激活(W8A8) 两者都是 int8,直接用整数矩阵乘 还省算力 激活的离群值 SmoothQuant

最朴素的做法:逐组四舍五入(RTN)

$$Q(w) = \Delta\cdot\text{Round}\!\left(\frac{w}{\Delta}\right), \qquad \Delta = \frac{\max|w|}{2^{N-1}}$$

一组权重里绝对值最大的那个决定步长 $\Delta$,其余都按这个格子取整。(公式按 AWQ 论文的写法。)问题出在 $\max$:组里只要有一个特别大的数,$\Delta$ 就被撑大,其他所有数都量化得很粗。

难点:离群特征

LLM.int8()(Dettmers et al. 2022)最早把这件事量化清楚:

它的解法是混合精度:这约 0.1% 的维度用 16 位算,其余 99.9% 用 int8。论文报告到 175B 都没有性能下降(零样本准确率;困惑度表只覆盖到 13B)。缺点是混合精度对硬件不友好,后面三种方法都在设法绕开它。

GPTQ:量化一列,就把误差补到还没量化的列上

Frantar et al. 2022(ICLR 2023)。目标是逐层最小化输出误差,而不是权重本身的误差:

$$\arg\min_{\widehat W}\; \big\|WX - \widehat W X\big\|_2^2$$

X 是校准数据在这一层的输入(论文用的是 C4 里随机抽的 128 段、每段 2048 token)。这个目标的海森矩阵是 $H = 2XX^\top$——它只和输入有关,描述的是"输入的各维度之间有多相关"。

做法沿用 OBQ(Optimal Brain Quantization):一次量化一列权重,把产生的误差按 $H^{-1}$ 分摊到还没量化的那些列上:

$$\delta_F = -\frac{w_q - \text{quant}(w_q)}{[H_F^{-1}]_{qq}}\cdot (H_F^{-1})_{:,q}$$

直觉:如果第 3 维和第 7 维的输入高度相关,那么第 3 列权重四舍五入多出来的误差,可以通过微调第 7 列来抵消——反正两者总是一起出现,输出看到的是它们的合力。所以 GPTQ 能补偿多少,取决于输入的相关性有多强。

让它能跑到 175B 的三个工程改动:

改动 作用
所有行按同一顺序量化 每行共享同一个 $H^{-1}$,不用每行各算一遍
惰性批量更新:一次处理 128 列 把大量小更新攒成矩阵乘,提高 GPU 利用率
Cholesky 分解 + 阻尼(对角线加平均值的 1%) 数值稳定

论文结果:175B 模型约 4 个 GPU 小时量化到 3~4 位,精度损失可忽略。⚠️ 常被引用的"OPT-175B 单卡跑"和"A100 上约 3.25 倍、A6000 上约 4.5 倍加速"都是 3 位模型的结果(约 63 GB,4 位放不进一张 80 GB 的 A100)。

AWQ:重要的权重由激活决定,放大它再量化

Lin et al. 2023(MLSys 2024 最佳论文)。两个观察:

  1. 只保护 1% 的"显著"权重,就能大幅降低量化误差
  2. 哪些权重显著,要看激活的大小,不是看权重本身的大小——对应输入通道经常很大的那几列,对输出的影响最大

但混合精度不好用(同上),于是 AWQ 换了个等价变换:把显著通道的权重乘以 s,对应的输入除以 s,数学上输出不变:

$$Q(w\cdot s)\cdot\frac{x}{s} \quad\text{vs}\quad Q(w)\cdot x$$

为什么放大能降误差(论文的推导):四舍五入的误差平均约 $0.25\Delta$,与 w 本身无关;放大一个权重通常不会改变组内最大值,所以 $\Delta$ 基本不变。于是放大后的误差 ≈ 原误差 × $\frac{1}{s}$。显著通道的相对误差被压小了。但 s 不能太大:s 大到改变了组内最大值,$\Delta$ 跟着变大,其他通道的误差就会上升(论文在 OPT-6.7B 上 s = 2 最好)。

缩放因子按 $s = s_X^\alpha$ 选,$s_X$ 是每个输入通道激活的平均幅度,$\alpha$ 在 [0, 1] 上网格搜索。不需要反向传播,也不需要重建,所以不容易对校准集过拟合。全文用 group size 128。论文配套的推理框架 TinyChat 在桌面和移动 GPU 上比 HuggingFace 的 fp16 实现快 3 倍以上。

SmoothQuant:把激活的难度搬给权重

Xiao et al. 2022(ICML 2023),目标是 W8A8。出发点是一个不对称:权重好量化,激活难量化——激活的离群值能比大多数值大约 100 倍,而且固定出现在少数通道上。

既然离群是按通道出现的,就逐通道除掉它,再把这个因子乘到权重上:

$$Y = \big(X\,\text{diag}(s)^{-1}\big)\cdot\big(\text{diag}(s)\,W\big) = \hat X \hat W, \qquad s_j = \frac{\max(|X_j|)^\alpha}{\max(|W_j|)^{1-\alpha}}$$

$\alpha$ 控制"难度"在两边怎么分:$\alpha = 0.5$ 是 OPT 和 BLOOM 全系的通用甜点,GLM-130B 用 0.75,LLaMA 系用 0.8~0.85。缩放因子在多数位置都能离线并进前一层(线性层、LayerNorm)的参数里,不增加额外的 kernel 调用;只有输入来自残差相加时需要单独处理。

论文结果:在 OPT-175B、BLOOM-176B、GLM-130B、MT-NLG 530B 上验证,最高 1.56 倍加速、2 倍显存节省,530B 模型能放进单台机器。

三者对照

GPTQ AWQ SmoothQuant
量化对象 权重(3~4 位) 权重(3~4 位) 权重 + 激活(8 位)
核心手段 二阶误差补偿 按激活缩放显著通道 按通道把激活的幅度迁到权重
利用了什么 输入之间的相关性($H = 2XX^\top$) 通道重要性不均 离群值按通道出现
需要校准数据 要 要(不反传) 要(只统计最大值)
主要收益 显存、带宽 显存、带宽 还省算力(整数矩阵乘)

玩具实验:三种方法分别在什么条件下起作用

用 numpy 搭一个 512×512 的线性层,输入 4096 条,量化到 INT4(group 128),比较输出的相对误差 $\|WX - \widehat WX\|/\|WX\|$。GPTQ 和 AWQ 都是按论文思路写的简化版(GPTQ 不做 act-order,AWQ 只搜 α 不做 clipping),这是机制演示,不代表真实模型上的数字:

输入 X 的结构 RTN GPTQ AWQ
各维独立、无离群 0.118 0.114 0.118
各维相关、无离群 0.118 0.083 0.117
各维相关 + 6 个通道放大 20 倍 0.120 0.098 0.077

读法:

同一个实验做 W8A8(激活整张张量共用一个步长、离群通道放大到约 100 倍):直接量化误差 0.077,SmoothQuant(α = 0.5)之后 0.013。

三种方法不是互相替代,而是各自利用了激活的一种统计结构:GPTQ 用相关性,AWQ 用不均匀,SmoothQuant 用"离群值固定出现在少数通道"。

9.10量化与"2 bit / 参数"那个上限

一句话:2 bit/参数 是模型里"知识"的信息量,不是每个参数需要的存储位数。int8 不掉容量、int4 掉到约 0.7 bit/参数,说明决定损失的不只是"位数够不够装下信息",还有"量化方法能不能找准信息存在哪"。训练得越充分的模型,冗余越少,量化越伤。

先把 8.2 的数字说准

Allen-Zhu & Li 2024(Physics of Language Models 3.3)的原始结论:

条件 知识容量
每条知识在训练中出现 1000 次,bf16 2 bit/参数
同上,量化到 int8 2 bit/参数(不变)
同上,量化到 int4 0.7 bit/参数
每条知识只出现 100 次(训练不足) 约 1 bit/参数

他们做 int4 量化用的是 GPTQ。

矛盾:4 位明明大于 2 位,为什么还会掉?

一个很自然的推理是"8 位远大于 2 位所以无损,4 位开始伤害,这是信息论算出来的边界"(本文早先的版本就是这么写的,见附录 A.4)。但它只解释了一半:4 位也大于 2 位,按纯信息量比较,int4 也应该装得下。实际却掉到了 0.7,损失了 65%。

原因在于:"信息量是 2 bit"不等于"每个参数的高 2 位存着信息、低 14 位是空的"。知识是分散编码在所有参数的所有位上的(接 8.3 的叠加)。逐个参数四舍五入,相当于对每个数字独立地做有损压缩,而一个好的压缩器应该知道哪些组合重要、在全局上分配位数。打个比方:一个 54 GB 的文件里只有 6.8 GB 信息,理论上能压到 7 GB 左右;但"把每个字节的低 4 位清零"不是好的压缩办法。

证据一:量化方法越聪明,同样位数下损失越小

方法 位数 说明
RTN 8 LLM.int8() 发现直接量化在 6.7B 以上就出问题,要单独处理离群维度
GPTQ / AWQ 3~4 用二阶信息或激活统计,在组内重新分配误差
QuIP#(Tseng et al. 2024) ≤ 4,主打 2 随机 Hadamard 变换打散离群值 + E8 格点向量码本 + 微调
AQLM(Egiazarian et al. 2024) < 3 多码本加法量化,号称首个在 3 位以下做到精度—体积帕累托最优的方案

越往下越不是"逐个数取整",而是把一组参数当成一个向量来编码——更接近真正的压缩器。

Dettmers & Zettlemoyer 2022 曾得出"在总位数固定时,4 位几乎总是最优"(同样的位数预算,4 位的大模型胜过 8 位的小模型)。QuIP# 明确反驳了这个结论:用它的方法,3 位比 4 位的扩展性更好。"最优位数"不是信息论定死的常数,它随量化方法的进步往下走。

证据二:在约束下训练,比事后量化好得多

BitNet b1.58(Ma et al. 2024)从头训练时就把权重限制在 {-1, 0, 1}(每参数 log₂3 ≈ 1.58 位,激活 8 位),在 3B 规模上困惑度追平作者自己复现的 fp16 LLaMA(训练 100B token)。⚠️ 基线是作者自己训练的,规模也只到 3B,结论还需更大规模验证。

这和 2.5 的逻辑完全一样:GQA 必须从一开始就选,因为权重要在约束下长出来。事后量化(PTQ)是把一个"按 16 位训练出来"的模型硬塞进 4 位;量化感知训练(QAT)是让模型从一开始就学会只用这几个格子来编码知识。

证据三:训练越充分,越难量化

Kumar et al. 2024(Scaling Laws for Precision)发现:训练数据越多,事后量化带来的损失越大,以至于对要量化部署的模型来说,继续加预训练数据最终会有害(量化后的 loss 反而变差)。论文验证到 1.7B 参数、26B token。

这正好是 2 bit 上限的直接推论(这一句是本文的解释,论文没有这样表述):训练不足时,每个参数实际装的信息远不到上限,冗余很多,四舍五入丢掉的大多是冗余;训练越充分,信息越接近装满,冗余越少,每丢一点都是真东西。Allen-Zhu & Li 的"100 次曝光只有 1 bit/参数"说的是同一件事的另一面。

⚠️ 实践中常听到"Llama 3 比 Llama 2 更难量化",与此方向一致,但属于社区观察,这里没有找到系统的原始测量,待核实。

证据四:精度翻倍,记忆容量几乎不涨

Morris et al. 2025(How much do language models memorize?)用均匀随机数据(完全没有可泛化的规律)测 GPT 架构的记忆容量,得到约 3.6 bit/参数(bf16 训练)。把精度从 bf16 翻倍到 fp32,容量只从 3.51 涨到 3.83——多出来的 16 位几乎都没用来存东西。

⚠️ 这个 3.6 和 Allen-Zhu & Li 的 2 测的不是同一个量:前者是记随机比特串,后者是记有结构的知识三元组,模型规模和训练设置也不同,两个数不能直接比大小。但两者都指向同一个量级:模型实际用到的信息量,是每参数几个 bit,而不是 16 个。

放回 Gemma 2 27B

大小 对应每参数位数
bf16 权重文件 54.5 GB 16
int4(group 128) 约 14.2 GB 约 4.16
按 2 bit/参数 估的知识量 6.8 GB 2
按 3.6 bit/参数 估的记忆容量 约 12.3 GB 3.6

int4 文件仍然比 2 bit 估算大一倍,所以从信息量上看 int4 还有余量,余量能不能保住取决于量化方法;再往下到 2~3 位,就进入了要靠向量量化、微调或 QAT 才能守住的区间。

2 bit/参数 给的是"最少需要多少信息",不是"每个参数最少要几位"。两者之间的差距,就是量化方法还能继续进步的空间;而模型训练得越充分,这个差距越小。


第五部分:对齐

10预训练之后

10.1三段(现在是四段)

阶段 数据 目标 学什么
预训练 几十 TB 原始文本 CE loss(见 6.1) 语言本身
SFT 几万~几十万条人写的问答 还是 CE loss 格式:怎么当助手
偏好对齐 人类对回答的两两比较 奖励最大化 + KL 约束 品味:哪个回答更好
RLVR(2025 起) 可自动验证的题目 正确性 推理:怎么想对

SFT 在数学上和预训练完全一样——都是 $-\log p(\text{下一个 token})$,只是数据换成对话格式。真正的新东西从第三段开始。

为什么需要 RL:验证比生成容易

这是整件事的支点。SFT 需要人写出标准答案,但让标注员写一篇高质量回答极贵,而且人写的未必是模型能达到的最好水平。让人判断"A 和 B 哪个更好"则便宜得多,一致性也高得多。

$$\text{写一个好答案} \quad\gg\quad \text{判断两个答案孰优}$$

RLHF 的全部意义就是利用这个不对称:用廉价的比较信号,去优化昂贵的生成质量。

10.2RLHF 本体:两步

第一步,训奖励模型。拿一个 LLM,把 LM head 换成输出单标量的头,用 Bradley-Terry 模型拟合人类偏好:

$$P(y_w \succ y_l \mid x) = \sigma\big(r(x,y_w) - r(x,y_l)\big)$$

这就是 Christiano et al. 2017 那套:先用逻辑函数把偏好概率表示成奖励之差,再对观测到的偏好做极大似然。

第二步,用 PPO 优化策略:

$$\max_\pi \; \mathbb{E}\big[r(x,y)\big] - \beta\, D_{KL}\big(\pi \,\|\, \pi_{\text{ref}}\big)$$

那个 KL 项就是 7.2 讲的 KL 散度,$\pi_{\text{ref}}$ 是 SFT 模型。它防止模型为了刷高奖励而跑飞——奖励模型是个有缺陷的代理,放开优化必然被钻空子(reward hacking)。

工程上要同时持有四个模型:策略、参考、奖励、价值(critic)。显存和复杂度都很高,这是 PPO 路线最大的痛点。完整的训练循环见 10.8。

10.3DPO:把两步合成一步

推导只有三步:

① 解 KL 约束下的奖励最大化,最优策略有闭式解:

$$\pi^*(y|x) = \frac{1}{Z(x)}\,\pi_{\text{ref}}(y|x)\exp\!\Big(\tfrac{1}{\beta}r(x,y)\Big)$$

② 反解出奖励:

$$r(x,y) = \beta\log\frac{\pi^*(y|x)}{\pi_{\text{ref}}(y|x)} + \beta\log Z(x)$$

③ 代进 Bradley-Terry。关键在于 $\beta\log Z(x)$ 只依赖 prompt,两个回答相减时消掉了——那个算不动的配分函数就这么没了。

$$\mathcal{L}_{\text{DPO}} = -\mathbb{E}\left[\log\sigma\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)}\right)\right]$$

一个纯监督式损失:不用采样、不用 critic、不用奖励模型,只要两个模型(策略 + 参考)。写起来跟普通分类没区别。

10.4三个需要纠正的流行说法

⚠️ ①"DPO 不需要奖励模型"——误导

因为不训练单独的显式奖励模型,一些人误以为 DPO 完全绕开了奖励建模。实际上它学的是一个隐式奖励模型:

$$r_\theta(x,y) = \beta\log\frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)}$$

这就是论文标题 Your Language Model is Secretly a Reward Model 的意思——策略网络同时充当语言模型和隐式奖励。它没有消灭奖励建模,只是把奖励模型和策略合并成同一组参数。Bradley-Terry 假设一点没少,只是藏起来了。

⚠️ ②"DPO 和 RLHF 等价"——只在最优点等价

PPO 里 KL 惩罚显式出现在奖励中:

$$\tilde r(x,y) = r(x,y) - \beta\log\frac{\pi(y|x)}{\pi_{\text{ref}}(y|x)}$$

DPO 的 KL 约束是隐式的——重参数化假设策略已取到最优形式,从而自动满足 KL 约束。但这只在最优解处成立,优化过程中并不主动约束中间迭代。

这就是 DPO 比 PPO 更容易过拟合的原因:训练途中它可以任意跑偏,只有理论终点是对的。

⚠️ ③"DPO 效果不输 PPO"——学术榜单如此,实测不然

ICML 2024 的系统研究(Xu et al.)结论很直接:DPO 存在根本性局限,PPO 在所有测试场景下都超过其他对齐方法,并在困难的代码竞赛任务上取得当时最好结果。

具体局限:DPO 会找到利用分布外回答的有偏解,且对模型输出与偏好数据之间的分布偏移敏感。而 PPO 发挥好需要三个关键因素——优势归一化、大 batch、参考模型的 EMA 更新。

这解释了一个长期的观感差异:学术论文里 DPO 往往更好,工业界却坚持 PPO 路线。因为学术基准用固定的离线偏好数据集,正是 DPO 的舒适区;而 DPO 的软肋恰恰在"模型已经偏离数据分布之后怎么办",这在真实的迭代训练里天天发生。

10.5Likelihood displacement:最反直觉的失败模式

DPO 训练时,被偏好回答的概率经常是下降的。 叫 likelihood displacement(Razin et al. 2024)或 squeezing effect(Ren & Sutherland 2024)。

机制:$y^+$ 和 $y^-$ 往往共享大量 token 和模式,压制 $y^-$ 会连带压低共享 token 的概率,把 $y^+$ 一起拖下去。而概率必须归一化,从两者身上抽走的质量必须跑到别处去——通常是偏好对之外那些"没见过"的回答上。

一个让人不安的例子:训练模型偏好 "No" 而非 "Never",结果可以让 "Yes" 的概率大幅上升——概率质量转移到了含义完全相反的回答上。

在安全场景直接出事:该现象会降低模型对有害请求的拒答率,构成严重安全隐患。

还有个连锁反应:随着 $\pi_\theta(y^-|x)$ 趋近于零,损失对 $\pi^-$ 的梯度绝对值急剧增大,而对 $\pi^+$ 的梯度越来越小——训练重心逐渐从"学好答案"滑向"打压坏答案",而后者是个无底洞。

这也解释了 DPO 常常损害数学和推理基准:那些任务只有极少数回答是对的,任何概率位移都是灾难性的。

常见缓解手段:更小的学习率、CHES 分数筛样本、DPO-Shift、logits-SAM 等。

10.6GRPO 与 RLVR:2025 年的转折

真正改变格局的不是 DPO,是 DeepSeek。

GRPO 砍掉了 critic。对同一 prompt 采样一组回答(通常 8~64 个),给每个打分,拿组内平均值当基准——高于均值的被强化,低于的被抑制:

$$A_i = \frac{r_i - \text{mean}(\{r_1,\dots,r_G\})}{\text{std}(\{r_1,\dots,r_G\})}$$

用组内归一化的奖励替换 PPO 的价值函数,同时保留 PPO 式的 token 级重要性采样和 KL 惩罚。四个模型变三个,显存和不稳定性都大幅下降。出自 DeepSeekMath(2024),因 DeepSeek-R1(2025 年 1 月)而广为人知。

RLVR 换掉了奖励模型本身——这一步更关键。R1-Zero 刻意不用神经奖励模型,因为大规模 RL 训练下必然出现 reward hacking:训得够久,模型总会找到奖励模型的漏洞。改用可验证奖励(答案正确性 + 格式合规)让训练过程难以被钻空子。

对照 8.5 那个视角,这里的转变是:从"让人判断好不好"变成"让机器判断对不对"。数学题、代码单测、形式化证明——正确性可自动验证,于是奖励信号既免费又不可作弊。

但边界很明确:GRPO 在"单次回答 + 单一可验证结果"上表现极好,在长序列的智能体任务上就吃力——信用分配问题。一个 agent 走了 50 步失败了,每一步都拿到同样的负信号,哪怕其中有些步是对的。

10.7现状与不确定的地方

方法 适用 现状
SFT 打底 必备
DPO 及变体 轻量对齐、开源微调 广泛使用,但需防位移
PPO 通用偏好对齐 前沿实验室的主力
GRPO + RLVR 推理能力 训练推理和智能体模型的默认起点

⚠️ 不确定的部分:各家实验室的确切配方都不公开。上面那篇论文说 ChatGPT 和 Claude 用 reward-based 方法,但那是 2024 年的外部推测。公开的只有 Constitutional AI / RLAIF 那条线——用 AI 反馈替代部分人类标注。

一个仍未解决的问题:RLVR 在可验证领域效果惊人,但"写得好""有帮助""诚实"这些恰恰无法自动验证。所以偏好学习不会被取代,两条路会并存——如何把 RLVR 的可靠性带到不可验证的领域,是现在最活跃的开放问题。

接回 8.5 的统一视角:

预训练是压缩语料,对齐是在压缩结果上做筛选。 前者决定模型知道什么,后者决定它说什么。

而 RLVR 是第三种东西——它不筛选,它探索:模型自己生成候选、自己验证、自己强化。这是三段里唯一能产生训练数据中不存在的解法的阶段。

10.8训练流水线:每一步吃什么、产出什么

一句话:10.1–10.6 讲的是每种方法"为什么",这一节讲"怎么跑"。四种方法的根本差别在数据从哪来:SFT 和 DPO 吃现成的离线数据**,一步就是一次前向加反向;PPO 和 GRPO 要先让当前模型自己生成再打分,一步里要先跑一大轮推理。**

总览

预训练底座
   │  ① SFT:示范回答(人写或强模型写)
   ▼
SFT 模型(= 后面所有阶段的起点,也是参考模型 π_ref)
   ├─ ②a 训奖励模型 RM(人类两两比较)──→ ③ PPO:生成 → RM 打分 → 更新
   ├─ ②b DPO:离线偏好对,直接更新
   └─ ②c GRPO + RLVR:可验证的题目,生成一组 → 规则打分 → 更新
                                  ↓
                    对齐后的模型(各路线可以多轮迭代、混合使用)

① SFT:和预训练只差一个 loss mask

内容
输入 (prompt, 示范回答),按模型的对话模板拼成一条序列
损失 交叉熵(6.1),只算回答部分的 token
产出 SFT 模型

对话模板就是 1.2 提到的特殊控制符。Gemma 官方文档给的格式:

<start_of_turn>user
把这句话翻译成英文:猫在睡觉<end_of_turn>
<start_of_turn>model
The cat is sleeping.<end_of_turn>

loss mask:整条序列一起前向,但只有 model 那一轮的 token 计入 loss。Llama 2 论文的说法是把用户 prompt 部分的 loss 置零,只在回答 token 上反向传播。HuggingFace TRL 的 SFTTrainer 里对应两个开关:对话数据用 assistant_only_loss=True(需要对话模板里标好回答的位置),prompt-completion 数据默认就只算 completion。

packing:SFT 样本长短不一,补齐到同一长度会浪费大量算力(Krell et al. 2021 统计,最多一半的 token 是填充)。做法是把多条短样本拼进一条长序列。⚠️ 拼接后必须改注意力 mask,让每条样本只看自己,否则样本之间会互相"串"(论文称 cross-contamination),只插分隔符防不住。

数据要多少:

例子 规模 结论
InstructGPT(2022) 约 1.3 万条 prompt,训 16 个 epoch 1 个 epoch 后验证 loss 就开始过拟合,但多训几轮对奖励分和人类偏好仍有帮助
LIMA(2023) 1000 条精选样本,65B 模型 提出"表层对齐假说":知识和能力几乎都在预训练里学到,对齐只是教模型该用哪种格式回答
Llama 2(2023) 27,540 条 小节标题就叫"Quality Is All You Need"——少而精胜过多而杂

这和 10.9 的结论互相印证:SFT 主要改格式和行为,不是灌知识,所以数据不必多,LoRA 也够用。

②a + ③ RLHF(PPO):四个模型、两种计算

训奖励模型(InstructGPT 的做法):每个 prompt 让标注员给 K = 4~9 个回答排序,一次产生 $\binom{K}{2}$ 对比较。损失就是 10.2 的 Bradley-Terry,按比较对数平均:

$$\text{loss}(\theta) = -\frac{1}{\binom{K}{2}}\,\mathbb{E}_{(x, y_w, y_l)}\Big[\log\sigma\big(r_\theta(x, y_w) - r_\theta(x, y_l)\big)\Big]$$

同一个 prompt 的全部 $\binom K2$ 对放在同一个 batch 元素里训练,免得同一个回答被反复当作独立样本而过拟合。InstructGPT 只用 6B 的奖励模型(175B 的训练不稳定)。

PPO 循环,每一轮:

① 生成:策略模型对一批 prompt 采样回答            ← 推理,大头时间在这
② 打分:奖励模型给整条回答打一个分
        参考模型算每个 token 的 log 概率 → 每 token 的 KL 惩罚
        价值模型(critic)估计每个 token 位置的期望回报
③ 优势:用 GAE 把"奖励 − 价值"摊到每个 token 上
④ 更新:用 PPO 的截断目标更新策略,同时更新价值模型

优势估计用 GAE(Schulman et al. 2015),每个 token 的 TD 残差 $\delta_t = r_t + \gamma V(s_{t+1}) - V(s_t)$,再按 $\gamma\lambda$ 加权累加:

$$\hat A_t = \sum_{l=0}^{\infty}(\gamma\lambda)^l\,\delta_{t+l}$$

$\lambda = 0$ 时只看一步(方差小、偏差大),$\lambda = 1$ 时看到底(偏差小、方差大)。更新用 PPO 的截断目标(Schulman et al. 2017):

$$L^{\text{CLIP}} = \hat{\mathbb{E}}_t\Big[\min\big(\rho_t \hat A_t,\; \text{clip}(\rho_t, 1-\epsilon, 1+\epsilon)\,\hat A_t\big)\Big], \qquad \rho_t = \frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_{\text{old}}}(a_t \mid s_t)}$$

ε 常取 0.2:如果新旧策略的概率比已经朝有利方向超出 [0.8, 1.2](优势为正时比值 > 1.2,优势为负时比值 < 0.8),这个 token 就不再贡献梯度,防止一步走太远;朝不利方向偏离则照常修正。(PPO 论文把这个比值记作 $r_t(\theta)$,这里改记 $\rho_t$,免得和奖励 r 混淆。)

PPO 要同时持有的模型 训练吗 用途
策略(policy) ✅ 生成回答,被优化的对象
价值(critic) ✅ 估计期望回报,算优势
参考(reference) ❌ 冻结的 SFT 模型,算 KL
奖励(reward) ❌ 给回答打分

InstructGPT 的具体设置:KL 系数 β = 0.02(惩罚是逐 token、相对 SFT 模型算的);"PPO-ptx" 变体在目标里混入预训练数据的似然项(系数 γ = 27.8),用来缓解对齐后在公开 NLP 基准上的退化。最有名的结果:1.3B 的 InstructGPT 回答,比 175B 的 GPT-3 更受标注员偏好,参数少 100 倍。

Llama 2 没有一上来就用 PPO:前几轮只用拒绝采样微调(每个 prompt 采样多个回答,挑奖励最高的当 SFT 数据再训),之后才在拒绝采样的 checkpoint 上叠加 PPO;奖励模型也拆成了"有用性"和"安全性"两个。

②b DPO:一步就是一次有监督训练

内容
输入 离线偏好数据 $(x, y_w, y_l)$:同一 prompt 的一好一坏两个回答
需要的模型 策略(训练)+ 参考(冻结的 SFT 模型)
每一步 4 次前向:策略和参考各对 $y_w$、$y_l$ 算一次序列 log 概率;然后代入 10.3 的损失反向
不需要 生成、奖励模型、价值模型

参考模型对数据集的 log 概率可以预先算好存起来,训练时只剩策略的两次前向。论文默认 β = 0.1(摘要任务用 0.5),学习率 1e-6。

正因为不生成,DPO 只能在数据集已有的回答上学——这就是 10.4 说的"模型偏离数据分布之后怎么办"的根源。实践中常见的补救是在线/迭代 DPO(工程做法,这里不展开具体论文):用当前模型重新采样回答、打分、组成新的偏好对,再训一轮,本质上是把生成又加了回来。

②c GRPO + RLVR:规则打分、组内比较

内容
输入 有标准答案的题目(数学、代码、可自动判对错的任务)
需要的模型 策略(训练)+ 参考(冻结);没有价值模型;RLVR 下也没有奖励模型
每一步 每道题生成一组 G 个回答 → 规则判分 → 组内标准化得到优势 → 更新

DeepSeekMath 的 GRPO 目标(式 (3))在 PPO 截断目标的基础上改了三处:

$$\mathcal{J}_{\text{GRPO}} = \mathbb{E}\Bigg[\frac{1}{G}\sum_{i=1}^{G}\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}\Big\{\min\big(\rho_{i,t}\hat A_{i,t},\;\text{clip}(\rho_{i,t}, 1-\varepsilon, 1+\varepsilon)\hat A_{i,t}\big) - \beta\,\mathbb{D}_{KL}\big[\pi_\theta \,\|\, \pi_{\text{ref}}\big]\Big\}\Bigg]$$

和 PPO 比 GRPO 的做法
优势怎么来 不要价值模型,用同一题 G 个回答的奖励做组内标准化:$\hat A_{i,t} = \frac{r_i - \text{mean}(\mathbf r)}{\text{std}(\mathbf r)}$,回答里每个 token 都用这一个值(10.6)
KL 放在哪 直接加进损失,而不是像 PPO 那样扣在奖励里
KL 怎么估 用一个无偏且恒为正的估计量:$\frac{\pi_{\text{ref}}}{\pi_\theta} - \log\frac{\pi_{\text{ref}}}{\pi_\theta} - 1$(逐 token 算)

DeepSeekMath 的超参数:学习率 1e-6,KL 系数 0.04,每题采样 64 个回答,最大长度 1024,batch 1024;每轮探索之后策略只更新一次。(论文也给了"过程监督"版本:用过程奖励模型给每一步打分,优势按步累加。)

奖励怎么定:DeepSeek-R1-Zero 只用两种规则奖励——准确性(答案对不对)和格式(推理过程是否放在 <think> 和 </think> 之间),刻意不用神经网络奖励模型,因为它会被 reward hacking。

GRPO 的已知偏差和修补

工作 发现 改法
Dr. GRPO(Liu et al. 2025) 除以 $\lvert o_i \rvert$ 让长的错误回答受罚更轻 → 错误回答越写越长;除以 std 让太容易或太难的题权重偏大 去掉这两个归一化
DAPO(Yu et al. 2025) 训练中熵塌缩、长回答梯度被稀释等问题 Clip-Higher(放宽截断上限)、动态采样(丢掉全对或全错的组)、token 级损失、超长回答的奖励整形;Qwen2.5-32B 底座上 AIME 2024 达到 50 分
RLOO 等(Ahmadian et al. 2024) 在 RLHF 场景下 PPO 的很多组件是多余的 更简单的 REINFORCE 式方法(留一法基线),效果超过 PPO 和 DPO

一个完整的例子:DeepSeek-R1 的四段流水线

DeepSeek-V3-Base
  │ ① 冷启动 SFT:少量长思维链示范,解决 R1-Zero 可读性差、语言混杂的问题
  │ ② 推理导向的 RL:准确性奖励 + 语言一致性奖励(思维链里目标语言词的比例)
  │ ③ 拒绝采样 + SFT:用 ② 的模型采样,筛出约 60 万条推理数据
  │                   + 约 20 万条非推理数据(写作、问答等),共约 80 万条,
  │                   回到 V3-Base 上训 2 个 epoch
  │ ④ 面向全场景的 RL:推理题用规则奖励,通用对话用奖励模型
  ▼
DeepSeek-R1(同一批 80 万条数据也用来蒸馏小模型)

这条流水线把前面几种方法都用上了:SFT 打底、RL 学推理、拒绝采样把 RL 的成果"蒸"回 SFT 数据、最后再用 RL 对齐通用偏好。

四条路线对照

SFT PPO DPO GRPO + RLVR
数据 示范回答 prompt + 奖励模型 离线偏好对 可验证的题目
训练时要生成吗 否 是 否 是(每题 G 个)
显存里的模型 1 4(2 个训练) 2(1 个训练) 2(1 个训练)
优势/信号 逐 token 交叉熵 奖励 − 价值(GAE) 隐式奖励之差 组内标准化的奖励
主要瓶颈 数据质量 显存、稳定性、生成速度 分布偏移(10.5) 生成速度、奖励能否验证

为什么 RL 阶段的瓶颈在推理:PPO 和 GRPO 每一步都要先生成。GRPO 每题采样 64 个、每个最长 1024 token,一个 batch 就是几万条自回归生成——这正是 9.4 讲的带宽受限的解码。常见的开源 RL 框架因此把生成交给 vLLM 这类推理引擎,训练和推理各占一部分 GPU,每轮把新权重同步过去(这是工程实践的描述,不出自某篇论文)。⚠️ 训练侧和推理侧的 kernel、精度不完全一致,"生成时的概率"和"训练时重算的概率"会有细微差别——12.2 提到的推理不确定性在这里也会出现;它对 RL 稳定性的影响有多大,待核实。

四种方法的分界线是"训练时要不要自己生成数据"。 不生成的(SFT、DPO)便宜稳定,但只能学数据里有的东西;要生成的(PPO、GRPO)贵且难调,但能学到数据里没有的解法——这就是 10.7 那句"RLVR 是唯一能产生训练数据中不存在的解法的阶段"的工程含义。

10.9LoRA:只训练一个低秩的增量

一句话:微调时冻住原权重 $W_0$,只训练一个"瘦长矩阵乘扁宽矩阵"形式的增量 $BA$。Gemma 2 27B 全部线性层加秩 16 的 LoRA,可训练参数只有 1.14 亿(0.42%),优化器状态从 435 GB 降到不到 2 GB。代价是它学得少,但也忘得少。

为什么能这么做:微调的改动本来就是低秩的

LoRA(Hu et al. 2021)的出发点是一个假设:预训练好的模型在适配新任务时,权重的改动量 $\Delta W$ 有很低的"内在秩"。也就是说,虽然 $W$ 是 4608 × 36864 的大矩阵,但微调真正需要改的方向只有很少几个。

这个假设有前因:Aghajanyan et al. 2020 发现微调的"内在维度"低得惊人——在 RoBERTa-Large 上,只优化 200 个参数(再随机投影回全参数空间),就能在 MRPC 任务上达到全量微调 90% 的效果。

做法

$$h = W_0 x + \Delta W x = W_0 x + \frac{\alpha}{r} BAx, \qquad B \in \mathbb{R}^{d \times r},\; A \in \mathbb{R}^{r \times k},\; r \ll \min(d, k)$$

符号 含义
$W_0$ 原始权重($d \times k$),冻结,不算梯度、不存优化器状态
$A$ 先把 k 维输入压到 r 维,随机高斯初始化
$B$ 再从 r 维升回 d 维,初始化为 0
$r$ 秩,常用 8~64
$\alpha$ 缩放常数。论文的做法是 α 取第一次试的 r 值、之后不再调,这样改 r 时大致不用重调学习率

B 初始化为 0 是关键:训练开始时 $BA = 0$,模型和原模型完全一样,微调从原点出发。

         ┌──── W_0 (冻结, d×k) ────┐
x (k) ───┤                          ├─(+)──→ h (d)
         └── A (r×k) ──→ B (d×r) ──┘
              ↑ 只训练这两个

参数和显存账(Gemma 2 27B)

每个 $d \times k$ 矩阵加 LoRA 后多出 $r(d + k)$ 个参数。按 0.2 的单层矩阵形状算:

方案 可训练参数 占 27.2B 优化器 + 梯度 + 主权重(16 字节/参数,见 5.7)
全量微调 27.2 B 100% 435 GB
LoRA r = 16,只加在 $W_Q$、$W_V$ 11.3 M 0.04% 0.18 GB
LoRA r = 16,全部 7 个线性层 114 M 0.42% 1.8 GB
LoRA r = 64,全部 7 个线性层 457 M 1.68% 7.3 GB

冻结的原权重仍要放在显存里(bf16 下 54.5 GB),但不需要梯度和 Adam 状态。省下的是 5.7 那张表里除了"权重"以外的所有行。(激活显存另算,LoRA 省不掉它,见 9.6 和下面 QLoRA 那段。)

原论文的结果(GPT-3 175B,对比用 Adam 全量微调):可训练参数少 1 万倍,训练显存少 3 倍(1.2 TB → 350 GB);只加在 $W_Q$、$W_V$ 上、r = 4 时,checkpoint 从 350 GB 降到 35 MB。论文大部分实验只改 $W_Q$、$W_V$,并发现 r = 1 或 2 就够(d 高达 12288 时也是如此),但作者也在脚注里提醒,不指望小 r 对所有任务都管用。

推理时零开销:训练完把 $W = W_0 + \frac{\alpha}{r}BA$ 合并成一个矩阵,结构和原模型一样,不多一次乘法。不合并的话,也可以一个底座同时挂很多个 LoRA,按请求切换——每个 LoRA 文件只有几百 MB。

QLoRA:底座量化到 4 位

把冻结的 $W_0$ 用 4 位存(9.9),LoRA 的 A、B 仍用 bf16 训练。前向时把 $W_0$ 临时还原成 bf16 参与计算,梯度只流向 A、B。三个配套技术:

技术 作用
NF4(4-bit NormalFloat) 按正态分布的分位数设 16 个格点,适合大致服从正态分布的权重
双重量化 把每组的量化常数本身再量化一次,每参数再省约 0.37 位(65B 模型约 3 GB)
分页优化器 应对显存峰值:不够时把优化器状态临时换到 CPU 内存

结果(Dettmers et al. 2023):普通 16 位微调 LLaMA 65B 需要 780 GB 以上显存,QLoRA 能在单张 48 GB 的卡上微调 65B,并保持 16 位微调的任务表现;Guanaco 65B 在 Vicuna 基准上达到 ChatGPT 的 99.3%,只用单卡 24 小时。论文的另一个发现:LoRA 必须加在所有线性层上才能追平全量微调,只加在注意力上不够。

⚠️ QLoRA 论文还指出,LoRA 训练的显存大头其实是激活的梯度,不是 LoRA 参数本身(7B 模型上前者 567 MB,后者 26 MB)。所以长序列、大 batch 时,LoRA 照样会 OOM。

LoRA 不是免费的:学得少,也忘得少

Biderman et al. 2024(LoRA Learns Less and Forgets Less)在代码和数学上做了系统对比(指令微调约 10 万条、继续预训练约 200 亿 token):

全量微调 LoRA(常规低秩设置)
目标任务(代码、数学) 更好 明显更差
目标领域外的原有能力 退化更多 保留得更好
学到的改动的秩 比常规 LoRA 高 10~100 倍 被 r 卡住

⚠️ 也有例外:在通用指令数据 Tülu-v2-mix 上,LoRA 和全量微调持平。

这和 8.2 的容量视角对得上:**要往模型里灌大量新知识(继续预训练、学一门新语言),低秩增量装不下;只是改格式、风格、对齐行为,低秩增量就够了。**同一个限制带来了"忘得少":改动被限制在一个小子空间里,碰不到的方向就保持原样。

LoRA 和 RL 很搭

Thinking Machines Lab 的博客 LoRA Without Regret(Schulman & Thinking Machines Lab,2025-09)给了一组实用结论:

结论 说明
SFT 上 中小规模的指令和推理数据集,LoRA 与全量微调表现相同;数据量超出 LoRA 容量时才落后
RL 上 策略梯度类算法下,秩低到 1 也能完全追平全量微调
加在哪 加在所有权重矩阵上,尤其是 MLP / MoE 层;只加注意力层即使参数量相同也更差
学习率 LoRA 的最优学习率一贯约为全量微调的 10 倍(作者称这一条是初步观察)
batch 有些情况下 LoRA 比全量微调更不耐大 batch,增大秩也补不回来

RL 为什么秩 1 就够?一个直觉(本文的解释,不是博客原话):10.6 的 RLVR 每条回答只拿到一个标量奖励,每个 episode 带来的信息量很少,远不需要占满一个高秩的更新;SFT 每个 token 都有监督信号,信息量大得多。

几个变体

变体 改了什么
rsLoRA(Kalajdzievski 2023) 缩放因子从 $\alpha/r$ 改成 $\alpha/\sqrt r$;论文指出用 $\alpha/r$ 时秩一大梯度就会塌缩,大秩反而学不好
DoRA(Liu et al. 2024) 把权重拆成幅度和方向两部分,方向用 LoRA 更新,幅度单独学

HuggingFace PEFT 库的 LoraConfig 默认 r = 8、lora_alpha = 8;target_modules 可以设成 "all-linear",对应上面"加在所有层"的建议。

LoRA 押注的是"微调只需要改少数几个方向"。 改行为、改格式、做 RL 时这个赌注基本稳赢;要灌大量新知识时就会输,而输掉的那部分恰好也是它"忘得少"的原因。


第六部分:数学工具箱

11用到的数学

本章是查阅用的,不必顺读。每一条都标了"文档里在哪用到",按需回跳。

11.1微积分

导数:斜率

$$f'(x) = \lim_{h\to 0}\frac{f(x+h) - f(x)}{h}$$

读作"$x$ 变一个单位,$f$ 变多少"。实践中用中心差分做数值验证(比单边差分精度高一阶):

$$f'(x) \approx \frac{f(x+h)-f(x-h)}{2h}, \qquad h \sim 10^{-6}$$

本文档所有推导都用它验过。→ 5.1

偏导 vs 全微分

谁在变 形式
偏导 $\partial f/\partial u$ 只有 $u$,其余冻结 一个数
全微分 $df$ 所有变量一起变 各项之和

$$df = \frac{\partial f}{\partial u}du + \frac{\partial f}{\partial v}dv + \dots$$

长方形直觉:$f = uv$ 是面积,两边各增一点:

        u        du
     ┌───────┬────┐
   v │  uv   │v·du│ ← 宽 du,高 v
     ├───────┼────┤
  dv │  u·dv │ ▪▪ │ ← du·dv,二阶小,扔掉
     └───────┴────┘
        ↑
     宽 u,高 dv

$$df = v\,du + u\,dv$$

角落那块是两个小量相乘,$du,dv$ 各缩小 10 倍它缩小 100 倍,可忽略。

为什么重要:5.3 的扇出规则就是全微分——$x$ 走了残差和支路两条路,两份贡献必须相加($2.0 + 3.0 = 5.0$)。只算一条是偏导,不是答案。

求导四法则

法则 公式 文档里
和 $(u+v)' = u' + v'$ 残差 $x + F(x)$
积 $(uv)' = u'v + uv'$ $y=wx$ 的两个梯度
商 $\left(\frac uv\right)' = \frac{u'v-uv'}{v^2}$ 4.4 推 norm 的雅可比
复合(链式) $\big(f(g(x))\big)' = f'(g)\cdot g'(x)$ 反向传播的全部

商法则不是独立规则——把 $\frac uv$ 写成 $uv^{-1}$,用积法则 + 链式法则即得:

$$(uv^{-1})' = u'v^{-1} + u(-v^{-2}v') = \frac{u'v - uv'}{v^2}$$

那个减号的直觉:分子变大 → 分式变大(同向,加);分母变大 → 分式变小(反向,减)。

链式法则:斜率相乘

$$\frac{\partial L}{\partial w} = \frac{\partial L}{\partial y}\cdot\frac{\partial y}{\partial u}\cdot\frac{\partial u}{\partial w}$$

齿轮比喻:传动比 3 接传动比 2 = 总传动比 6。→ 5.2

多路径时各路相加(全微分):

$$\frac{\partial L}{\partial x_j} = \sum_i \frac{\partial L}{\partial \hat x_i}\cdot\frac{\partial \hat x_i}{\partial x_j}$$

常用导数速查

$f(x)$ $f'(x)$ 文档里
$x^n$ $nx^{n-1}$ 平方误差 $(\hat y-y)^2$
$e^x$ $e^x$ softmax
$\ln x$ $1/x$ CE loss
$\sqrt x$ $\frac{1}{2\sqrt x}$ $\sigma$ 从 $\sigma^2$ 反解
$\text{ReLU}(x)$ $1$($x>0$)或 $0$ 3.3
$\text{sigmoid}(x)=\sigma$ $\sigma(1-\sigma)$ Bradley-Terry
$\tanh x$ $1-\tanh^2 x$ —
$\text{GELU}(x) = x\Phi(x)$ $\Phi(x) + x\phi(x)$ 3.1

两个组合结果特别干净:

$$\frac{\partial}{\partial z_j}\text{softmax}(z)_i = p_i(\delta_{ij} - p_j) \qquad\Longrightarrow\qquad \boxed{\frac{\partial L_{CE}}{\partial z_k} = p_k - y_k}$$

softmax 的 $p(1-p)$ 和 log 的 $1/p$ 恰好抵消。→ 6.4

雅可比矩阵

多进多出时,"导数"变成矩阵:

$$J_{ij} = \frac{\partial y_i}{\partial x_j} \qquad(\text{行=输出,列=输入})$$

函数 雅可比
逐元素操作(ReLU) 对角阵,只存对角线即可
norm、softmax 稠密,非对角线非零

反向传播传梯度就是乘转置:$g_{\text{in}} = J^\top g_{\text{out}}$。→ 4.4、5.3

Kronecker delta

$$\delta_{ij} = \begin{cases}1 & i=j\\ 0 & i\ne j\end{cases}$$

就是单位矩阵 $I$ 的分量写法,也是"只有下标相同才有直接贡献"的紧凑记号。→ 4.4

11.2线性代数

向量与内积

$$\langle u, v\rangle = u^\top v = u\cdot v = \sum_i u_iv_i$$

三种写法同一个东西。对应位置相乘再全部加起来,结果是一个数。

$$\langle [1,2,3],\ [4,5,6]\rangle = 4+10+18 = 32$$

内积在文档里有三种不同含义,但算法一样:

出处 含义
2.3 attention $q\cdot k$ = 相似度,"问题和宣传对不对得上"
1.3 出口 $\langle h, E_k\rangle$ = logit 打分
4.2 $\|v\|^2 = \langle v,v\rangle$ = 长度平方

长度(范数)

$$\|v\| = \sqrt{\sum_i v_i^2}$$

就是勾股定理推广到 $d$ 维:每加一个坐标轴,它垂直于前面所有轴张成的空间,于是再用一次勾股定理,多一个平方项。

$$\text{RMS}(v) = \frac{\|v\|}{\sqrt d}$$

→ 4.2、4.3

矩阵乘法

$$(AB)_{ij} = \sum_k A_{ik}B_{kj}$$

形状是最好的检查工具:$(m\times n)(n\times p) = (m\times p)$,中间的 $n$ 必须对上并消掉。

类型 形状 算术强度 文档里
矩阵×向量 $(n\times d)(d\times 1)$ 低(每权重用一次) 解码 1 个 token
矩阵×矩阵 $(n\times d)(d\times k)$ 高(每权重用 $k$ 次) prefill、大 batch

这个区别是 9.4 和 9.5 的全部基础。

转置

$$(A^\top)_{ij} = A_{ji}, \qquad (AB)^\top = B^\top A^\top$$

为什么反向传播到处是转置:内积移项的必然结果——

$$\langle u,\ Av\rangle = \langle A^\top u,\ v\rangle$$

展开成求和就一目了然,两边都是 $\sum_{i,j}u_iA_{ij}v_j$,只是加的顺序不同。→ 5.3

外积与秩 1

$$(uv^\top)_{ij} = u_iv_j$$

内积出一个数,外积出一个矩阵。它的秩恒为 1——所有列都是 $u$ 的倍数。

出处 用法
4.4 $\hat x\hat x^\top$、$\mathbf{1}\mathbf{1}^\top$ 是雅可比的两项
5.3 参数更新 $\Delta W = -\eta\,g\,x^\top$ 是秩 1 的
8.1 ROME 编辑事实用的就是秩 1 修改

$\mathbf 1 = [1,1,\dots,1]^\top$,所以 $\mathbf{1}\mathbf{1}^\top$ 是全 1 矩阵。

正交与高维直觉

$$u \perp v \iff \langle u,v\rangle = 0$$

高维空间里随机两个向量几乎必然接近垂直。实测随机向量夹角余弦的绝对值:

维度 平均 $|\cos\theta|$
3 0.527
100 0.087
4608 0.012

维度越高越接近正交。这条性质撑起了文档里两个重要结论:

单位矩阵

$$I v = v, \qquad IA = AI = A$$

反向传播里 $I$ 代表"梯度原样通过"——4.7 那个"纯直通项"就是它。

11.3概率论

分布与期望

概率分布:$p_i \ge 0$ 且 $\sum_i p_i = 1$。期望是加权平均:

$$\mathbb{E}[X] = \sum_i p_i x_i$$

7.1 的熵就是"码长的期望"。

标准正态分布:PDF、CDF、Φ 与 erf

标准正态分布(μ=0,σ=1)的概率密度函数(PDF):

$$\varphi(z) = \frac{1}{\sqrt{2\pi}}\,e^{-z^2/2}$$

密度不是概率——连续分布取到任意一个精确值的概率严格为 0,真正有意义的是一段区间下方的面积。

CDF(累积分布函数)对任意分布的通用定义是"从 −∞ 累加到 x 的面积";PDF 恒 ≥0,所以 CDF 只增不减,从 0 爬到 1。标准正态的 CDF 专门记作大写 Φ:

$$\Phi(x) = P(Z\le x) = \int_{-\infty}^{x}\varphi(z)\,dz$$

关键性质:Φ(0)=0.5(左右对称);Φ(−x)=1−Φ(x);两端分别趋于 0 和 1 但永远碰不到。

为什么会冒出 erf:这个积分没有初等函数的原函数(跟 sin、cos、log 一样),数学家把这一类"高斯型积分"单独定义成误差函数:

$$\text{erf}(x) = \frac{2}{\sqrt\pi}\int_0^x e^{-t^2}\,dt$$

奇函数,erf(0)=0,值域 (−1,1),跟 Φ 是同一族 S 形曲线,只是中心和量程不同。

推导:换元把 Φ 变成 erf 的形式(令 z=√2·t):

$$\Phi(x) = \int_{-\infty}^{x}\frac{1}{\sqrt{2\pi}}e^{-z^2/2}dz = \frac{1}{\sqrt\pi}\int_{-\infty}^{x/\sqrt2}e^{-t^2}dt$$

从 0 处拆成两段:前段是总面积的一半 √π/2,后段代入 erf 定义,化简得:

$$\boxed{\Phi(x) = \frac12\Big[1+\text{erf}\big(x/\sqrt2\big)\Big]}$$

关键值表:

x −2.0 −1.0 −0.5 0 0.5 1.0 2.0
Φ(x) 0.0228 0.1587 0.3085 0.5000 0.6915 0.8413 0.9772

回到 GELU(见 3.1):GELU(x)=x·Φ(x) 用的正是这个 Φ——"x 有多大概率会被判定为该保留"的软性开关,处处光滑可导,这是它比 ReLU 训练更稳的来源之一。库函数里的 torch.erf 算的就是上面这个积分,算力紧张时也常用 tanh 近似整条 GELU 曲线省算力。

Softmax:把任意实数变成分布

$$p_i = \frac{e^{z_i}}{\sum_j e^{z_j}}$$

$z$ 叫 logits,可以是任意实数(有正有负)。指数把它们全变成正数,除以总和让它们加起来等于 1。

三个性质:

性质 说明
平移不变 $\text{softmax}(z) = \text{softmax}(z+c)$,绝对尺度被丢弃
指数放大差异 $[1,2,3]\to[0.09,0.24,0.67]$;$[10,20,30]\to$ 几乎 $[0,0,1]$
永不为零 输出严格大于 0,这是 5.5 出口梯度稠密的原因

温度:$p_i \propto e^{z_i/T}$。$T\to 0$ 退化成取最大值(贪心),$T\to\infty$ 趋于均匀分布。

似然与对数似然

模型给一整句话的概率是连乘(链式法则的直觉、逐项拆解见 0.4):

$$P(w_1\dots w_n) = \prod_t P(w_t\mid w_{<t})$$

几千个小数连乘会数值下溢(直接变成 0),所以取对数变加法:

$$\log P = \sum_t \log P(w_t\mid w_{<t})$$

取负号变成最小化,就是 CE loss。→ 6.4

熵、交叉熵、KL

$$H(p) = -\sum_k p_k\log p_k, \qquad H(p,q) = -\sum_k p_k\log q_k$$

$$H(p,q) = H(p) + D_{KL}(p\|q)$$

三者的完整讲解在第 7 章,这里只列公式。$D_{KL} \ge 0$ 且仅当 $q=p$ 时取零——这就是它能当"分布距离"用的全部依据(虽然它不对称,不是真正的距离)。

Bradley-Terry 模型

把"A 比 B 好"这种比较,转成概率:

$$P(a \succ b) = \sigma\big(r_a - r_b\big) = \frac{1}{1+e^{-(r_a-r_b)}}$$

只依赖分数之差,所以 $r$ 的绝对值没有意义(整体加个常数不变),和 softmax 的平移不变是同一件事。→ 10.2

One-hot 与求和塌缩

$$y = [0,\dots,1,\dots,0] \qquad\Longrightarrow\qquad \sum_k y_k f_k = f_{\text{正确那个}}$$

因为 $0 \times$ 任何数 $= 0$。这个塌缩在文档里出现过两次,机制完全相同:

出处 塌缩成
1.3 embedding 矩阵乘 → 查表($O(d)$ 而非 $O(Vd)$)
6.1 CE loss 25.6 万项求和 → 一次索引

one-hot 遇上求和,必然退化成索引。

方差、标准误与中心极限定理(12 章用)

概念 公式 一句话
方差 $\text{Var}(X) = \mathbb{E}[(X - \mathbb{E}X)^2]$ 偏离均值的平均平方距离
0/1 变量的方差 $p(1-p)$ p = 0.5 时最大(0.25),p 接近 0 或 1 时趋于 0
独立和的方差 $\text{Var}(X + Y) = \text{Var}X + \text{Var}Y$ 不独立时要加 $2\,\text{Cov}(X,Y)$
样本均值的方差 $\text{Var}(\bar X) = \sigma^2 / n$ n 个独立样本平均,方差缩小 n 倍
标准误 $\text{SE} = \sigma / \sqrt n$ 样本均值的标准差;样本量翻 4 倍,误差才减半

中心极限定理:不管单个 $X_i$ 是什么分布(哪怕只取 0 和 1),只要独立同分布、方差有限,n 足够大时 $\bar X$ 近似服从正态分布 $\mathcal{N}(\mu, \sigma^2/n)$。所以"$\bar x \pm 1.96\,\text{SE}$"能当 95% 区间用——1.96 满足 $\Phi(1.96) = 0.975$(上面关键值表里 x = 2.0 对应 0.9772,略大一点),两侧各留 2.5%,中间正好 95%。"n 足够大"是前提,n 小时它会失灵(见 12.1)。

全方差公式:随机性分两层时(先抽 Y,再在 Y 给定的条件下抽 X),

$$\text{Var}(X) = \underbrace{\mathbb{E}\big[\text{Var}(X \mid Y)\big]}_{\text{层内}} + \underbrace{\text{Var}\big(\mathbb{E}[X \mid Y]\big)}_{\text{层间}}$$

评测里 Y 是"抽到哪道题"、X 是"这道题这次答没答对":层间方差是题目难度不同带来的,层内方差是同一题多次作答的随机性。12.2 的分解就是它。


第七部分:评测

12评测统计:一个分数有多可信

前面各章讲的是模型怎么做出来;这一章讲做出来之后,"A 比 B 高 2 分"这句话什么时候能信。数学基础(期望、方差、中心极限定理)见 11.3。

12.1一个分数也是一次抽样

一句话:基准上的准确率是"从所有可能的题目里抽了 n 道"的样本均值,它有标准误。题目越少,误差越大:30 道题的 AIME,95% 置信区间宽约 ±16 个百分点;1.4 万题的 MMLU 才缩到 ±0.7。

把评测写成统计问题

设第 i 道题的得分是 $x_i$(答对 1、答错 0,或者 0~1 之间的分数),一共 n 道。报告的分数是样本均值:

$$\bar x = \frac{1}{n}\sum_{i=1}^n x_i$$

这些题目可以看成从一个"所有可能的同类题"的总体里抽出来的。换一批同样难度的题,分数会变。这种波动的大小就是标准误(standard error, SE)。Anthropic 的 Miller 2024(Adding Error Bars to Evals)把评测写成的就是这套标准做法(式 (1)–(3)):

$$\text{SE} = \sqrt{\frac{s^2}{n}}, \qquad 95\%\ \text{置信区间} = \bar x \pm 1.96\,\text{SE}$$

符号 含义
$s^2$ 题目得分的样本方差;0/1 得分时就是 $\bar x(1-\bar x)$。⚠️ 得分是 F1 这类 0~1 之间的分数时不能套 $\bar x(1-\bar x)$,那样会把区间估得过宽(Miller 举了 Llama 3 报告的例子)
1.96 标准正态分布 97.5% 分位数,来自中心极限定理

具体有多大

基准规模 准确率 SE 95% 置信区间
30 题(AIME 一年的题量) 50% 9.1 pp ±17.9 pp
30 题 70% 8.4 pp ±16.4 pp
500 题 70% 2.0 pp ±4.0 pp
1,000 题 80% 1.3 pp ±2.5 pp
14,042 题(MMLU 测试集) 80% 0.34 pp ±0.66 pp

(pp = 百分点。)30 道题时,一道题就是 3.3 个百分点;两个模型差 5 分,可能只是多对了一道半题。

榜单上的数字后面没有误差棒,不代表误差不存在,只代表没算。

小样本时别用 ±1.96 SE

上面的公式靠中心极限定理,n 小或准确率接近 0、1 时会失灵。Bowyer et al. 2025(ICML 2025 立场论文)的标题就是"题目少于几百道时别用 CLT":这类区间通常严重低估不确定性,在小 n 下只有贝叶斯可信区间和 Wilson 区间能达到名义覆盖率。统计学里这个问题早有定论:Brown, Cai & DasGupta 2001 指出正态近似(Wald)区间的覆盖率表现"混乱",小 n 时推荐 Wilson 或 Jeffreys 区间。最极端的例子:30 题全对,$\bar x = 1$,$s^2 = 0$,区间缩成一个点 [1, 1]——显然不对。

Wilson 区间是常用的替代(k 道答对、共 n 道、$\hat p = k/n$、$z = 1.96$):

$$\frac{\hat p + \frac{z^2}{2n}}{1 + \frac{z^2}{n}} \;\pm\; \frac{z}{1 + \frac{z^2}{n}}\sqrt{\frac{\hat p(1-\hat p)}{n} + \frac{z^2}{4n^2}}$$

30 题答对 正态近似(Wald) Wilson
27 道(90%) [79.3%, 100.7%] [74.4%, 96.5%]
30 道(100%) [100%, 100%] [88.6%, 100%]

Wald 区间会越过 100%,或者缩成一个点。拿模拟检验(与上面两篇论文的结论一致):真实准确率 90%、每次抽 30 题、重复 2 万次,名义 95% 的 Wald 区间实际只覆盖了 81% 的情况,Wilson 覆盖 97%(本文的模拟)。

12.2多次采样:两种方差,只有一种能靠重跑消掉

一句话:分数的波动有两个来源:抽到了哪些题(题目方差),和同一道题模型每次答得不一样(采样方差)。每题多采样 K 次,后者按 1/K 缩小,前者纹丝不动——它只能靠更多的题来减小。

两层随机性

来源 是什么 怎么减小
题目方差 第 i 题本身难不难;换一批题分数就变 只能加题
采样方差 温度 > 0 时,同一题每次生成不同;第 i 题的真实答对率是 $p_i$,单次结果是 0 或 1 每题多采样 K 次取平均

设每道题采样 K 次、取平均。按全方差公式(11.3),Miller 2024 §3.1 给出的分解是($x_i$ 记第 i 题的真实答对率 $p_i$,$\sigma_i^2 = p_i(1-p_i)$ 是单次作答的方差):

$$\text{Var}(\bar x) = \frac{1}{n}\Big(\underbrace{\text{Var}(p_i)}_{\text{题目方差}} + \underbrace{\frac{\mathbb{E}[p_i(1-p_i)]}{K}}_{\text{采样方差}}\Big)$$

模拟:30 道题,每题真实答对率从 Beta(2, 1) 抽(平均约 67%),固定这 30 道题,反复重跑整个评测:

每题采样 K 次 重跑之间分数的标准差
1 7.7 pp
4 3.9 pp
16 1.9 pp
64 1.0 pp
对照:换一批题造成的标准差 3.5 pp(与 K 无关)

读法:只采样 1 次时,重跑一遍的波动(7.7 pp)比换一批题(3.5 pp)还大,所以"跑一次就报分"的数字里有一大半是运气。K 加到 16 以上,采样方差已经小于题目方差,再加 K 收益很小——这正是 Miller 的说法:一旦 $\mathbb{E}[\sigma_i^2]/K \ll \text{Var}(p_i)$,继续加 K 几乎没用。

实测也是这个量级:Hochlehnert et al. 2025 在 AIME'24(30 题)、AMC'23(40 题)上把 9 个推理模型各跑 20 次,pass@1 在不同随机种子间的标准差有 5~15 个百分点;他们建议小基准至少跑 30 个种子。同一模型换不同的计算集群,AIME'24 分数也能差到 6~8 个百分点。

别靠调低温度来降方差。 Miller 专门有一节叫"别碰恒温器":把温度调到 0,单题的采样方差 $\sigma_i^2$ 确实没了,但每道题的结果变成确定的 0 或 1,题目方差 $\text{Var}(p_i)$ 反而变大,总方差不降反升(他的例子里最小方差从 1/12 升到 1/4)。不需要思维链的选择题,更好的办法是直接读答案选项的 next-token 概率当作分数,相当于 K → ∞。

⚠️ 温度 0 也不一定可复现。 Thinking Machines 的博客 Defeating Nondeterminism in LLM Inference(Horace He & Thinking Machines Lab,2025-09)用 Qwen3-235B 在温度 0 下对同一 prompt 生成 1000 次,得到 80 种不同的输出,第一次分叉出现在第 103 个 token。原因不是 GPU 并发,而是推理服务的 batch 大小随负载变化,而常用 kernel 的计算结果不是"batch 无关"的(浮点加法不满足结合律,batch 一变,累加顺序就变)。换成 batch 无关的 kernel 后,1000 次完全一致。所以"temperature 0 只跑一次"不能等同于"没有采样方差"。

pass@k:采样 n 次,估计"k 次里至少对一次"

代码、数学推理常报 pass@k。直接采样 k 次、看有没有对的,估计方差很大;Codex 论文的做法是每题采样 n ≥ k 次,数出其中 c 次正确,用无偏估计:

$$\text{pass@}k = \mathbb{E}_{\text{题目}}\left[1 - \frac{\binom{n-c}{k}}{\binom{n}{k}}\right]$$

直觉:$\binom{n-c}{k}/\binom{n}{k}$ 是"从 n 次里随机挑 k 次、恰好全挑到错误答案"的概率。Codex 论文用 n = 200、k ≤ 100,并给了数值稳定的实现(直接算组合数会溢出)。

⚠️ 看起来更顺手的 $1 - (1-\hat p)^k$($\hat p = c/n$)是有偏的,论文附录证明它会系统性低估。模拟(真实单次答对率 10%,n = 10,k = 5):真实 pass@5 = 40.9%,无偏估计平均 40.9%,朴素公式平均 34.8%——系统性低估 6 个百分点。原因是 $1 - (1-p)^k$ 是 p 的凹函数,先估 p 再代进去会偏小(Jensen 不等式)。

12.3比较两个模型:用配对,别用两个独立区间

一句话:两个模型在同一批题上测,它们的得分是正相关的(难题大家都错)。比较时应该看每道题上的分差,再算分差的标准误;把两个模型各自的置信区间画出来看重不重叠,会把误差高估。

配对差

对每道题算 $d_i = x_i^{(B)} - x_i^{(A)}$,比较的就是 $\bar d$ 和它的标准误:

$$\text{SE}(\bar d) = \sqrt{\frac{\text{Var}(d_i)}{n}}, \qquad \text{Var}(d_i) = \text{Var}(x^{(A)}) + \text{Var}(x^{(B)}) - 2\,\text{Cov}(x^{(A)}, x^{(B)})$$

两个模型越相关,协方差项减掉的越多,分差的标准误就越小。Miller 2024 式 (7) 之后给的等价写法是 $\text{SE}_{A-B} = \sqrt{\text{SE}_A^2 + \text{SE}_B^2 - 2\,\text{SE}_A\text{SE}_B\,\text{Corr}(s_A, s_B)}$,并称之为"白送的方差缩减"。

模拟:500 道题,题目难度分布两头重(有很多大家都会、也有很多大家都不会的题),模型 B 在每题上的真实答对率比 A 高 3 个百分点,两个模型独立作答。

方法 分差的标准误
当成两个独立样本 3.1 pp
配对 2.2 pp
对照:重复 2000 次实验,分差的真实标准差 2.25 pp

两个模型逐题得分的相关系数约 0.5,配对的估计和真实值吻合,独立样本的算法高估了约 40%。高估误差意味着真实存在的差距更难被检出。

0/1 得分的配对检验:McNemar

只看两个模型"一对一错"的题:A 对 B 错的有 b 道,A 错 B 对的有 c 道(两个都对、都错的题不提供比较信息):

$$\chi^2 = \frac{(b - c)^2}{b + c}$$

自由度 1,大于 3.84 即在 5% 水平显著。b + c 小于 25 左右时,传统建议改用精确的二项检验。

题目不独立时:聚类标准误

阅读理解类基准常常是一篇文章配好几道题,同一篇文章的题目对错高度相关。这时把它们当成独立样本,n 被高估,标准误被低估。做法是按文章(簇)聚类计算标准误,把同簇题目之间的协方差加回来(Miller 2024 式 (4)):

$$\text{SE}_{\text{clustered}} = \Big(\text{SE}^2 + \frac{1}{n^2}\sum_{c}\sum_{i}\sum_{j \ne i}(s_{i,c} - \bar s)(s_{j,c} - \bar s)\Big)^{1/2}$$

Miller 用 Anthropic 模型的实测(表 4):

基准 簇是什么 聚类 SE ÷ 朴素 SE
DROP 同一篇文章 3.05
MGSM 同一道题的不同语言版本 1.88
RACE-H 同一篇文章 1.10

要多少题才够:Miller 的功效分析(式 (9))给出一个例子:想以 80% 的把握检出 3 个百分点的真实差距(显著性 5%),在他假设的方差下大约要 969 道题,所以他建议新建的评测至少有 1000 道题。

12.4评测数字里的其他噪声源

噪声源 现象 应对
prompt 格式 Sclar et al. 2023:只改分隔符、大小写、空格等不影响语义的格式,LLaMA-2-13B 的准确率最多差 76 个百分点;50 多个任务、多个模型上平均差约 10 个百分点 报告时固定并公开模板;多个格式取平均或报范围
训练随机种子 Madaan et al. 2024:10 个只差初始化种子的 7B 模型,多数基准上种子间标准差小于 95% 置信区间的宽度,但不可忽略(如 HumanEval 1.1 pp) 比较训练方法时要多种子;小模型上改用连续指标(如正确答案的概率)信噪比高得多
推理设置 温度、top-p、最大长度、硬件和推理框架都会改变分数 一并报告
小基准 AIME 这类只有几十题的基准,一题几个百分点 多次采样 + 报区间;结论要保守
Arena 排名 Chatbot Arena(Chiang et al. 2024)用人类两两投票拟合 Bradley-Terry 模型(同 10.2 的奖励模型)得到分数 看置信区间:论文比较了自助法和"三明治"稳健标准误,上线用的是后者;区间重叠的名次没有意义

最小报告清单

  1. 题数 n,以及每题采样次数 K 和温度
  2. 分数 + 95% 置信区间(n 小时用 Wilson 或贝叶斯区间)
  3. 比较两个模型时报配对差及其区间
  4. 有成组题目时用聚类标准误
  5. prompt 模板、推理框架和版本

评测分数是带误差的测量值。 误差有两层:换题的误差只能靠加题减小,重跑的误差可以靠多次采样减小;比较两个模型时,配对能把共同的题目难度抵消掉。


附录 A:勘误与易踩的坑

A.1 原图(Gemma 2 幻灯片)的两处错误

项 原图 正确
KV cache 用的 head 数 32(Num heads) 16(Num KV heads) — 表里明写了 GQA
每 token 大小 753664 B (736 KB) 376832 B (368 KiB)
A100 能放 114k tokens ≈ 6.8 万(原式把整张卡都给了 KV cache,没扣 54.5 GB 权重)

A.2 论文与 config 的口径不一致

项 论文 HF config 原因
Feedforward dim 73728 intermediate_size = 36864 论文把 gate 和 up 两个并行投影加在一起报
Vocab size 256128 vocab_size = 256000 256000 已能被 128 整除,差出的 128 不是对齐填充;原因论文未说明,待核实(见 1.2)

看到门控结构(GeGLU/SwiGLU)时,论文报的 FFN 维度要留意是不是已经乘了 2。

A.3 Gemma 2 27B 特有的缩放因子

注意力缩放用的是 1/√144,不是 1/√head_dim = 1/√128。config 里有单独的 query_pre_attn_scalar: 144(恰好 = d_model/n_heads),而 2B/9B 的这个字段 = head_dim = 256。

当年不少推理实现在这里踩过坑——输出质量悄悄劣化但不报错。

A.4 早先写得不准确、后来修正的地方

原话 修正
"256128 = 256000 真 token + 128 个对齐用的占位" 公开权重的词表是 256000,而 256000 本身已能被 128 整除;256128 是论文报的数,差值原因待核实(见 1.2)
"KV cache 用 144 算多 15%" 混用了 KB/KiB,正确比例是 11%
"注意力把 4608 切成 32 段" 应为先投影到 4096 再切,没有任何东西被丢掉(见 2.2)
"32 个头各自看历史时权重加起来是 1" 有歧义。精确表述见 2.3:某一个头里的某一个 query 对所有可见 key 之和 = 1
投机解码期望 3.4 个、加速 2.9× 精确计算是 3.29 个、2.7×(见 9.5)
"GQA 不省 FLOPs" 说过头了。attention 核心确实不省,但 QKV 投影省,合计约 3%(见 2.5)
"LN 只改尺度,不改方向;正负、排序、相对比例全部保留" 只对 RMSNorm 成立。LayerNorm 的减均值是垂直投影,会改方向、翻正负、破坏比例(见 4.5)
"Gemma 2 是 Post-LN,post 压住残差流膨胀" Gemma 的 norm 加在支路输出上而非和上,残差直通轴是干净的;且它锁住每层贡献幅度,并不消除 $\sqrt{L}$ 增长(见 4.7)
"取 γ=σ、β=μ 就恢复成恒等映射" 论证有漏洞。$\sigma$ 逐 token 现算,$\gamma$ 是全体共用的固定参数——逐 token 的尺度被永久丢弃了(见 4.1)
"归一化后每维被压成同样的分布" 错。LN 沿特征轴归一化,只约束整个向量的和与长度;逐维标准化的是 BatchNorm(见 4.1)
"尺度每层被强制归零重来" 错。残差流主干从未被归一化,只有送进支路的拷贝被 norm 处理——否则本节"残差流按 $\sqrt{L}$ 膨胀"就不成立了(见 4.1)
"γ 可被 weight decay 约束,行为可控" 容易误解。主流实现通常把 norm 参数排除在 decay 之外;$\gamma$ 的价值是尺度成了显式参数、可选择约束与否(见 4.1)
"int8 无损、int4 开始伤害容量,这是信息论算出来的边界"(8.2 旧版) 说过头了。int4 的 4 位同样大于 2 bit,容量却从 2 掉到 0.7 bit/参数;损失来自逐参数四舍五入这种粗糙的编码方式,不是信息量装不下(见 9.10)
"后续工作把 GPT 类估计上修到 ~3.6 bit/参数"(8.2 旧版) 不是"上修"。Morris et al. 2025 的 3.6 测的是记忆随机数据的容量,和 Allen-Zhu & Li 的知识容量是两个不同的量,不能直接比(见 9.10)
"DeepSeek-V2 用 MLA 把 KV cache 减少 93.3%" 93.3% 是论文摘要的数字,但部署时 KV cache 还被压到平均 6 bit;按 config 只算元素个数,MLA 本身的减少约 82%(见 2.11,属推算)
"GPTQ 让 OPT-175B 能在单张 A100 上运行" 只对 3 位成立;4 位约放不进 80 GB(见 9.9)
2.3 只给了 $A_{ij} = \exp(s_{ij})/\sum\exp(s_{ij'})$,没说 $s_{ij}$ 怎么来 补上了打分(含 $1/\sqrt{d_{\text{head}}}$ 缩放)、mask、softmax 三步和数值例子;9.7 原来写的 $S = QK^\top$ 省略了缩放、$\text{softmax}(s_i)$ 与 2.3 下标不一致,现已对齐并加对照表(见 2.3、9.7)

A.5 概念上最容易混的几组

A B 区别
词表 embedding 表 词表是清单(0 参数,训练前定死);embedding 表是数字(1.18B 参数,训练学出来)
d_model 序列长度 每个词多"厚" vs 有几个词。10 个词是 10 × 4608,行数变列数不变
head_dim d_model / n_heads 现代模型已解耦,必须从 config 读
注意力权重 A W_Q/W_K/W_V A 是每次前向现算现扔的中间结果,不在模型文件里
tied 初始化相同 tied 是共享同一个张量到训练结束,梯度加到同一块内存
稀疏梯度 梯度很小 稀疏 = 严格等于 0(没参与前向),不是"数值小"
前向的 loss 反向的梯度 one-hot 下 loss 只看 1 项,梯度动全部 25.6 万项
激活函数 softmax 逐元素变换特征 vs 整行归一化成概率
上游梯度 下游梯度 跟着梯度走不跟数据走:上游=靠近 loss,下游=靠近输入(见 5.3)
Pre-LN / Post-LN 里的 LN $\text{LN}(x)$、$J^{LN}$ 里的 LN 前者泛指归一化层的位置(Gemma 用 RMSNorm 也叫 Post-LN),后者特指 LayerNorm(见 4.7)
经典 Post-LN Gemma 的 post-norm 前者 LN 套在加号外(流不涨、直通轴被挡),后者套在里(流照涨、直通轴干净)——两者收益完全不同(见 4.7)
$\hat x$(4.4) $\hat y$(5.2)/ $\hat m,\hat v$(5.6) 帽子只表示"处理后的版本",具体处理各不相同
GQA MLA GQA 是头之间共享同一份 K/V(组内 K 相同);MLA 是所有头共用一个压缩向量,每个头解出的 K 各不相同(见 2.11)
困惑度能外推 能用上长上下文 前者只说明位置编码没出分布;ALiBi 困惑度外推好,但远处 token 被压得几乎看不见(见 2.10)
总参数 激活参数 MoE 的显存和读权重带宽按总参数算,FLOPs 按激活参数算(见 3.6)
每参数存储位数 每参数信息量 前者是 16 / 8 / 4;后者是 ~2 bit 的知识量。信息量小于位数不等于可以随便砍位数(见 9.10)
题目方差 采样方差 前者来自抽到哪些题,只能加题减小;后者来自同一题每次答得不同,可以靠每题多采样 K 次减小(见 12.2)
标准差 标准误 前者描述单道题得分的离散程度;后者是平均分的不确定度,等于标准差 ÷ $\sqrt n$(见 11.3)
两个区间不重叠 差距显著 同一批题上比较两个模型应该看配对差的区间;"区间重叠就不显著"会把误差高估(见 12.3)
DPO 的参考模型 PPO 的价值模型 前者冻结、只用来算 log 概率比;后者要训练、用来估计期望回报。GRPO 只保留了参考模型(见 10.8)

A.6 代码层面的常见 bug


附录 B:延伸——自动化的边界(非技术)

这部分是从"压缩即智能"引申出来的讨论,不是技术结论,记录下来备查。

B.1 推论里的跳跃

信息可压缩 → 可检索 → ? → 可执行

第三个箭头不是自动的。

B.2 预测 ≠ 干预(Pearl 因果阶梯)

层级 问题形式 例子
1. 关联 P(y|x) 看到湿地面,推断下过雨
2. 干预 P(y|do(x)) 我去洒水,会怎样
3. 反事实 P(y_x|x',y') 如果当时没洒水,会怎样

核心定理:仅凭第 1 层的观测数据,无法推出第 2 层的答案。这不是"数据不够",是信息论意义上的欠定。

而整套压缩机器做的全是第 1 层——CE loss 优化的是 p(下一个 token),一个观测分布。

文本间接携带了人类写下的因果知识,所以模型继承了人类因果模型的压缩副本。够做高层规划("要煮咖啡,先烧水"),不够支撑执行层("这个杯子该用多大力捏"从来没人写下来过)。

B.3 三个不对称

数据:

文本 机器人操作
可得规模 数十万亿 token 百万级轨迹
获取成本 爬虫,近乎免费 真实世界 1 倍速

百万条轨迹 ≈ 2800 小时,而一个五岁小孩已积累约 3 万小时具身经验。第 2 层的数据必须靠干预产生,不可能被动积累。

容错:文本出错你看一眼就发现,成本≈0;物理操作不可撤销。所需可靠性从 ~95% 跳到 99.999%,最后几个 9 指数级昂贵。

前提本身:可被压缩的只有被写下来的部分。波兰尼悖论(我们知道的比能说出来的多)、莫拉维克悖论(高层推理便宜,感知运动昂贵)。AI 的能力曲线是沿着人类的书写习惯长出来的,不是沿着任务的客观难度。

B.4 环境可以被改造,但关键变量是"谁能批准"

历史先例极强:汽车出现后城市被彻底重建(划车道线、红绿灯、驾照制度、1920 年代把"乱穿马路"新造成一种罪名、战后修高速建郊区)。

但:

仓库 城市街道
决策者 1 个 市政、管线、业主、行人、快递、急救…
改造周期 停工两周 十年听证
谁能进 扫码才能进 任何人,随时

仓库能自动化不是因为它是人造的,是因为它有一个业主。

结构 ≠ 可预测:仓库的优势不是几何简单,是事件分布有界。可以用混凝土改造几何,改不了事件分布——除非同时控制谁能进入。而"任何人都能进"恰恰是城市之所以是城市的原因。

可检验的推论:能排他的地方自动化确实已经发生了(机场、港口、矿区、企业园区)。

B.5 道路:最好的证据,也是尺度的证据

道路是人类造过的最迁就机器的环境。现状(2026 年 8 月):Waymo 服务面积超 1400 平方英里、覆盖 11 个美国城市、约 3000–4000 辆车、周订单约 50 万、目标年底 100 万。

方向被证实了。 但换个分母:美国城市化土地约十万平方英里量级,1400 是百分之一出头;而从项目启动到今天是 17 年。

一个不对称的飞轮:环境改造是在机器已经可用之后才启动的。汽车在土路上就能跑,先证明了有用,社会才愿意花五十年重建城市。环境适配是放大器,不是启动器。

B.6 结论

自动化会沿着产权和控制权的边界扩散,而不是沿着技术难度扩散。

[  仓库内:机器人  ]──围墙──[  最后一公里:人  ]

交接点恰好在环境控制权终止的地方。预期是长期斑块状——围墙内高度自动化,围墙外仍是人,围墙一点点向外推,每推一次打一轮政治仗。新建的地方会比改造的快得多。

最不确定的地方:上述论证的隐含前提是"改造环境的成本不变"。如果机器变得足够通用能直接吃下未经改造的环境,整个论证失效。视频预训练和仿真如果把物理常识做到位,这条路不是不可能。


附录 C:符号速查

符号 含义
d_model / d 残差流宽度,4608
L 层数,46
n_h Query head 数,32
n_kv KV head 数,16
d_head 每个头的维度,128
d_ffn FFN 中间宽度,36864
V 词表大小,256128
t 当前序列长度
P 总参数量
E embedding 表
A 注意力权重矩阵(t × t),softmax 之后的结果;9.7 里记作 $P$
$s_{ij}$ / $S$ 注意力打分:缩放后的点积 $q_i\cdot k_j/\sqrt{d_{\text{head}}}$(2.3);$S$ 是它们排成的矩阵(9.7)。9.7 里大写带下标的 $S_{ij}$ 指一个分块小矩阵
p 模型预测分布
y 目标分布(通常 one-hot)
α 投机解码接受率
$\rho_t$ PPO / GRPO 中新旧策略的概率比(PPO 论文记作 $r_t(\theta)$,10.8 改记 $\rho_t$ 以免和奖励 r 混淆)
$\hat A_t$, $\lambda$ 优势估计;GAE 的衰减系数(10.8)
$G$ GRPO 每题采样的回答数(10.8)
$r$ 10.2–10.8 中为奖励;10.9 中为 LoRA 的秩
$\beta$ 5.6 中为 Adam 的动量系数 $\beta_1, \beta_2$;10.2–10.8 中为 KL 惩罚系数
$A$, $B$(10.9) LoRA 的两个低秩矩阵,与注意力权重 $A$ 无关
$n$, $K$(12) 题目数、每题采样次数
SE 标准误:样本均值的标准差(11.3、12.1)
N 序列长度(9.7–9.8 沿用 FlashAttention 论文记号,= 本文的 t)
m, ℓ 在线 softmax 的行最大值、行指数和(分母);带波浪号为单块局部量
B_r, B_c FlashAttention 的块行数 / 块列数
$\theta_i$, $b$ RoPE 第 i 对维度的旋转频率;base(config 里的 rope_theta),见 2.8
$\lambda_i$ RoPE 第 i 对维度的波长,$2\pi/\theta_i$
$m$, $n$ 2.8–2.9 中为 q、k 所在的位置,与 9.7 在线 softmax 的行最大值 $m$ 无关
$L$, $L'$ 2.9 中为训练长度、目标长度
$s$ 2.9 中为上下文放大倍数 $L'/L$;9.9 的 AWQ / SmoothQuant 中为逐通道缩放因子
$m_h$ ALiBi 第 h 个头的斜率(2.10)
$c^{KV}$, $d_c$ MLA 缓存的压缩向量及其维度(512),见 2.11
$d_h^R$ MLA 解耦 RoPE 通道的维度(64)
$N_E$, $k$ MoE 的专家数、每 token 激活的专家数(3.6–3.7)
$f_i$, $P_i$ 负载均衡损失里专家 i 的实际 token 比例、平均路由概率
$b_i$, $\gamma$ DeepSeek-V3 无辅助损失均衡中的专家偏置及其更新步长(3.7 中的 γ 与 2.9 YaRN 的 γ 无关)
$H$ GPTQ 中逐层目标的海森矩阵 $2XX^\top$(9.9)
$\Delta$ 量化步长(9.9)

附录 D:参考文献

主题 文献
Transformer Vaswani et al. 2017, Attention Is All You Need
纯注意力会塌缩 Dong et al. 2021, Attention is not all you need
FFN 是 key-value memory Geva et al. 2021, Transformer Feed-Forward Layers Are Key-Value Memories
知识定位与编辑 Meng et al. 2022, Locating and Editing Factual Associations in GPT(ROME)
叠加 Elhage et al. 2022, Toy Models of Superposition(Anthropic)
知识容量 Allen-Zhu & Li 2024, Physics of Language Models 3.3: Knowledge Capacity Scaling Laws
Pre-LN vs Post-LN Xiong et al. 2020, On Layer Normalization in the Transformer Architecture
LayerNorm Ba et al. 2016, Layer Normalization
RMSNorm Zhang & Sennrich 2019, Root Mean Square Layer Normalization
BN 为何不适合 NLP Shen et al. 2020, PowerNorm: Rethinking Batch Normalization in Transformers
BN 有效的真正原因 Santurkar et al. 2018, How Does Batch Normalization Help Optimization?
Cross-attention 起源 Bahdanau et al. 2014, Neural Machine Translation by Jointly Learning to Align and Translate
Seq2seq Sutskever et al. 2014 / Cho et al. 2014
MQA Shazeer 2019, Fast Transformer Decoding: One Write-Head is All You Need
GQA 与 uptraining Ainslie et al. 2023, GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
注意力头冗余 Michel et al. 2019, Are Sixteen Heads Really Better than One?
头的功能分化 Voita et al. 2019, Analyzing Multi-Head Self-Attention
投机解码 Leviathan et al. 2023 / Chen et al. 2023
FlashAttention Dao et al. 2022, FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness
FlashAttention-2 Dao 2023, FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning
FlashAttention-3 Shah et al. 2024, FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision
RoPE Su et al. 2021, RoFormer: Enhanced Transformer with Rotary Position Embedding(arXiv 2104.09864)
Gemma 2 Gemma Team 2024, Gemma 2: Improving Open Language Models at a Practical Size(arXiv 2408.00118)
位置插值 PI Chen et al. 2023, Extending Context Window of Large Language Models via Positional Interpolation(arXiv 2306.15595)
NTK-aware / Dynamic NTK bloc97、emozilla 2023,Reddit r/LocalLLaMA 帖子(社区来源,经 YaRN 论文引用)
YaRN Peng et al. 2023, YaRN: Efficient Context Window Extension of Large Language Models(arXiv 2309.00071)
大 base(Code Llama) Rozière et al. 2023, Code Llama: Open Foundation Models for Code(arXiv 2308.12950)
RoPE ABF(Llama 2 Long) Xiong et al. 2023, Effective Long-Context Scaling of Foundation Models(arXiv 2309.16039)
LongRoPE Ding et al. 2024, LongRoPE: Extending LLM Context Window Beyond 2 Million Tokens(arXiv 2402.13753)
有效上下文评测 Hsieh et al. 2024, RULER: What's the Real Context Size of Your Long-Context Language Models?(arXiv 2404.06654)
ALiBi Press et al. 2021, Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation(arXiv 2108.12409,ICLR 2022)
ALiBi ≈ 窗口注意力 Chi et al. 2022, Dissecting Transformer Length Extrapolation via the Lens of Receptive Field Analysis(arXiv 2212.10356,ACL 2023)
FIRE Li et al. 2023, Functional Interpolation for Relative Positions Improves Long Context Transformers(arXiv 2310.04418)
T5 相对位置偏置 Raffel et al. 2019, Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer(arXiv 1910.10683)
BLOOM BigScience Workshop 2022, BLOOM: A 176B-Parameter Open-Access Multilingual Language Model(arXiv 2211.05100)
NoPE Kazemnejad et al. 2023, The Impact of Positional Encoding on Length Generalization in Transformers(arXiv 2305.19466,NeurIPS 2023)
无位置编码仍学到位置 Haviv et al. 2022, Transformer Language Models without Positional Encodings Still Learn Positional Information(arXiv 2203.16634)
NoPE 的长度上限 Wang et al. 2024, Length Generalization of Causal Transformers without Position Encoding(arXiv 2404.12224)
RoPE/NoPE 混合 Yang et al. 2025, Rope to Nope and Back Again: A New Hybrid Attention Strategy(arXiv 2501.18795);Team Cohere 2025, Command A(arXiv 2504.00698)
Llama 4 iRoPE Meta AI 博客 2025-04-05, The Llama 4 herd(ai.meta.com/blog/llama-4-multimodal-intelligence)
MLA DeepSeek-AI 2024, DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model(arXiv 2405.04434)
DeepSeek-V3(MLA + 无辅助损失均衡) DeepSeek-AI 2024, DeepSeek-V3 Technical Report(arXiv 2412.19437)
MLA 推理是算力瓶颈 DeepSeek, FlashMLA 技术博客 2025-04-22(github.com/deepseek-ai/FlashMLA,docs/20250422-new-kernel-deep-dive.md)
GQA ⊂ MLA Meng et al. 2025, TransMLA: Multi-Head Latent Attention Is All You Need(arXiv 2502.07864)
MHA → MLA 改造 Ji et al. 2025, Towards Economical Inference: Enabling DeepSeek's Multi-Head Latent Attention in Any Transformer-based LLMs(MHA2MLA,arXiv 2502.14837)
Kimi K2(MLA、64 头) Kimi Team 2025, Kimi K2: Open Agentic Intelligence(arXiv 2507.20534)
稀疏门控 MoE Shazeer et al. 2017, Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer(arXiv 1701.06538)
GShard Lepikhin et al. 2020, GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding(arXiv 2006.16668)
Switch Transformer Fedus et al. 2021, Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity(arXiv 2101.03961)
Router z-loss Zoph et al. 2022, ST-MoE: Designing Stable and Transferable Sparse Expert Models(arXiv 2202.08906)
Expert Choice Zhou et al. 2022, Mixture-of-Experts with Expert Choice Routing(arXiv 2202.09368,NeurIPS 2022)
Mixtral Jiang et al. 2024, Mixtral of Experts(arXiv 2401.04088)
细粒度 + 共享专家 Dai et al. 2024, DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models(arXiv 2401.06066)
无辅助损失均衡 Wang et al. 2024, Auxiliary-Loss-Free Load Balancing Strategy for Mixture-of-Experts(arXiv 2408.15664)
Qwen3 MoE Yang et al. 2025, Qwen3 Technical Report(arXiv 2505.09388)
离群特征 / LLM.int8() Dettmers et al. 2022, LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale(arXiv 2208.07339,NeurIPS 2022)
GPTQ Frantar et al. 2022, GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers(arXiv 2210.17323,ICLR 2023)
AWQ Lin et al. 2023, AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration(arXiv 2306.00978,MLSys 2024)
SmoothQuant Xiao et al. 2022, SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models(arXiv 2211.10438,ICML 2023)
4 位最优 Dettmers & Zettlemoyer 2022, The case for 4-bit precision: k-bit Inference Scaling Laws(arXiv 2212.09720)
QuIP# Tseng et al. 2024, QuIP#: Even Better LLM Quantization with Hadamard Incoherence and Lattice Codebooks(arXiv 2402.04396,ICML 2024)
AQLM Egiazarian et al. 2024, Extreme Compression of Large Language Models via Additive Quantization(arXiv 2401.06118,ICML 2024)
BitNet b1.58 Ma et al. 2024, The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits(arXiv 2402.17764)
量化与训练数据量 Kumar et al. 2024, Scaling Laws for Precision(arXiv 2411.04330)
记忆容量 3.6 bit/参数 Morris et al. 2025, How much do language models memorize?(arXiv 2505.24832)
Gemma 对话模板 Google AI for Developers, Gemma formatting and system instructions(ai.google.dev/gemma/docs/core/prompt-structure)
InstructGPT 流水线细节 Ouyang et al. 2022(arXiv 2203.02155),附录 C、E(β = 0.02、γ = 27.8)
Llama 2 SFT / RLHF Touvron et al. 2023, Llama 2: Open Foundation and Fine-Tuned Chat Models(arXiv 2307.09288)
LIMA Zhou et al. 2023, LIMA: Less Is More for Alignment(arXiv 2305.11206)
Packing 不串样本 Krell et al. 2021, Efficient Sequence Packing without Cross-contamination(arXiv 2107.02027)
TRL SFTTrainer HuggingFace TRL 文档(huggingface.co/docs/trl/sft_trainer,assistant_only_loss / completion_only_loss)
PPO Schulman et al. 2017, Proximal Policy Optimization Algorithms(arXiv 1707.06347)
GAE Schulman et al. 2015, High-Dimensional Continuous Control Using Generalized Advantage Estimation(arXiv 1506.02438)
Dr. GRPO Liu et al. 2025, Understanding R1-Zero-Like Training: A Critical Perspective(arXiv 2503.20783)
DAPO Yu et al. 2025, DAPO: An Open-Source LLM Reinforcement Learning System at Scale(arXiv 2503.14476)
RLOO / REINFORCE Ahmadian et al. 2024, Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs(arXiv 2402.14740)
LoRA Hu et al. 2021, LoRA: Low-Rank Adaptation of Large Language Models(arXiv 2106.09685)
微调的内在维度 Aghajanyan et al. 2020, Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning(arXiv 2012.13255)
QLoRA Dettmers et al. 2023, QLoRA: Efficient Finetuning of Quantized LLMs(arXiv 2305.14314)
LoRA vs 全量微调 Biderman et al. 2024, LoRA Learns Less and Forgets Less(arXiv 2405.09673,TMLR)
LoRA 实践结论 Schulman & Thinking Machines Lab 2025-09-29, LoRA Without Regret(thinkingmachines.ai/blog/lora)
rsLoRA Kalajdzievski 2023, A Rank Stabilization Scaling Factor for Fine-Tuning with LoRA(arXiv 2312.03732)
DoRA Liu et al. 2024, DoRA: Weight-Decomposed Low-Rank Adaptation(arXiv 2402.09353,ICML 2024)
评测误差棒 Miller 2024, Adding Error Bars to Evals: A Statistical Approach to Language Model Evaluations(arXiv 2411.00640,Anthropic);博客 A statistical approach to model evaluations(2024-11-19)
小样本别用 CLT Bowyer et al. 2025, Position: Don't Use the CLT in LLM Evals With Fewer Than a Few Hundred Datapoints(arXiv 2503.01747,ICML 2025)
二项比例的区间估计 Brown, Cai & DasGupta 2001, Interval Estimation for a Binomial Proportion, Statistical Science 16(2)
pass@k 无偏估计 Chen et al. 2021, Evaluating Large Language Models Trained on Code(arXiv 2107.03374)
训练种子方差 Madaan et al. 2024, Quantifying Variance in Evaluation Benchmarks(arXiv 2406.10229)
prompt 格式敏感性 Sclar et al. 2023, Quantifying Language Models' Sensitivity to Spurious Features in Prompt Design(arXiv 2310.11324,ICLR 2024)
推理基准的可复现性 Hochlehnert et al. 2025, A Sober Look at Progress in Language Model Reasoning: Pitfalls and Paths to Reproducibility(arXiv 2504.07086,COLM 2025)
推理不确定性 Horace He & Thinking Machines Lab 2025-09-10, Defeating Nondeterminism in LLM Inference(thinkingmachines.ai/blog)
Chatbot Arena Chiang et al. 2024, Chatbot Arena: An Open Platform for Evaluating LLMs by Human Preference(arXiv 2403.04132)
信息论 Shannon 1948, A Mathematical Theory of Communication
数据处理不等式 Cover & Thomas, Elements of Information Theory, ch. 2
英语的熵 Shannon 1951, Prediction and Entropy of Printed English
RLHF 起源 Christiano et al. 2017, Deep RL from Human Preferences
InstructGPT / RLHF 流程 Ouyang et al. 2022, Training language models to follow instructions
DPO Rafailov et al. 2023, Direct Preference Optimization: Your Language Model is Secretly a Reward Model
DPO vs PPO 实测 Xu et al. 2024 (ICML), Is DPO Superior to PPO for LLM Alignment?
Likelihood displacement Razin et al. 2024, Unintentional Unalignment / Ren & Sutherland 2024
GRPO Shao et al. 2024, DeepSeekMath
RLVR 与推理 DeepSeek-AI 2025, DeepSeek-R1
Constitutional AI Bai et al. 2022 (Anthropic)
RLHF 教科书 Lambert, Reinforcement Learning from Human Feedback (arXiv 2504.12501)
因果阶梯 Pearl, The Book of Why
隐性知识 Polanyi 1966, The Tacit Dimension

附录 E:还没聊到、值得继续的方向

(数学基础已收入第 11 章。)

已完成(2026-10-18 补入):

还没聊到: