跳转至

附录 B 关键节点拆解 Ⅰ:2017–2022,decoder-only 范式的确立

这一篇的任务:把 2017 到 2022 这六年里真正改变了架构的论文排成一条线,每一个都回答三个问题——它当时要解决什么问题、它给今天留下了哪个零件、这个零件在本书第几章。

怎么用:不必按顺序读完。读完正文某一章之后,回来看这里对应的那几节,你会知道那个设计是谁在什么压力下做出来的。

B.1 Transformer(2017):一次拆解,看清哪些活到了今天

论文:Attention Is All You Need(arXiv:1706.03762)

它当时要解决的问题:RNN 的序列依赖让训练无法并行,长距离依赖也传不动。CNN 类方案(ByteNet、ConvS2S)并行了但感受野随距离线性/对数增长。作者的主张是:只用注意力,把任意两个位置的路径长度降到 1,同时全序列并行。

原始配置(base 模型,约 65M 参数):6 层编码器 + 6 层解码器,d_model=512,h=8,d_k=d_v=64,d_ff=2048,Dropout 0.1,label smoothing 0.1。训练用 Adam(β2=0.98)配 4000 步 warmup 和 inverse-sqrt 衰减。

现在逐个零件判生死:

零件 今天的状态 说明 章节
缩放点积注意力 softmax(QKᵀ/√d)V 原样保留 核心公式九年没变 第 2.2 节
多头 保留,但头的配置全变了 MQA/GQA/MLA 重新分配了 K、V 的头数 第 7 章
残差 + 归一化 保留 归一化的种类和位置都换了 第 5 章
FFN(升维再降维) 保留,激活换了 ReLU → GELU → SwiGLU 第 5.3 节
因果掩码 保留 解码器侧的那一半成了全部 第 2.3 节
Adam + warmup 保留 warmup 至今几乎必需 第二册第 8 章
Post-LN 淘汰 深层难训,被 Pre-LN 取代 第 5.1 节
正弦位置编码 淘汰 外推能力差,被 RoPE 取代 第 6 章
encoder-decoder 在 LLM 里淘汰 但在多模态里以"视觉编码器 + 语言解码器"的形式复活 附录 G
ReLU FFN 淘汰 见上 第 5.3 节
Dropout / label smoothing 预训练阶段基本关掉 原因见附录 A.7 —
d_ff = 4 × d_model 松动 SwiGLU 为保持参数量改成约 8/3 × d_model 第 5.3 节

这张表是本书的一条暗线:活下来的都是"决定信息怎么流动"的结构,被换掉的都是"数值细节"。判断一篇新论文重不重要,可以先问它动的是哪一类。

B.2 2018–2019:三条路线分叉,为什么 decoder-only 赢了

同一时期出现了三种用 Transformer 做预训练的方式:

  • GPT-1(2018,decoder-only,117M):自回归语言建模 + 下游微调。
  • BERT(2018,encoder-only,110M/340M):掩码语言建模(MLM)+ 下一句预测,双向上下文,在理解类任务上碾压。
  • T5(2019,encoder-decoder):把所有任务统一成 text-to-text,span corruption 预训练,用相对位置偏置。

2018 到 2020 年,BERT 才是学术界和工业界的主流。decoder-only 后来赢了,原因有四条,值得记住,因为它们解释了本书为什么从第 2 章起就只讲解码器:

  1. 它天然会生成。MLM 模型要生成得额外设计解码过程,而生成是后来所有能力(对话、推理链、工具调用)的载体。
  2. 训练信号密度高。自回归在每个位置上都产生一个预测目标;BERT 只在被掩码的 15% 位置上有 loss。同样的算力,前者从数据里榨出的监督多得多。
  3. 结构最简单,最好扩展。没有 encoder-decoder 的 cross-attention,没有两套参数,张量并行和流水并行的切分都更规整(第二册第 4–7 章)。
  4. 推理形态与 KV Cache 完美契合。因果掩码意味着历史表示永不改变,于是可以缓存。双向注意力每来一个新 token 就要重算全部(第 4 章)。

第 4 条尤其值得体会:一个看起来纯属"建模选择"的因果掩码,实际上决定了整个推理系统能不能做出来。 第二册几乎所有的推理优化都建立在这一个性质上。

B.3 GPT-2(2019):把归一化挪了个位置

