对应 Maps to:CMU 11-868 / 11-968 Large Language Model Systems(Spring 2026,Lei Li),Lecture 7 · Wed 2/4 · Pre-trained LLMs。 阅读材料:Raffel et al. (2020) Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer(T5,JMLR);Brown et al. (2020) Language Models are Few-Shot Learners(GPT-3,NeurIPS);Touvron et al. (2023) LLaMA: Open and Efficient Foundation Language Models;Su et al. (2021) RoFormer;Shazeer (2020) GLU Variants Improve Transformer;Zhang & Sennrich (2019) Root Mean Square Layer Normalization;Ainslie et al. (2023) GQA。 依据说明:本讲以原课第 7 讲公开的 slides(llmsys-07-llms.pdf,23 页)为主线:回顾、T5(结构与束搜索、三个规模、C4 与多任务微调、span corruption 预训练、带任务说明的多任务 SFT)、LLaMA(pre-normalization、SwiGLU、RoPE 的公式与块对角旋转、规模、训练策略)、GPT-3(结构改动、规模、训练、计算量)、小测、总结、HW3。slides 的规模表和训练细节页是论文截图,本讲的数字取自原论文。span corruption 的实现与长度统计、文本到文本的城市语言任务、各部件的数值检查、GQA 的 KV 缓存账、z-loss 与 bf16、逐项升级小 GPT 的消融与长度外推、GPT-3 vs LLaMA 的”参数 vs 数据”对比、上下文学习与归纳头的小实验,都是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:
code/lecture07/(4 个脚本 +llama.py;首次运行要训练并缓存小模型,03 约 1.5 分钟、04 约 50 秒,之后都是几秒) 预计阅读时间:3–4 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说出 T5 的三个关键设计:编码器–解码器结构、span corruption 预训练目标、“一切都是文本到文本”的多任务格式;能手算一条样本破坏后的输入、目标长度。
- 说出 GPT-3 的贡献:规模(175B、300B token、3.14e23 FLOPs)和上下文学习(few-shot 提示),并用一个小实验解释上下文学习靠的是什么(归纳头)。
- 解释 LLaMA 相对 GPT-2 / 原始 Transformer 的四处改动——Pre-RMSNorm、SwiGLU、RoPE、GQA——各自的公式、为什么这样做、系统上省了什么。
- 用公式复现 T5、GPT-3、LLaMA 各个规模的参数量,并算出训练计算量(6ND)。
- 理解”参数 vs 数据”的取舍:GPT-3(大模型、少数据)→ Chinchilla(计算最优)→ LLaMA(为推理成本”过度训练”小模型)。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲只给直觉,后面再展开 Previewed only |
|---|---|
| Transformer 的全部部件、Pre-LN、正弦位置编码(第 6 讲) | 分词与 BPE(第 8 讲);束搜索与解码(第 9 讲) |
| 参数量公式、6ND、KV 缓存(第 1 讲) | 指令微调与 RLHF(第 23、25 讲);前缀缓存(第 22、27 讲) |
| 浮点格式与 bf16(P2) | MoE(第 17 讲);长上下文的位置插值 |
0.3 本讲地图 Map
§1 T5:编码器–解码器 + span corruption + 文本到文本 ← 代码 01
§2 GPT-3:规模、稀疏注意力、上下文学习 ← 代码 04
§3 LLaMA:Pre-RMSNorm、SwiGLU、RoPE、GQA;规模与训练配方 ← 代码 02、03
§4 三者对照:"参数 vs 数据" ← 代码 04
§5 系统含义汇总
§6 小结 §7 常见误区 §8 练习 §9 延伸阅读 §10 下一讲预告
1. T5:一切都是文本到文本 · T5
1.1 结构
T5(Raffel et al. 2020)就是第 6 讲的编码器–解码器 Transformer,解码时用束搜索(slides 第 4 页:束宽 4、长度惩罚 0.6,第 9 讲细讲)。几个容易忽略的细节,后来都被 LLaMA 继承或呼应:
- LayerNorm 只做缩放:不减均值、没有偏置 β——这其实就是 RMSNorm(§3.2)。
- 线性层没有偏置。
- 相对位置偏置:不用正弦编码或位置表,而是在注意力分数上加一个只依赖相对距离(分成 32 个桶)的可学习标量——和 RoPE 一样,关注的是相对位置。
- 编码器输入、解码器输入、输出层共享一个嵌入矩阵。
1.2 预训练目标:span corruption
T5 在 C4(从 Common Crawl 过滤出的约 750GB 英文文本,slides 第 5 页)上预训练,目标是恢复被随机破坏的片段(slides 第 6 页):15% 的 token 被破坏,平均每段 3 个;每个被破坏的片段在输入里换成一个哨兵 <Xk>(T5 词表里的 <extra_id_k>),目标按顺序列出”哨兵 + 它遮住的原文”。01 号脚本在城市语言上演示:
输入:… the doctors from new york who read after <X0> pittsburgh is a city of bridges . miami is a city of <X1> </s>
目标:<X0> work love the parks . <X1> history </s>
编码器双向地读整个输入,解码器自回归地写出目标——一次填好几个空、每个空可以是几个词的完形填空。和 BERT(每个被遮的 token 换成一个 [MASK]、原位预测)相比,T5 把连续片段压成一个哨兵,输入和目标都变短。
01 号脚本第 2 部分统计一条 512 token 的样本:破坏 77 个 token(0.150)、分成 26 段(平均 2.96),输入 462 个、目标只有 104 个(含结束符)。和同参数量的 decoder-only 模型比(每 token 约 2N 次运算,第 6 讲 §8.2):
| 做法 | 处理的 token | 有损失的 token | 前向 GFLOPs / 样本 |
|---|---|---|---|
| T5-base:编码器读输入 + 解码器写目标 | 462 + 104 | 104 | 102.0 |
| 同参数量的 decoder-only,预测下一个 token | 512 | 512 | 202.9 |
每条样本便宜一半,但提供损失的 token 只有 1/5。只看”每个有监督的 token 花了多少计算”,decoder-only 更划算;不过两种目标学到的东西不同,T5 论文在相近的预算下系统比较过多种目标,span corruption 在它的编码器–解码器上效果最好。
1.3 文本到文本与多任务微调
T5 的另一个贡献是把所有任务写成同一个格式:输入是”任务说明 + 文本”,输出也是文本(slides 第 7 页)。01 号脚本第 3 部分在城市语言上造了几个任务:
| 输入 | 输出 |
|---|---|
| weather of: in santa barbara it is often sunny . | sunny |
| which city: the doctors from new york who read after work love the parks . | new york |
| known for: pittsburgh is a city of bridges . | bridges |
分类、抽取、回归(T5 把相似度分数写成 “3.8” 这样的文本)、翻译、摘要都变成”读一段、写一段”:一个模型、一个损失、一个解码过程,不需要为每个任务加专门的输出层。预训练之后在 GLUE / SuperGLUE、CNN/DM 摘要、SQuAD 问答、WMT 翻译上做多任务监督微调(slides 第 5 页)。因为任务说明是自然语言,继续加大指令数据就得到 T0、Flan-T5,也就是今天”指令微调”的前身(第 23、25 讲)。
1.4 规模与训练 token
01 号脚本第 4 部分用公式复现 slides 第 4 页的三个配置:
| 模型 | 块数 | d_model | d_ff | 头 × d_kv | 公式 | slides |
|---|---|---|---|---|---|---|
| T5-base | 12 + 12 | 768 | 3072 | 12 × 64 | 0.223B | 220M |
| T5-3B | 24 + 24 | 1024 | 16384 | 32 × 128 | 2.852B | 3B |
| T5-11B | 24 + 24 | 1024 | 65536 | 128 × 128 | 11.307B | 11B |
注意 3B 和 11B 的 d_model 都只有 1024,参数几乎全靠加宽前馈层和加多头堆出来:每层是少数几个又宽又大的矩阵乘法,在 TPU 上效率很高,但和后来”d_model 随规模增大”的配方不同。预训练 2^19 ≈ 52 万步、每批 128 条 × 512 token,共 2^35 ≈ 34.4B token(slides 第 6 页的 “34B”)。今天看这很少:LLaMA-7B 训练了 1T token,约 30 倍。
2. GPT-3:规模与上下文学习 · GPT-3
2.1 结构:GPT-2 + 几处小改
slides 第 15 页:GPT-3 基本就是 GPT-2——Decoder-only、Pre-LN、改过的初始化、可逆的分词(字节级 BPE,第 8 讲)。唯一显著的结构改动是交替使用稠密注意力和局部带状稀疏注意力(类似 Sparse Transformer):带状层里每个位置只看最近 w 个 token。04 号脚本第 3 部分数了要计算的 (查询, 键) 对:n = 2048、w = 256 时带状层只算稠密层的 0.234;两种层各占一半时,整体最多省一半。GPT-3 论文没有公布带宽,表里的 w 只是示意。n = 2048 时注意力只占 175B 模型 FLOPs 的一小部分(第 6 讲:n = 6d = 73728 时才占一半),所以在 GPT-3 上这主要是显存问题。今天的模型(Mistral、Gemma 2 等)仍在用”局部窗口层 + 全局层”交替。
2.2 规模与计算量
04 号脚本第 1 部分用 GPT-2 结构的公式(每层 12d² + 13d,嵌入共享)复现了 GPT-3 家族的 8 个规模(slides 第 16 页):
| 模型 | 层 | d_model | 头 | 每头维度 | 批(token) | 学习率 | 公式 |
|---|---|---|---|---|---|---|---|
| Small | 12 | 768 | 12 | 64 | 0.5M | 6.0e-4 | 0.125B |
| XL | 24 | 2048 | 24 | 128 | 1M | 2.0e-4 | 1.316B |
| 6.7B | 32 | 4096 | 32 | 128 | 2M | 1.2e-4 | 6.658B |
| 175B | 96 | 12288 | 96 | 128 | 3.2M | 0.6e-4 | 174.604B |
全部训练 300B token。175B 模型的 6ND = 3.14e23 FLOPs ≈ 3638 PF-days,与论文报告的 3.14e23 一致;相当于 1000 块 A100 以 40% MFU 跑约 29 天。两个规律:模型越大批越大、学习率越小(论文按梯度噪声尺度选批大小——损失越低,能有效利用的批越大,正好给数据并行更多活干);每头维度固定在 64–128,加宽模型主要靠加头。
2.3 上下文学习
GPT-3 论文的标题是 Language Models are Few-Shot Learners:不更新任何参数,只在提示里放几个”输入 → 输出”示例,模型就能做新任务。这叫上下文学习(in-context learning):zero-shot 只给任务说明,one-shot / few-shot 再给 1 个 / 几个示例。
它是怎么发生的?04 号脚本第 4 部分做了一个最小的实验。每条训练序列先随机定一个映射”键 → 值”(每条都不同),然后列出 12 个 (键, 值) 对,同一个键会重复出现。一个值能不能猜对,只取决于它的键在这条序列前面有没有出现过——参数里不可能记住任何映射。一个 2 层、d = 64 的小模型训练 5000 步后,在 4000 条全新的序列上:
| 前文里同一个键的示例数 | 准确率 |
|---|---|
| 0(零样本) | 0.128(随机猜 1/8 = 0.125) |
| 1 | 0.985 |
| 2 | 0.992 |
| ≥ 3 | 0.994 |
一个示例就够了,而参数在测试时一点没变——“学习”完全发生在一次前向计算里。机制是归纳头(induction head,Olsson et al. 2022):第 1 层让每个值的位置记住”我前面是哪个键”,第 2 层在新的键位置上找”前面是同一个键”的那个值、把它复制过来。脚本检查了第 2 层:4 个头分别把 0.43–0.57 的注意力放在”上一次同一个键后面的值”上(均匀分配只有 0.08)。这个电路学得很慢:前 2000 步损失只降到 1.228,5000 步才到 0.723(任务下限 0.670)。GPT-3 的发现是:在海量文本上预训练的大模型会自发地学出这类机制,并把它推广到”从示例里归纳任务”。
系统含义:few-shot 把”微调”换成了更长的提示。每个示例都占上下文、都进 KV 缓存、每个请求都要重新算一遍——第 22、27 讲的前缀缓存(RadixAttention、LMCache)正是为了复用这些重复的提示。
3. LLaMA:四处改动 · LLaMA
LLaMA(Touvron et al. 2023)的骨架仍是 Decoder-only Transformer,slides 第 8 页列出三处改动,各自”借”自一篇前作:pre-normalization(GPT-3)、SwiGLU(PaLM)、旋转位置编码 RoPE(RoFormer)。LLaMA-2 / 3 又加了第四处:GQA。llama.py 把每一处做成一个开关。
3.1 Pre-normalization 与 RMSNorm
LLaMA 在每个子层的输入上归一化(Pre-LN,第 6 讲 §5.4),并且用 RMSNorm 代替 LayerNorm:
不减均值、没有 β。02 号脚本第 1 部分:LayerNorm 对输入的平移和缩放都不敏感(变化 4.4e-16 / 7.3e-06),RMSNorm 只对缩放不敏感(整体加 3 后输出变化 1.83)。实践中这点差别不影响效果(Zhang & Sennrich 2019;03 号脚本),省掉的是一次沿特征维的归约和一个参数向量。GPU 上一次归约就是一次块内同步(第 3 讲),LayerNorm 的”两遍”还是”一遍但有数值抵消风险”正是第 10 讲 LightSeq 要处理的问题;RMSNorm 直接绕开了它。⏱ CPU 上两者耗时几乎一样(4096 × 4096 都约 4.5 ms,谁快谁慢每次运行都不一样)——都是访存受限,读写一遍数据的时间占大头。
3.2 SwiGLU
slides 第 10 页:
三个矩阵:一个”门”(Swish(xW₁))、一个”值”(xV)、一个输出。门让每个中间单元可以被输入”按需关掉”,比单纯的激活函数多一层乘法交互;Swish(也叫 SiLU)处处光滑,在 x ≈ −1.278 有最小值 −0.278(02 号脚本第 2 部分)。
三个矩阵比两个多 50% 参数,所以中间维度从 4d 缩到 2/3 · 4d:3 · d · (8d/3) = 8d²,参数和 FLOPs 都和原来一样。LLaMA 的官方代码再把它向上取到 256 的倍数,四个规模的 d_ff 全部精确复现:
| 模型 | d | 2/3·4d | 取到 256 的倍数 = 论文配置 |
|---|---|---|---|
| LLaMA-7B | 4096 | 10922.67 | 11008 |
| LLaMA-13B | 5120 | 13653.33 | 13824 |
| LLaMA-33B | 6656 | 17749.33 | 17920 |
| LLaMA-65B | 8192 | 21845.33 | 22016 |
取到 256 的倍数是为了矩阵形状对齐(第 4 讲:分块、合并访存都喜欢整齐的维度)。系统代价:反向要保存门和值两个中间张量,比 GELU 版多一份激活。
3.3 RoPE:旋转位置编码
slides 第 11–12 页:把 q、k 的每一对维度看成平面上的一个点,位置 m 的向量旋转 mθ_i:
旋转矩阵的转置等于逆,R_mᵀR_n = R_{n−m},所以分数只依赖相对位置 m − n。d 维向量分成 d/2 对,每对用不同的频率 θ_i = 10000^(−2i/d)(和第 6 讲的正弦编码同一组频率),写成块对角矩阵。02 号脚本第 3 部分的数值检查:
- 同一相对距离、不同绝对位置的分数:RoPE 随 m 的标准差 ~1e-15(舍入级别);把正弦编码加到输入上,(q + p_m)·(k + p_n) 里有只依赖绝对位置的交叉项,标准差约 5。
- 旋转不改变长度(‖R_m q‖ = ‖q‖,误差 1.8e-15);不需要任何参数,也没有位置表。
- 把相邻两维看成一个复数,旋转就是乘以 e^{imθ}(Meta 官方代码就是这样写的),与实数写法差 2.2e-16。
- 实现约定的坑:Meta 的代码让相邻两维成对,HuggingFace 的 LLaMA 让前一半和后一半成对(
rotate_half)。两者只差一个维度置换,数学上等价;但不重排就直接套用,分数差 0.378——转换权重时的经典错误。 - “远程衰减”:q、k 各维相同时,Σ_i e^{iΔθ_i} 的大小随距离 Δ 变小(Δ = 1 / 10 / 100 / 1000:0.976 / 0.691 / 0.490 / 0.227),RoPE 自带”远处默认关系弱一些”的偏好。
3.4 GQA:分组查询注意力
LLaMA-2 70B 和 LLaMA-3 用 GQA(Ainslie et al. 2023):h 个查询头分成 n_kv 组,同组共用一组 K、V。n_kv = h 就是普通多头(MHA),n_kv = 1 是多查询(MQA)。02 号脚本第 4 部分:K、V 头数从 8 降到 4 / 2 / 1,缓存里 K 的形状跟着变成 (2, 4, 10, 8) …(2, 1, 10, 8),KV 缓存缩小 2 / 4 / 8 倍;把 MQA 的唯一一组 K、V 复制给每个头,输出与”MHA + 共享 K、V”完全一样(差 3.6e-07,float32)。
每个 token 的 KV 缓存 = 2 × 层数 × KV 头数 × 每头维度 × 字节数(fp16 为 2):
| 模型 | 层 / 查询头 / KV 头 | 每 token | 4096 token × 32 条 |
|---|---|---|---|
| LLaMA-2 7B | 32 / 32 / 32 | 512 KiB | 64 GiB |
| LLaMA-2 70B(若用 MHA) | 80 / 64 / 64 | 2560 KiB | 320 GiB |
| LLaMA-2 70B(GQA-8) | 80 / 64 / 8 | 320 KiB | 40 GiB |
| LLaMA-3 8B(GQA-8) | 32 / 32 / 8 | 128 KiB | 16 GiB |
70B 若用 MHA,32 条 4096 token 的请求要 320 GiB 的 KV 缓存,4 块 80 GB 的 H100 都装不下(还要放 140 GB 的权重);GQA-8 只要 40 GiB。解码是访存受限的,每生成一个 token 都要把整个 KV 缓存读一遍(第 9 讲),所以 GQA 同时省显存和带宽,计算量几乎不变。代价是表达能力略降,LLaMA-2 论文的消融里 GQA 与 MHA 效果接近。
3.5 规模与训练配方
02 号脚本第 5 部分(词表 32000、无偏置、输出层不共享,每层 4d² + 3·d·d_ff + 2d):
| 模型 | d | 层 | 头 | d_ff | 公式 | 论文 | 训练 token | token / 参数 |
|---|---|---|---|---|---|---|---|---|
| LLaMA-7B | 4096 | 32 | 32 | 11008 | 6.74B | 6.7B | 1.0T | 148 |
| LLaMA-13B | 5120 | 40 | 40 | 13824 | 13.02B | 13.0B | 1.0T | 77 |
| LLaMA-33B | 6656 | 60 | 52 | 17920 | 32.53B | 32.5B | 1.4T | 43 |
| LLaMA-65B | 8192 | 80 | 64 | 22016 | 65.29B | 65.2B | 1.4T | 21 |
训练只用公开数据(slides 第 14 页),标准的语言模型损失。slides 同一页还写了两句:不用标签平滑,加一个辅助损失让 softmax 的归一化项 log Z 接近 0。这两句原本出自 PaLM 论文的训练配方。为什么需要 z-loss?02 号脚本第 6 部分:softmax 对所有 logits 同加一个常数不敏感,交叉熵本身不会阻止 logits 整体”漂”大;fp32 下没关系,可一旦 logits 存成 bf16(有效精度只有 8 位,P2),平移 100 时交叉熵误差已有 0.17,平移 1000 时 1.37。z-loss = 10⁻⁴ · (log Z)² 把 log Z 拉回 0 附近,不改变预测的分布,只把数值留在精确的范围里——大规模、低精度训练的稳定性技巧。不用标签平滑的理由见第 6 讲 §7.3:预训练要的正是准确的概率。
3.6 把小 GPT 逐项升级成 LLaMA
03 号脚本在城市语言上(2 层、d = 64、训练 1000 步)把 GPT-2 式基线逐项替换,每种结构 2 个种子,看测试集交叉熵超出理论下界的毫 nat / token:
| 结构 | 参数 | KV 缓存(个数 / token) | 种子 0 | 种子 1 | 平均 |
|---|---|---|---|---|---|
| GPT-2 式基线 | 107,264 | 256 | 6.1 | 7.1 | 6.6 |
| + RMSNorm | 106,944 | 256 | 5.8 | 6.3 | 6.0 |
| + SwiGLU | 107,564 | 256 | 5.5 | 9.8 | 7.6 |
| + RoPE | 105,216 | 256 | 5.6 | 6.1 | 5.9 |
| + GQA(2 组 K/V) | 98,944 | 128 | 6.7 | 7.0 | 6.8 |
| LLaMA 式(全部 + 无偏置) | 95,680 | 128 | 5.6 | 5.6 | 5.6 |
六种结构的平均值相差 2.0,而同一结构换种子最多差 4.3。**在这门小语言上,四个改动对质量的影响都在噪声以内。**这不是坏消息:LLaMA 选这些部件,是因为它们在大规模上更稳定、对推理更友好,并且不损失质量——“质量不变”恰恰是前提。差别在别处:RoPE 少了 2048 个位置参数、也没有长度上限;GQA 让 KV 缓存减半;无偏置更省更简单。
长度外推(03 号脚本第 2 部分):只在长度 32 的窗口上训练,拿到长度 256 的窗口上用,按位置分段的交叉熵:
| 位置方案 | 位置 1–31 | 32–63 | 64–127 | 128–255 |
|---|---|---|---|---|
| 学出来的位置表(只训练过前 32 行) | 0.696 | 1.557 | 1.549 | 1.483 |
| 正弦位置编码(加到嵌入上) | 0.715 | 6.302 | 13.452 | 12.055 |
| RoPE | 0.694 | 0.689 | 0.732 | 0.827 |
| 不加任何位置信息(NoPE) | 0.697 | 0.707 | 0.922 | 1.149 |
训练过的位置上四种一样。超出之后:正弦编码崩得最厉害——“算得出任意位置”不等于”模型认识它”,没见过的 sin / cos 组合是陌生输入;学出来的位置表在没训练过的行上也明显变差;RoPE 退化得最慢(它只编码相对位置,而这里有用的相对距离都很短、训练时见过),但更远的 token 仍以没见过的旋转角出现,也在慢慢变差;NoPE(因果掩码本身就泄露了位置)近处同样好,远处退化得比 RoPE 快。真实 LLM 把上下文从 4K 扩到 128K,靠的是 RoPE 之上的改造(位置插值、NTK / YaRN 缩放)再加长文本训练,而不是”RoPE 天然能外推”。
4. 三者对照:“参数 vs 数据” · Comparing the three
| T5 | GPT-3 | LLaMA | |
|---|---|---|---|
| 结构 | 编码器–解码器 | Decoder-only | Decoder-only |
| 预训练目标 | span corruption | 下一个 token | 下一个 token |
| 归一化 | 只缩放的 LN(= RMSNorm),Pre-LN | Pre-LN | Pre-RMSNorm |
| 前馈激活 | ReLU | GELU | SwiGLU |
| 位置 | 相对位置偏置 | 学出来的位置表 | RoPE |
| 注意力 | 稠密 | 稠密 / 局部带状交替 | 稠密;LLaMA-2/3 用 GQA |
| 最大规模 / 训练 token | 11B / 34B | 175B / 300B | 65B / 1.4T |
| 主要用法 | 多任务微调 | 少样本提示 | 开放权重的基础模型 |
04 号脚本第 2 部分把”钱花在哪”摆在一起:
| 模型 | 参数 N | 训练 token D | token / 参数 | 训练 6ND | 推理每 token 2N |
|---|---|---|---|---|---|
| GPT-3 175B | 174.6B | 0.3T | 2 | 3.14e23 | 3.49e11 |
| LLaMA-13B | 13.0B | 1.0T | 77 | 7.80e22 | 2.60e10 |
| LLaMA-65B | 65.2B | 1.4T | 21 | 5.48e23 | 1.30e11 |
GPT-3 按 Kaplan 规模定律把预算主要花在参数上;Chinchilla(Hoffmann et al. 2022)发现同样的计算应该多用数据(约 20 token / 参数,LLaMA-65B 的 21 正好在这里);LLaMA 更进一步,为推理成本”过度训练”小模型:LLaMA-13B 的训练计算只有 GPT-3 的约 1/4,论文报告它在大多数基准上超过 GPT-3,推理成本只有约 1/13。一个模型训练一次、服务亿万次,推理才是长期的大头——这是模型–系统协同设计的典型例子。
5. 系统含义汇总 · Systems implications
| 设计 | 系统上的影响 | 后面哪一讲会用到 |
|---|---|---|
| RMSNorm | 少一次归约 / 同步,少一个参数向量 | 第 10–11 讲(融合的归一化内核) |
| SwiGLU | 多一个矩阵(d_ff 缩到 2/3 抵消);多保存一份激活;d_ff 对齐到 256 | 第 18 讲(激活显存)、第 4 讲(对齐) |
| RoPE | 没有位置表、没有长度上限;对 q、k 多一次逐元素旋转(可融合进注意力内核) | 第 21 讲(FlashAttention 里融合 RoPE) |
| GQA | KV 缓存缩小 h / n_kv 倍,解码时读的字节同样缩小 | 第 9、22、24 讲(解码、服务、PagedAttention) |
| span corruption | 目标短,解码器计算少 | — |
| 少样本提示 | 提示变长,KV 缓存变大,重复的前缀值得缓存 | 第 22、27 讲(RadixAttention、LMCache) |
| 小模型 + 多数据 | 训练更贵,推理更便宜 | 第 19–20 讲(量化)、第 22 讲之后(服务) |
| z-loss | 让 logits 在 bf16 下保持精确 | P2、第 11 讲(混合精度) |
6. 小结 · Summary
- T5:编码器–解码器 + span corruption(15% 的 token、平均 3 个一段,512 token 的样本变成 462 的输入、104 的目标)+ 一切都是文本到文本;规模靠加宽前馈和加头堆出来;训练 34B token。
- GPT-3:结构几乎就是 GPT-2(加了稠密 / 局部带状交替的注意力);175B 参数、300B token、3.14e23 FLOPs;核心发现是上下文学习——一个小实验里,归纳头让 2 层模型看过一次示例就能把准确率从 1/8 提到 0.985,参数不变。
- LLaMA:Pre-RMSNorm(少一次归约)、SwiGLU(d_ff = 2/3·4d,取到 256 的倍数)、RoPE(分数只依赖 m − n,没有位置表)、GQA(KV 缓存缩小 h / n_kv 倍)。在小模型上这些改动不改变质量——这正是它们能被采用的前提,价值在稳定性、推理成本和长度上。
- 参数 vs 数据:GPT-3(2 token / 参数)→ Chinchilla(约 20)→ LLaMA-7B(148):为推理成本过度训练小模型。
- 训练细节里的”小技巧”大多服务于稳定性:Pre-norm、不用标签平滑、z-loss(bf16 下 logits 不能漂太大)。
7. 常见误区 · Common pitfalls
- “T5 是 BERT 那样的掩码语言模型。” T5 把连续片段压成一个哨兵、由解码器自回归地写出被遮的内容;输入和目标都比原文短。
- “T5-11B 很深、很宽。” 它只有 24 + 24 块、d_model = 1024,参数主要在 d_ff = 65536 的前馈层和 128 个头里。
- “上下文学习就是模型在测试时做了梯度下降。” 参数一点没变;在小实验里它是注意力电路(归纳头)在一次前向里完成的”查找并复制”。
- “RMSNorm 和 LayerNorm 完全等价。” RMSNorm 不减均值,对输入的平移敏感;只是实践中效果相当。
- “SwiGLU 比 GELU 前馈层大 50%。” 中间维度缩到 2/3·4d 后,参数和 FLOPs 相同。
- “RoPE 是加到嵌入上的位置编码。” RoPE 不改嵌入,而是在每一层注意力里旋转 q 和 k。
- “有了 RoPE 模型就能处理任意长的输入。” 03 号脚本里 RoPE 也在慢慢变差;长上下文要靠插值 / 缩放再加训练。
- “相邻成对和前后两半成对的 RoPE 可以随便换。” 数学上等价,但权重要按维度置换转换,否则分数全错。
- “GQA 省计算。” 计算几乎不变,省的是 KV 缓存的显存和解码时的读带宽。
- “LLaMA 的四个改动让模型更聪明。” 在我们的小实验里质量差异在种子噪声以内;它们的价值是在不损失质量的前提下更稳、更省。
- “Chinchilla 最优就是最好的训练方式。” 它只在”给定训练计算”时最优;考虑推理成本时,更小的模型训练更久更划算。
8. 练习 · Exercises
- 一条 100 token 的样本按 T5 的规则(15%、平均片段长 3)破坏:被破坏几个 token、分几段?输入、目标各多长(含结束符)?
- 算出 T5-base 一个编码器块的参数量(d = 768、d_ff = 3072、12 个头 × 64,无偏置,2 个只缩放的 LayerNorm)。
- 一个 d = 2048 的 LLaMA 式模型,按”2/3·4d 再向上取到 256 的倍数”,d_ff 是多少?此时前馈层的参数比 GELU 版的 8d² 多百分之几?
- 用复数证明:把 q 的一对维度看成复数 q,位置 m 时乘以 e^{imθ};k 在位置 n 乘以 e^{inθ},则 Re(q e^{imθ} · conj(k e^{inθ})) 只依赖 m − n。
- LLaMA-3 70B:80 层、64 个查询头、8 个 KV 头、每头 128 维。每个 token 的 KV 缓存(fp16)多少?128K 上下文的一条请求呢?
- 对输入的每个分量都加 5,LayerNorm 的输出变不变?RMSNorm 呢?
- GPT-3 6.7B(公式 6.658B)训练 300B token,6ND 是多少 FLOPs?多少 PF-days?
- 训练计算预算为 5.48e23 FLOPs,按 Chinchilla 的”D = 20N”,计算最优的 N 和 D 各是多少?和 LLaMA-65B 比较。
- 03 号脚本里,正弦位置编码在位置 64–127 上的交叉熵高达 13.452,为什么比”学出来的位置表”还差?
- 为什么上下文学习的小实验至少需要 2 层注意力?只有 1 层会怎样?
- bf16 的有效精度是 8 位。logit 约为 1012 时,相邻两个可表示的 bf16 数相差多少?这对交叉熵意味着什么?
- n = 8、带宽 w = 3 的局部带状因果注意力要计算多少个 (查询, 键) 对?因果稠密注意力呢?
参考答案
- 破坏 round(100 × 0.15) = 15 个,分 round(15 / 3) = 5 段。输入 = 100 − 15 + 5(哨兵)+ 1(
</s>)= 91;目标 = 15 + 5(哨兵)+ 1 = 21。 - 注意力 4 × 768 × (12 × 64) = 2,359,296;前馈 2 × 768 × 3072 = 4,718,592;LayerNorm 2 × 768 = 1,536。合计 7,079,424。
- 2/3 × 8192 = 5461.33,除以 256 得 21.33,向上取 22,d_ff = 5632。前馈参数 3 × 2048 × 5632 = 34,603,008,8d² = 33,554,432,多 3.1%。
- q e^{imθ} · conj(k e^{inθ}) = q · conj(k) · e^{i(m−n)θ},实部只依赖 m − n(每一对维度都如此,总分数是各对之和)。这就是 RoPE 的分数 ⟨R_m q, R_n k⟩。
- 2 × 80 × 8 × 128 × 2 = 327,680 字节 = 320 KiB / token;131072 个 token:320 KiB × 131072 = 40 GiB。
- LayerNorm 不变(减均值时把 5 减掉了);RMSNorm 会变(均方根和方向都变了)。
- 6 × 6.658e9 × 3e11 ≈ 1.20e22 FLOPs;÷ (1e15 × 86400) ≈ 139 PF-days(04 号脚本:138.7)。
- C = 6ND = 6N · 20N = 120N²,N = √(5.48e23 / 120) ≈ 6.8e10(68B),D = 20N ≈ 1.35T。LLaMA-65B(65.2B、1.4T)正好落在计算最优点附近;而 LLaMA-7B 远离它(148 token / 参数)。
- 正弦编码对任何位置都”算得出”一个向量,但模型只见过位置 0–31 的那些 sin / cos 组合;更远位置的向量(尤其低频维度的值)落在训练分布之外,加到嵌入上之后把整个输入推到了陌生区域,于是彻底出错。学出来的位置表的未训练行接近初始化时的小随机数(还被权重衰减缩小),对嵌入的干扰反而较小。
- 要”找到前面同一个键后面的那个值”,查询(当前的键)必须和”前一个 token 是这个键”的位置匹配;而”我前一个 token 是什么”这个信息要先由一层注意力(看前一个位置)写进每个值的位置,第二层才能用它做匹配。只有 1 层时,查询只能按 token 本身的内容去匹配——会找到前面那个键,而不是它后面的值。
- bf16 有 8 位有效精度,[512, 1024) 区间的间距是 2^9 / 2^7 = 4,[1024, 2048) 是 8;1012 在前一个区间,相邻可表示数相差 4,存储误差最多 2。logits 的差决定概率(e^2 ≈ 7 倍),这样的误差足以让交叉熵完全算错——02 号脚本平移 1000 时误差 1.37。
- 带状:位置 0、1、2 分别看 1、2、3 个,位置 3–7 各看 3 个:1 + 2 + 3 × 6 = 21;因果稠密:8 × 9 / 2 = 36。
9. 延伸阅读 · Further reading
- Raffel et al. (2020) Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer(JMLR):T5;§3 系统比较了结构、目标、数据、规模,是”做消融实验”的范本。
- Brown et al. (2020) Language Models are Few-Shot Learners(NeurIPS):GPT-3;附录 D 有计算量的详细表格。
- Touvron et al. (2023) LLaMA 与 Llama 2:结构、数据配比、训练稳定性;LLaMA-2 的 GQA 消融。
- Su et al. (2021) RoFormer: Enhanced Transformer with Rotary Position Embedding:RoPE 的推导与远程衰减。
- Shazeer (2020) GLU Variants Improve Transformer:SwiGLU 等门控前馈层的对比。
- Zhang & Sennrich (2019) Root Mean Square Layer Normalization(NeurIPS)。
- Ainslie et al. (2023) GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints;Shazeer (2019) Fast Transformer Decoding: One Write-Head is All You Need(MQA)。
- Hoffmann et al. (2022) Training Compute-Optimal Large Language Models(Chinchilla)。
- Olsson et al. (2022) In-context Learning and Induction Heads(Anthropic):归纳头与上下文学习的关系。
- Chowdhery et al. (2022) PaLM:z-loss、不用标签平滑、SwiGLU 的大规模实践。
- Chen et al. (2023) Extending Context Window of Large Language Models via Positional Interpolation;Peng et al. (2023) YaRN:RoPE 的长度扩展。
10. 下一讲预告 · Next lecture
这一讲里 T5 用 32K 的 SentencePiece 词表,GPT-3 用 50257 个 token 的字节级 BPE,LLaMA 用 32000,LLaMA-3 扩到 128K——分词器是每个 LLM 的第一层,也决定了序列长度、嵌入矩阵和 softmax 的大小。第 8 讲(分词与嵌入)从”按词切""按字切”的问题讲起,从零实现 BPE(训练、编码、解码),用信息论(VOLT 的边际效用)讨论”词表多大最好”,再看实际 LLM 分词器的种种细节:字节级 BPE、SentencePiece、代码与数字的处理、多语言词表的分配,以及无分词器的 Byte Latent Transformer。