第 7 讲 · 预训练大语言模型:T5、GPT-3 与 LLaMA · Pre-trained LLMs

Large Language Model Systems · Lecture 07。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 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

学完这一讲,你应该能够:

  1. 说出 T5 的三个关键设计:编码器–解码器结构、span corruption 预训练目标、“一切都是文本到文本”的多任务格式;能手算一条样本破坏后的输入、目标长度。
  2. 说出 GPT-3 的贡献:规模(175B、300B token、3.14e23 FLOPs)和上下文学习(few-shot 提示),并用一个小实验解释上下文学习靠的是什么(归纳头)。
  3. 解释 LLaMA 相对 GPT-2 / 原始 Transformer 的四处改动——Pre-RMSNorm、SwiGLU、RoPE、GQA——各自的公式、为什么这样做、系统上省了什么。
  4. 用公式复现 T5、GPT-3、LLaMA 各个规模的参数量,并算出训练计算量(6ND)。
  5. 理解”参数 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 + 104104102.0
同参数量的 decoder-only,预测下一个 token512512202.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_modeld_ff头 × d_kv公式slides
T5-base12 + 12768307212 × 640.223B220M
T5-3B24 + 2410241638432 × 1282.852B3B
T5-11B24 + 24102465536128 × 12811.307B11B

注意 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)学习率公式
Small1276812640.5M6.0e-40.125B
XL242048241281M2.0e-41.316B
6.7B324096321282M1.2e-46.658B
175B9612288961283.2M0.6e-4174.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)
10.985
20.992
≥ 30.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:

RMSNorm(x)=x1d∑ixi2+ϵ⊙γ\mathrm{RMSNorm}(x) = \frac{x}{\sqrt{\tfrac{1}{d}\sum_i x_i^2 + \epsilon}} \odot \gamma

不减均值、没有 β。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 页:

FFNSwiGLU(x)=(Swish(xW1)⊙xV) W2,Swish(z)=z⋅σ(z)\mathrm{FFN}_{\mathrm{SwiGLU}}(x) = \big(\mathrm{Swish}(xW_1) \odot xV\big)\,W_2,\qquad \mathrm{Swish}(z) = z\cdot\sigma(z)