它的主要贡献常被记成"1.5B 参数 + zero-shot",但对架构而言更重要的是两个细节:

  • Pre-LN:把 LayerNorm 移到每个子层的输入端,并在最后一层之后补一个 LayerNorm。残差主干上不再有归一化操作,梯度能一路直通。这和 pre-activation ResNet 是同一个发现(附录 A.3)。
  • 残差投影的初始化缩放:把每个残差分支最后那个投影层的初始权重乘以 1/√N(N 为残差层数)。因为 L 层的输出会累加到同一条残差流上,不缩放的话主干的方差随深度线性增长。

配置:48 层,d_model=1600,上下文 1024,BPE 词表 50257。

为什么值得单列一节:这两条今天仍然写在几乎每一份开源模型的代码里,而且是第 5 章"训练稳定性"整章的起点。很多人以为稳定性问题是模型做到百亿以上才出现的,其实 2019 年就已经在解了。

B.4 GPT-3(2020):规模本身成了方法

论文:Language Models are Few-Shot Learners(arXiv:2005.14165)

配置:175B 参数,96 层,d_model=12288,96 个头(d_head=128),上下文 2048,训练约 300B token。

架构上它几乎没有新东西——照抄 GPT-2,唯一的结构改动是"交替使用稠密注意力与局部带状稀疏注意力"(借自 Sparse Transformer,arXiv:1904.10509)。

但它确立了两件影响至今的事:

  1. 上下文学习(in-context learning):不改一个参数,只在 prompt 里给几个示例,模型就能完成新任务。这直接催生了后来的 prompt 工程、few-shot 评测协议,以及第三册整册的"不改权重也能改行为"这条线。
  2. 稀疏/稠密交替是可行的。这个结论被搁置了几年,2024 年之后随着长上下文需求回归,成了主流(第 12、14 章,以及附录 C.4、D.3)。

顺便记一个数:175B 参数、300B token,比例约 1.7 token/参数。两年后 Chinchilla 会告诉你这个配比错得离谱。

B.5 Scaling law 的两次修正:一条决定了所有模型尺寸的线

这条线不改计算图,却决定了每一个模型该做多大、训多少数据,因此必须放进架构书里。

第一次(Kaplan et al., 2020,arXiv:2001.08361):损失随参数量、数据量、算力呈幂律下降,并且结论是给定算力时应优先把参数做大。GPT-3 那一代的"大模型、相对少数据"路线就是这么来的。

第二次(Chinchilla, 2022,arXiv:2203.15556):DeepMind 重做了实验,发现参数与数据应该按同等比例一起扩,经验值约 20 token/参数。他们用 70B 模型训 1.4T token,全面打败了 280B 的 Gopher。这直接导致下一年的模型集体变小、数据集体变多——LLaMA 就是这条结论的产物。

第三次修正(2023 年之后,没有单一论文,是工业界的共识):Chinchilla 最优是训练算力最优,不是总成本最优。一个模型训一次、推理无数次,把小模型训到远超 Chinchilla 点(Llama 3 的 8B 训了 15T token,约 1800 token/参数)在总账上更划算。

给你的判断工具:看到一个模型的"参数量 / 训练 token 数"比例,就能大致推断它的定位——接近 20 是研究型或算力受限,几百到上千是为部署优化的产品型。

B.6 2020–2022:零件的铺货期

现代模型用的大部分零件都在这两三年里被发明出来,但当时没有任何一个模型把它们凑齐。

年份 工作 它给了什么 本书章节
2019 MQA(arXiv:1911.02150) 所有头共享一份 K/V,KV Cache 直接除以头数 第 7.2 节
2019 Sparse Transformer 跨步/固定稀疏模式,长序列注意力的第一批可用方案 第 11 章
2019 RMSNorm 去掉均值中心化的 LayerNorm 第 5.2 节
2020 GShard(arXiv:2006.16668) MoE 的 top-2 路由、容量因子、跨设备专家并行 第 9 章
2020 GLU 变体(arXiv:2002.05202) SwiGLU,以及"把 d_ff 乘 2/3 保持参数量"这个惯例 第 5.3 节
2021 Switch Transformer(arXiv:2101.03961) top-1 路由把 MoE 做到 1.6T 参数,也暴露了负载均衡和容量丢弃 第 8.3–8.4 节
2021 RoPE(arXiv:2104.09864) 旋转位置编码:相对位置、可外推、无需额外参数 第 6.2 节
2021 ALiBi(arXiv:2108.12409) 线性距离惩罚,当时外推最好的方案 第 6 章
2022 FlashAttention(arXiv:2205.14135) IO 感知的精确注意力,分块计算不落 n×n 矩阵 第 4.4 节
2022 muP(arXiv:2203.03466) 让小模型上调好的超参能迁移到大模型 附录 F

两点值得说:

  • ALiBi 输给了 RoPE,但不是因为效果差。它当时确实外推更好。输的原因是 RoPE 对后续技术更友好——后来的窗口扩展多半在 RoPE 的频率上做手脚(第 6 章),生态一旦形成就很难逆转。"哪个技术胜出"经常不取决于单点指标,这在本书后面会反复出现。
  • FlashAttention 不是近似注意力,它计算同一个数学结果,只是重排顺序以避开显存带宽瓶颈。由于浮点运算次序不同,数值不保证逐 bit 相同。把它和第 11 章的稀疏注意力分清楚:前者不改变目标算子,后者改变参与计算的连接。

B.7 PaLM(2022):第一份"现代配方"的完整清单

论文:arXiv:2204.02311,540B 稠密模型。

规模已经不是它今天的价值所在,它的价值在于第一次把一批选择打包在一起并公开说明理由:

  • SwiGLU 替代 ReLU FFN
  • RoPE 替代可学习位置嵌入
  • 去掉所有 bias(包括 LayerNorm 的)——报告称这提升了大模型的训练稳定性
  • 输入输出嵌入共享
  • MQA(在当时是为了推理速度)
  • 并行化的 attention 与 FFN(两者读同一个归一化后的输入,输出相加,可以省一次通信)
  • 预训练不用 Dropout

除了最后一条"并行 attention+FFN"没有成为主流(收益主要在特定并行配置下,后来被更好的通信重叠方案取代),其余每一条都进了 2023 年的标准配方。下一篇的 LLaMA 基本就是这张清单去掉 MQA 和并行层。

B.8 这六年留下的三条经验

  1. 结构上的胜者都在解决"信息怎么流",数值上的细节会被反复替换。 残差、注意力、因果掩码活了九年;归一化种类、激活函数、位置编码换了好几轮。
  2. 一个建模选择的真正代价往往出现在系统侧。 因果掩码带来了 KV Cache,MQA 是为了推理而不是为了精度,稀疏注意力的成败取决于能不能写出高效核。
  3. 好想法经常要等几年才等到它的场景。 稀疏注意力 2019 年就有,2024 年才成主流;MoE 2020 年就能做到 1.6T,2024 年才在开源模型里普及。技术不是在发明的那一年成熟的,是在约束变化的那一年成熟的。

核心问答

Q1:现在还有必要读 2017 年那篇原论文吗? 有,但读法要变。读它的第 3 节(模型结构)和附录里的超参表,对照 B.1 那张表看哪些还在。不要照着它建立对现代模型的认识——它有一半内容(encoder-decoder、Post-LN、正弦编码、label smoothing)在今天的 LLM 里已经不存在了。

Q2:BERT 这条路线彻底死了吗? 在生成式大模型这条线上是的。但 encoder 结构在检索(embedding 模型、reranker)、分类、以及多模态的视觉侧仍然是主力。它不是被证伪,是被换了赛道。

Q3:Chinchilla 的 20 token/参数现在还能用吗? 只能当参考下界。它回答的是"训练算力固定时怎么分配",而真实项目要考虑推理成本、部署显存、上下文长度。现在的实际取值普遍远高于 20,见 C.1。

Q4:为什么 MoE 在 2021 年就能做到 1.6T 参数,开源社区却到 2023 年底才用上? 三个原因:稀疏模型当时训练不稳定且质量不如同算力稠密模型;专家并行需要的通信基础设施(AllToAll)不成熟;以及最关键的——显存价格还没贵到让人愿意接受"总参数很大但激活很小"这种交易。第 9.6 节算过这笔账。

Q5:这一段里哪一件事对读现代模型代码最有用? B.1 的那张生死表。打开任何一份 modeling_*.py,你看到的结构就是"2017 年的骨架 + 表里那几处替换"。认出这一点之后,读新模型的速度会快一个量级。