三个矩阵:一个”门”(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 全部精确复现:

模型d2/3·4d取到 256 的倍数 = 论文配置
LLaMA-7B409610922.6711008
LLaMA-13B512013653.3313824
LLaMA-33B665617749.3317920
LLaMA-65B819221845.3322016

取到 256 的倍数是为了矩阵形状对齐(第 4 讲:分块、合并访存都喜欢整齐的维度)。系统代价:反向要保存门和值两个中间张量,比 GELU 版多一份激活。

3.3 RoPE:旋转位置编码

slides 第 11–12 页:把 q、k 的每一对维度看成平面上的一个点,位置 m 的向量旋转 mθ_i:

f(q,m)=(cos⁡mθ−sin⁡mθsin⁡mθcos⁡mθ)(q1q2),⟨f(q,m), f(k,n)⟩=g(q,k,m−n)f(q, m) = \begin{pmatrix}\cos m\theta & -\sin m\theta\\ \sin m\theta & \cos m\theta\end{pmatrix}\begin{pmatrix}q_1\\ q_2\end{pmatrix},\qquad \langle f(q,m),\ f(k,n)\rangle = g(q, k, m-n)

旋转矩阵的转置等于逆,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 头每 token4096 token × 32 条
LLaMA-2 7B32 / 32 / 32512 KiB64 GiB
LLaMA-2 70B(若用 MHA)80 / 64 / 642560 KiB320 GiB
LLaMA-2 70B(GQA-8)80 / 64 / 8320 KiB40 GiB
LLaMA-3 8B(GQA-8)32 / 32 / 8128 KiB16 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公式论文训练 tokentoken / 参数
LLaMA-7B40963232110086.74B6.7B1.0T148
LLaMA-13B512040401382413.02B13.0B1.0T77
LLaMA-33B665660521792032.53B32.5B1.4T43
LLaMA-65B819280642201665.29B65.2B1.4T21

训练只用公开数据(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,2642566.17.16.6
+ RMSNorm106,9442565.86.36.0
+ SwiGLU107,5642565.59.87.6
+ RoPE105,2162565.66.15.9
+ GQA(2 组 K/V)98,9441286.77.06.8
LLaMA 式(全部 + 无偏置)95,6801285.65.65.6

六种结构的平均值相差 2.0,而同一结构换种子最多差 4.3。**在这门小语言上,四个改动对质量的影响都在噪声以内。**这不是坏消息:LLaMA 选这些部件,是因为它们在大规模上更稳定、对推理更友好,并且不损失质量——“质量不变”恰恰是前提。差别在别处:RoPE 少了 2048 个位置参数、也没有长度上限;GQA 让 KV 缓存减半;无偏置更省更简单。

长度外推(03 号脚本第 2 部分):只在长度 32 的窗口上训练,拿到长度 256 的窗口上用,按位置分段的交叉熵:

位置方案位置 1–3132–6364–127128–255
学出来的位置表(只训练过前 32 行)0.6961.5571.5491.483
正弦位置编码(加到嵌入上)0.7156.30213.45212.055
RoPE0.6940.6890.7320.827
不加任何位置信息(NoPE)0.6970.7070.9221.149

训练过的位置上四种一样。超出之后:正弦编码崩得最厉害——“算得出任意位置”不等于”模型认识它”,没见过的 sin / cos 组合是陌生输入;学出来的位置表在没训练过的行上也明显变差;RoPE 退化得最慢(它只编码相对位置,而这里有用的相对距离都很短、训练时见过),但更远的 token 仍以没见过的旋转角出现,也在慢慢变差;NoPE(因果掩码本身就泄露了位置)近处同样好,远处退化得比 RoPE 快。真实 LLM 把上下文从 4K 扩到 128K,靠的是 RoPE 之上的改造(位置插值、NTK / YaRN 缩放)再加长文本训练,而不是”RoPE 天然能外推”。


4. 三者对照:“参数 vs 数据” · Comparing the three

T5GPT-3LLaMA
结构编码器–解码器Decoder-onlyDecoder-only
预训练目标span corruption下一个 token下一个 token
归一化只缩放的 LN(= RMSNorm),Pre-LNPre-LNPre-RMSNorm
前馈激活ReLUGELUSwiGLU
位置相对位置偏置学出来的位置表RoPE
注意力稠密稠密 / 局部带状交替稠密;LLaMA-2/3 用 GQA
最大规模 / 训练 token11B / 34B175B / 300B65B / 1.4T
主要用法多任务微调少样本提示开放权重的基础模型

04 号脚本第 2 部分把”钱花在哪”摆在一起:

模型参数 N训练 token Dtoken / 参数训练 6ND推理每 token 2N
GPT-3 175B174.6B0.3T23.14e233.49e11
LLaMA-13B13.0B1.0T777.80e222.60e10
LLaMA-65B65.2B1.4T215.48e231.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)
GQAKV 缓存缩小 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

  1. T5:编码器–解码器 + span corruption(15% 的 token、平均 3 个一段,512 token 的样本变成 462 的输入、104 的目标)+ 一切都是文本到文本;规模靠加宽前馈和加头堆出来;训练 34B token。
  2. GPT-3:结构几乎就是 GPT-2(加了稠密 / 局部带状交替的注意力);175B 参数、300B token、3.14e23 FLOPs;核心发现是上下文学习——一个小实验里,归纳头让 2 层模型看过一次示例就能把准确率从 1/8 提到 0.985,参数不变。
  3. LLaMA:Pre-RMSNorm(少一次归约)、SwiGLU(d_ff = 2/3·4d,取到 256 的倍数)、RoPE(分数只依赖 m − n,没有位置表)、GQA(KV 缓存缩小 h / n_kv 倍)。在小模型上这些改动不改变质量——这正是它们能被采用的前提,价值在稳定性、推理成本和长度上。
  4. 参数 vs 数据:GPT-3(2 token / 参数)→ Chinchilla(约 20)→ LLaMA-7B(148):为推理成本过度训练小模型。
  5. 训练细节里的”小技巧”大多服务于稳定性: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

  1. 一条 100 token 的样本按 T5 的规则(15%、平均片段长 3)破坏:被破坏几个 token、分几段?输入、目标各多长(含结束符)?
  2. 算出 T5-base 一个编码器块的参数量(d = 768、d_ff = 3072、12 个头 × 64,无偏置,2 个只缩放的 LayerNorm)。
  3. 一个 d = 2048 的 LLaMA 式模型,按”2/3·4d 再向上取到 256 的倍数”,d_ff 是多少?此时前馈层的参数比 GELU 版的 8d² 多百分之几?
  4. 用复数证明:把 q 的一对维度看成复数 q,位置 m 时乘以 e^{imθ};k 在位置 n 乘以 e^{inθ},则 Re(q e^{imθ} · conj(k e^{inθ})) 只依赖 m − n。
  5. LLaMA-3 70B:80 层、64 个查询头、8 个 KV 头、每头 128 维。每个 token 的 KV 缓存(fp16)多少?128K 上下文的一条请求呢?
  6. 对输入的每个分量都加 5,LayerNorm 的输出变不变?RMSNorm 呢?
  7. GPT-3 6.7B(公式 6.658B)训练 300B token,6ND 是多少 FLOPs?多少 PF-days?
  8. 训练计算预算为 5.48e23 FLOPs,按 Chinchilla 的”D = 20N”,计算最优的 N 和 D 各是多少?和 LLaMA-65B 比较。
  9. 03 号脚本里,正弦位置编码在位置 64–127 上的交叉熵高达 13.452,为什么比”学出来的位置表”还差?
  10. 为什么上下文学习的小实验至少需要 2 层注意力?只有 1 层会怎样?
  11. bf16 的有效精度是 8 位。logit 约为 1012 时,相邻两个可表示的 bf16 数相差多少?这对交叉熵意味着什么?
  12. n = 8、带宽 w = 3 的局部带状因果注意力要计算多少个 (查询, 键) 对?因果稠密注意力呢?

参考答案

  1. 破坏 round(100 × 0.15) = 15 个,分 round(15 / 3) = 5 段。输入 = 100 − 15 + 5(哨兵)+ 1(</s>)= 91;目标 = 15 + 5(哨兵)+ 1 = 21。
  2. 注意力 4 × 768 × (12 × 64) = 2,359,296;前馈 2 × 768 × 3072 = 4,718,592;LayerNorm 2 × 768 = 1,536。合计 7,079,424。
  3. 2/3 × 8192 = 5461.33,除以 256 得 21.33,向上取 22,d_ff = 5632。前馈参数 3 × 2048 × 5632 = 34,603,008,8d² = 33,554,432,多 3.1%。
  4. q e^{imθ} · conj(k e^{inθ}) = q · conj(k) · e^{i(m−n)θ},实部只依赖 m − n(每一对维度都如此,总分数是各对之和)。这就是 RoPE 的分数 ⟨R_m q, R_n k⟩。
  5. 2 × 80 × 8 × 128 × 2 = 327,680 字节 = 320 KiB / token;131072 个 token:320 KiB × 131072 = 40 GiB。
  6. LayerNorm 不变(减均值时把 5 减掉了);RMSNorm 会变(均方根和方向都变了)。
  7. 6 × 6.658e9 × 3e11 ≈ 1.20e22 FLOPs;÷ (1e15 × 86400) ≈ 139 PF-days(04 号脚本:138.7)。
  8. 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 / 参数)。
  9. 正弦编码对任何位置都”算得出”一个向量,但模型只见过位置 0–31 的那些 sin / cos 组合;更远位置的向量(尤其低频维度的值)落在训练分布之外,加到嵌入上之后把整个输入推到了陌生区域,于是彻底出错。学出来的位置表的未训练行接近初始化时的小随机数(还被权重衰减缩小),对嵌入的干扰反而较小。
  10. 要”找到前面同一个键后面的那个值”,查询(当前的键)必须和”前一个 token 是这个键”的位置匹配;而”我前一个 token 是什么”这个信息要先由一层注意力(看前一个位置)写进每个值的位置,第二层才能用它做匹配。只有 1 层时,查询只能按 token 本身的内容去匹配——会找到前面那个键,而不是它后面的值。
  11. bf16 有 8 位有效精度,[512, 1024) 区间的间距是 2^9 / 2^7 = 4,[1024, 2048) 是 8;1012 在前一个区间,相邻可表示数相差 4,存储误差最多 2。logits 的差决定概率(e^2 ≈ 7 倍),这样的误差足以让交叉熵完全算错——02 号脚本平移 1000 时误差 1.37。
  12. 带状:位置 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。

← 返回课程目录