第 4 讲 · 预训练、微调与现代 Transformer · Pre-training, Fine-tuning & Modern Transformers

Generative AI · Lecture 04。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

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

本篇目录

对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Spring 2026;Aran Nayebi、Matt Gormley),Lecture 4 · Mon 26-Jan · Pre-training, fine-tuning / Modern Transformers(slides 标题:Pretraining vs. finetuning + Modern Transformers (RoPE, GQA, Longformer))。 阅读材料:Ainslie et al. (2023), GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints;Beltagy, Peters & Cohan (2020), Longformer: The Long-Document Transformer;Su et al. (2021), RoFormer: Enhanced Transformer with Rotary Position Embedding。 依据说明:本讲以原课第 4 讲公开的 slides(lecture4-rope-gqa.pdf)为主线:深度学习的起点与 2006 年的预训练、预训练与微调的定义和例子、MNIST 上的预训练、自编码器、视觉的有监督预训练、LLM 的生成式预训练与训练数据、预训练 → 中期训练 → 后训练的流程、现代开源模型的配方清单、RoPE(包括被标了 “wrong” 的那一版公式、两个思考题、高效实现和矩阵版)、GQA、滑动窗口注意力的三种实现。模型清单里的细节以 slides 为准,个别地方对照了原始论文。全部实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture04/(5 个脚本 + 2 个模块;只需要 PyTorch CPU 版;02 1 秒,其余 50–70 秒;05 --seeds 3 约 2 分钟) 预计阅读时间:4 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

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

  1. 说出预训练和微调的定义(两种预训练:无监督 / 有监督),举出视觉和语言里的例子;解释”先在便宜的大数据上预训练、再在昂贵的小数据上微调”为什么有效,以及全量微调可能带来的问题。
  2. 描述现代 LLM 的训练流程:预训练 → 中期训练 → 后训练。
  3. 列出 2017 年之后开源 Transformer 的常见改动:RMSNorm、SwiGLU、去掉偏置、RoPE、GQA/MQA、滑动窗口……
  4. 推导 RoPE:为什么按绝对位置旋转 qq、kk 会得到只依赖相对位置的注意力分数;回答 slides 的两个问题(为什么切成二维小块、为什么每块转不同的角度);会写高效实现。
  5. 写出 GQA 的公式,说明 MHA 和 MQA 是它的两个特例;会计算 KV 缓存省了多少,知道怎样把 MHA 模型”改装”成 GQA。
  6. 画出滑动窗口注意力的掩码,比较三种实现的代价,计算多层叠加后的感受野,解释 Mistral 的滚动缓存。
  7. 用实验说明:相对位置编码并非在所有任务上都更好。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 2 讲:注意力、多头、位置编码、GPT 的结构指令微调、RLHF、DPO(第 11–12 讲)
第 3 讲:KV 缓存、批处理参数高效微调 LoRA(第 10 讲)
二维旋转矩阵 (cos⁡θ−sin⁡θsin⁡θcos⁡θ)\begin{pmatrix}\cos\theta & -\sin\theta\\ \sin\theta & \cos\theta\end{pmatrix}长上下文外推(位置插值、YaRN,第 19 讲)
前置讲 P1 §5 的参数公式ViT 的有监督预训练(第 5 讲);混合专家 MoE(第 16 讲)

0.3 本讲地图 Map

§1  回顾
§2  预训练 vs 微调:2006 年的火花;定义与例子;自编码器;LLM 的预训练与训练流程;实验     ← 代码 01
§3  现代 Transformer:开源模型的配方清单;RMSNorm、SwiGLU、去掉偏置
§4  旋转位置编码 RoPE                                                         ← 代码 02
§5  分组查询注意力 GQA                                                         ← 代码 03
§6  滑动窗口注意力                                                             ← 代码 04
§7  拼起来:HW1 式的现代 TransformerLM;位置编码与长度外推的再讨论               ← 代码 05
§8–12  小结、误区、练习、延伸阅读、下一讲

1. 回顾 · Recap

slides 把前三讲总结为两条线:

  • 深度学习:自动微分以模块(forward() 和 backward())为构件;计算图是定义函数的另一种方式;我们见过 RNN-LM 和 Transformer-LM 两张很深的计算图。
  • 语言建模:以前面的词为条件采样下一个词;n-gram 用巨大的骰子表,RNN-LM / Transformer-LM 用神经网络;n-gram 靠数数学习,神经语言模型通过 SGD 优化目标函数、用自动微分算梯度(第 3 讲)。

这一讲回答两个新问题:(1) 训练好的语言模型怎样用到别的任务上——预训练与微调;(2) 2017 年的 Transformer 在今天的开源模型里变成了什么样子。


2. 预训练 vs 微调 · Pre-training vs fine-tuning

2.1 深度学习的火花来自预训练

slides 指出,现代深度学习的结构其实早就有了:

  • 1960 年代:Rosenblatt 的三层感知机,ReLU;
  • 1970–80 年代:RNN 和 CNN;
  • 1990 年代:线性化的自注意力。

但”深度”网络在 2006 年之前很难训练(第 2 讲讲过的梯度消失是原因之一)。火花来自 2006 年的预训练(Hinton & Salakhutdinov, 2006):先用无监督的方式一层一层地训练网络,再在有标注的数据上整体训练。

2.2 定义

slides 的定义:

  • 预训练:随机初始化参数,然后——
    • 选项 A:在非常大的无标注数据集上做无监督训练;
    • 选项 B:在非常大的有标注数据集上做有监督训练。
  • 微调:用预训练得到的值初始化参数;(可选地)加一个只有少量随机初始化参数的预测头;在感兴趣的具体任务上用反向传播训练。
视觉语言
预训练A:在大量无标注图像(如 MNIST)上训练自编码器;B:在大型图像分类数据集上有监督训练(如 ImageNet-21k:2.1 万类、1400 万张图)在大量无标注句子上最大化似然:The Pile(800 GB 文本)、Dolma(3 万亿 token)
微调目标检测:在 COCO 的 20 万张标注图上训练;语义分割:在 ADE20k 的 2 万张标注图上训练MMLU:57 个任务(从小学数学到遗传学、法律)里各取几个例子;代码生成:MBPP 的约 400 个训练例子

模式很清楚:预训练用便宜、海量的数据,微调用昂贵、少量的数据。

2.3 MNIST 上的预训练

slides 展示了 Bengio et al. (2006) 在 MNIST 手写数字分类上的结果(错误率越低越好),比较了四种做法:浅层网络、不预训练的深层网络、有监督逐层预训练的深层网络、无监督逐层预训练的深层网络——每种做法最后都在有标注的数据上微调。结论是无监督预训练的深层网络错误率最低:同样深的网络,先预训练再微调,比直接训练好。

2.4 自编码器:无监督预训练”第一层”该预测什么?

slides 问:“无监督地预训练第一层,它应该预测什么?我们还观察到了什么?“答案是:输入本身。

  • 编码器:z=h(Wx)z = h(Wx);解码器:x′=h(W′z)x' = h(W'z);
  • 损失:重构误差 ∥x−DECODER(ENCODER(x))∥\lVert x - \mathrm{DECODER}(\mathrm{ENCODER}(x)) \rVert,用两层神经网络同样的反向传播训练,xx 既是输入又是输出。

如果隐藏层 zz 比输入小,网络就被迫学一种压缩的表示。逐层预训练就是:训练好第一层的自编码器后,把它的 zz 当作下一层的输入,再训练下一层,依此类推;最后把所有编码器叠起来,加上分类层,整体微调。(第 9 讲的变分自编码器会把自编码器变成一个生成模型。)

2.5 有监督预训练(视觉)

slides:“现在我们倾向于直接在一个巨大的有标注数据集上做有监督预训练。“Vision Transformer 的成功在很大程度上归功于更大的预训练数据集——第 5 讲会用实验看到这一点。

2.6 LLM 的无监督预训练

对深度语言模型来说,“无监督预训练”就是第 3 讲的生成式预训练:每个训练样本是一个(无标注的)句子,目标函数是观察到的句子的似然;实践中把很多样本组成批来提高效率。

slides 给出了两个训练数据的例子:

  • GPT-3 的训练数据:以过滤后的 Common Crawl 为主,再加上 WebText2、两个图书语料、维基百科,按质量给不同的采样权重(第 3 讲 §3.1)。
  • The Pile:一个开源的语言模型训练集,由 22 个较小的数据集组成,偏重高质量文本,约 825 GB。

2.7 LLM 的训练流程

slides 把今天的 LLM 训练分成三个阶段:

阶段做什么例子
预训练在大量无标注句子上最大化似然The Pile(800 GB)、Dolma(3 万亿 token)
中期训练(mid-training)和预训练一样,但换成更高质量的数据Dolmino Mix 1124(1000 亿–3000 亿 token)
后训练(post-training)以下的某种组合:指令微调;RLHF / DPO;可验证奖励的强化学习(RLVR);安全微调;任务相关的微调。通常只用少量有监督数据第 11、12、20 讲

2.8 实验:预训练 + 微调 vs 从零训练

01_pretrain_finetune.py 在农场语言上设计了一个下游任务:给定句子开头到动词之前的部分(如 “the dogs near the cat behind the cow”),判断主语是单数还是复数。测试集里干扰名词全部和主语相反,“看最后一个名词”这条捷径在测试集上的准确率是 0。

预训练模型就是第 2 讲在 2 万句无标注文本上训练的 GPT。比较几种做法(3 个随机种子的平均;k = 4–6 是比训练句子更长的”外推”测试):

做法标注样本数 Nk = 1–3k = 4–6
零样本(只用语言模型:比较复数动词和单数动词的总概率)01.0001.000
从零训练160.4610.374
从零训练2560.9820.587
线性探针(冻结预训练模型,只训练分类头)161.0000.999
全量微调,学习率 1e-3160.9100.842
全量微调,学习率 1e-32561.0000.932
全量微调,学习率 1e-4160.9310.868
  • 从零训练:16 个样本只有 0.461(比乱猜还差);256 个样本能到 0.982,但外推到更长的句子只有 0.587。几百个样本不够让模型自己发现”主语是第一个名词、要跳过介词短语”这条规则。
  • 用预训练模型:16 个样本、只训练分类头就全对。预训练时模型为了预测动词的形式,已经学会了在动词前的位置表示主语的单复数(第 2 讲 §6.4 的干预实验);标注数据只需要教它”把这个信息读出来”。
  • 全量微调反而不如线性探针:16 个样本、学习率 1e-3 时只有 0.910,外推也更差。用很少的样本更新十万个参数,会破坏预训练学到的表示(过拟合 / 灾难性遗忘)。把学习率降到 1e-4 只略有改善。在这个任务上,最保守的做法——只训练分类头——反而最好。这是第 10 讲参数高效微调(LoRA 等只训练很少的参数)的动机之一。
  • 零样本也是 1.000:语言模型本身就会做这个任务,只是要换一种问法——让它预测下一个词(GPT-2 的思路,第 3 讲 §7)。

这个例子里”预训练数据”和下游任务高度相关,所以效果特别夸张。真实情况下两者的距离更远,但道理相同:便宜的无标注数据教会模型通用的表示,昂贵的标注数据只用来做最后一步。


3. 现代 Transformer 模型 · Modern Transformer models

3.1 开源模型的配方清单

slides 列了一张很长的清单(按时间顺序,节选):

模型时间相对于前代 / GPT 的主要改动(以 slides 为准)
PaLM2022.105400 亿参数,闭源;SwiGLU 代替 ReLU/GELU;多查询注意力(MQA);输入输出嵌入共享
Llama-12023.02半开源;13B 平均超过 GPT-3;输入端的 RMSNorm(代替输出端的 LayerNorm);SwiGLU;RoPE 代替绝对位置;AdamW,1.0–1.4 万亿 token
Falcon2023.06–117B、40B、180B,首个 Apache 2.0 的完全开源模型;多查询 / 分组查询注意力代替 MHA(slides 这一行写得有些混乱:7B 用 MQA,更大的版本用分组的变体);RoPE(比 ALiBi 好);GELU;最多 3.5 万亿 token,z-loss
Llama-22023.087B、13B、70B;推出 Llama 2-Chat;GQA(论文里只有 34B、70B 用了 GQA);上下文 4096;2 万亿 token
Mistral2023.107B,Apache 2.0;平均超过 Llama-2 13B;GQA;滑动窗口注意力 + 滚动缓存
OLMo2024.021B、7B,完全开放(权重、数据、训练代码);无偏置;无参数的 LayerNorm;SwiGLU;RoPE;QKV 截断
Gemma2024.022B、7B,开放权重;多查询注意力;RoPE;GeGLU、RMSNorm;3–6 万亿 token
Gemma 22024.06GQA、RoPE;pre-norm 和 post-norm 都用 RMSNorm;QK-Norm;局部滑动窗口和全局注意力交替
Llama 3 / 3.12024.048B、70B、405B;GQA(更少的 KV 头);文档内掩码;405B 用了 15.6 万亿 token
OLMo 22024.12–2025.03RMSNorm、重新排列归一化的位置、QK-norm;RoPE 但 base 大得多;z-loss,4–6 万亿 token
DeepSeek-R12025.01MIT 开源;R1-Zero 纯强化学习,R1 是 SFT + RL(第 20 讲)
Gemma 3、Llama 4、Qwen 32025.03–05量化感知训练(Gemma 3)等
gpt-oss2025.0820B、120B;RoPE、GQA、SwiGLU;混合专家(MoE)(第 16 讲);预训练用了 210 万 H100 小时
Olmo 32025.127B、32B,完全开放;7B 用 MHA、32B 用 GQA;RoPE;滑动窗口注意力

slides 还开了个玩笑:“要是 LLM 能帮我自动更新这张清单就好了。”——“你会这么想,但是……”(它们会编造不存在的模型细节。)

几个反复出现的改动:

  • RMSNorm 代替 LayerNorm,并放在子层的输入端(pre-norm);
  • SwiGLU / GeGLU 门控前馈网络代替 ReLU / GELU;
  • 去掉线性层的偏置;
  • RoPE 代替绝对位置嵌入;
  • GQA / MQA 代替普通多头注意力;
  • 滑动窗口注意力(常和全局注意力交替);
  • 训练稳定性技巧:z-loss、QK-norm 等。

slides 重点讲其中三个:RoPE、GQA、滑动窗口注意力(§4–6)。前三个在 modern_lm.py 里都有实现,这里简要说明。

3.2 RMSNorm、SwiGLU、去掉偏置

RMSNorm(Zhang & Sennrich, 2019):y=x/mean(x2)+ϵ⊙gy = x / \sqrt{\mathrm{mean}(x^2) + \epsilon} \odot g。和 LayerNorm(第 2 讲 §4.3)相比,不减均值、没有偏置 β\beta,只按均方根缩放;少一次求均值、少一组参数,效果相当(练习 9)。

SwiGLU(Shazeer, 2020):FFN(x)=Wdown(SiLU(Wgatex)⊙Wupx)\mathrm{FFN}(x) = W_\text{down}\big(\mathrm{SiLU}(W_\text{gate}x) \odot W_\text{up}x\big)。一路算”内容”,一路算”门开多大”,逐元素相乘。比 GELU 前馈多一个矩阵;为了参数量相当,中间维度取约 83d\frac{8}{3}d(练习 8)。

去掉偏置:实践中偏置几乎不影响效果,去掉后参数更少、训练更稳定(PaLM 的报告)。


4. 旋转位置编码 RoPE · Rotary position embeddings

4.1 动机:相对位置

第 2 讲的位置编码都是绝对的:把”我在第 tt 个位置”的向量加到输入上。但语言里大多数关系是相对的:“形容词在名词前一个位置”、“动词离它的主语 3 个词”,不管这句话出现在文档的开头还是第 1000 个 token。我们希望注意力分数 st,js_{t,j} 只依赖内容和相对距离 t−jt - j。

RoPE(Su et al., 2021)用一个漂亮的办法做到了这一点:按每个 token 的绝对位置旋转它的 qq 和 kk。

4.2 slides 的定义

标准注意力:qj=Wq⊤xjq_j = W_q^\top x_j,kj=Wk⊤xjk_j = W_k^\top x_j,st,j=kj⊤qt/dks_{t,j} = k_j^\top q_t / \sqrt{d_k}。RoPE 注意力:

q~j=RΘ,j qj,k~j=RΘ,j kj,st,j=k~j⊤q~t/dk,at=softmax(st)\tilde q_j = R_{\Theta, j}\, q_j,\qquad \tilde k_j = R_{\Theta, j}\, k_j,\qquad s_{t,j} = \tilde k_j^\top \tilde q_t / \sqrt{d_k},\qquad a_t = \mathrm{softmax}(s_t)

其中对某个固定的绝对位置 mm,旋转矩阵是块对角的:

RΘ,m=(cos⁡mθ1−sin⁡mθ1sin⁡mθ1cos⁡mθ1⋱cos⁡mθd/2−sin⁡mθd/2sin⁡mθd/2cos⁡mθd/2),Θ={θi=10000−2(i−1)/d, i=1,…,d/2}R_{\Theta, m} = \begin{pmatrix} \cos m\theta_1 & -\sin m\theta_1 & & & \\ \sin m\theta_1 & \cos m\theta_1 & & & \\ & & \ddots & & \\ & & & \cos m\theta_{d/2} & -\sin m\theta_{d/2} \\ & & & \sin m\theta_{d/2} & \cos m\theta_{d/2} \end{pmatrix},\qquad \Theta = \{\theta_i = 10000^{-2(i-1)/d},\ i = 1, \dots, d/2\}

也就是说:把 dd 维向量切成 d/2d/2 个二维小块,第 ii 个小块旋转 mθim\theta_i 弧度,mm 是这个查询或键的绝对位置(slides 的图:Key idea)。02_rope.py 第 1 部分打印了 RΘ,5R_{\Theta,5} 的左上角,并验证三种写法(完整矩阵、slides 的逐元素写法、矩阵版)给出同一个结果。

4.3 slides 上被标了 “wrong” 的那一版

slides 先放了一版公式,上面被红笔标了好几处 “wrong”,并自嘲:“为什么这张 slide 有这么多错误?我真的不知道,我都是自己仔细敲的 LaTeX。“那一版的意思大致是:qq 和 kk 都旋转 RΘ,mR_{\Theta, m},其中 m=t−jm = t - j。

这为什么错?02 第 3 部分真的按它算了一遍:

版本和”不加位置信息”的分数的 max|差|
错误版:qq、kk 都旋转 Rt−jR_{t-j}1.8×10−151.8 \times 10^{-15}
正确版:qtq_t 旋转 RtR_t,kjk_j 旋转 RjR_j4.57

两边转同一个角度,旋转在点积里完全抵消(Rm⊤Rm=IR_m^\top R_m = I),模型什么位置信息都得不到。正确的做法是每个向量按自己的位置旋转——相对位置会在点积里”自己冒出来”。

4.4 为什么只依赖相对位置

旋转矩阵满足 RΘ,j⊤RΘ,t=RΘ,t−jR_{\Theta,j}^\top R_{\Theta,t} = R_{\Theta, t-j}(转 tt 再倒转 jj 等于转 t−jt - j)。于是

st,j∝k~j⊤q~t=kj⊤RΘ,j⊤RΘ,t qt=kj⊤RΘ,t−j qts_{t,j} \propto \tilde k_j^\top \tilde q_t = k_j^\top R_{\Theta,j}^\top R_{\Theta,t}\, q_t = k_j^\top R_{\Theta, t-j}\, q_t

绝对位置在相乘时抵消了,只剩相对距离 t−jt - j。02 第 2 部分把同一对 qq、kk 放在 (5, 2)、(105, 102)、(1005, 1002) 三组位置上,点积都是 +1.685028392114;矩阵恒等式的误差 9.5×10−159.5 \times 10^{-15}。

和第 2 讲的正弦位置编码比较:正弦编码加在输入上,PE[p]⋅PE[p+k]\mathrm{PE}[p] \cdot \mathrm{PE}[p+k] 只依赖 kk,但经过 WqW_q、WkW_k 的线性变换之后这个性质就不严格了;RoPE 直接作用在每一层的 qq、kk 上,相对性在每一层都严格成立。

4.5 slides 的两个问题

问题 1:把向量切成二维小块再旋转,有什么好处?

  • 旋转不改变向量的长度(02 第 4 部分:差 1.8×10−151.8 \times 10^{-15}),所以位置信息只改变 qq、kk 的方向,不会放大或缩小内容;
  • 两个旋转过的二维向量的点积只取决于它们转过的角度之差——这正是相对位置的来源;
  • 块对角矩阵乘向量只需要 O(d)O(d) 次运算(§4.6),而不是 O(d2)O(d^2)。

问题 2:为什么不同的小块转不同的角度?

如果所有块都用同一个转速 θ\theta,“相隔 Δ\Delta 的两个位置有多像”就是 cos⁡(Δθ)\cos(\Delta\theta),以 2π/θ2\pi/\theta 为周期反复出现,模型分不清这些距离。02 第 4 部分(d=64d = 64):

距离 Δ\Delta所有块都用 θ=1\theta = 1RoPE:θi=10000−2(i−1)/d\theta_i = 10000^{-2(i-1)/d}
0+1.000+1.000
1+0.540+0.966
44+1.000+0.598
355−1.000+0.225
4000−0.730+0.002

同一转速时,Δ=44\Delta = 44(约 7 圈)和 Δ=0\Delta = 0 一模一样。RoPE 让各块的转速按几何级数从 1 降到约 1/10000:最快的一对每个位置转 1 弧度(周期 6.3 个位置),最慢的一对周期约 4.7 万个位置。就像时钟的秒针、分针、时针,合起来才能在很大的范围内唯一地表示位置。相似度随距离整体变小,RoFormer 论文称之为长程衰减:离得越远的 token,在不考虑内容时得到的分数越小。

4.6 高效实现

slides:“因为 RΘ,mR_{\Theta,m} 的块稀疏结构,可以更高效地计算它和任意向量 yy 的乘积”:

RΘ,m y=(y1y2y3y4⋮)⊙(cos⁡mθ1cos⁡mθ1cos⁡mθ2cos⁡mθ2⋮)+(−y2y1−y4y3⋮)⊙(sin⁡mθ1sin⁡mθ1sin⁡mθ2sin⁡mθ2⋮)R_{\Theta,m}\, y = \begin{pmatrix} y_1 \\ y_2 \\ y_3 \\ y_4 \\ \vdots \end{pmatrix} \odot \begin{pmatrix} \cos m\theta_1 \\ \cos m\theta_1 \\ \cos m\theta_2 \\ \cos m\theta_2 \\ \vdots \end{pmatrix} + \begin{pmatrix} -y_2 \\ y_1 \\ -y_4 \\ y_3 \\ \vdots \end{pmatrix} \odot \begin{pmatrix} \sin m\theta_1 \\ \sin m\theta_1 \\ \sin m\theta_2 \\ \sin m\theta_2 \\ \vdots \end{pmatrix}

矩阵版(一次处理所有位置):构造 N×dN \times d 的角度矩阵 CC(第 mm 行是 mθ1,…,mθd/2,mθ1,…,mθd/2m\theta_1, \dots, m\theta_{d/2}, m\theta_1, \dots, m\theta_{d/2}),则

Y~=g(Y;Θ)=[ Y:,1:d/2, Y:,d/2+1:d ]⊙cos⁡(C)+[ −Y:,d/2+1:d, Y:,1:d/2 ]⊙sin⁡(C)\tilde Y = g(Y; \Theta) = [\,Y_{:,1:d/2},\ Y_{:,d/2+1:d}\,] \odot \cos(C) + [\,-Y_{:,d/2+1:d},\ Y_{:,1:d/2}\,] \odot \sin(C)

(slides 对这一页的自评是”我也不确定它对不对,但这是我自己写的”。)注意矩阵版把第 ii 维和第 i+d/2i + d/2 维配成一对,而逐元素版把相邻两维配成一对——这正是 Llama / GPT-NeoX 的写法和 RoFormer 论文写法的区别。两者只是约定不同,重排维度后完全等价(02 第 1 部分),但加载预训练权重时必须用训练时的约定。

4.7 RoPE 与 KV 缓存

RoPE 按每个 token 自己的绝对位置旋转 kk,旋转后的 kk 存进缓存,以后再也不用改;新 token 来了只需按它自己的位置旋转它的 qq 和 kk。所以 RoPE 和 KV 缓存天然兼容(02 第 5 部分:逐个解码和整段前向差 1.7×10−161.7 \times 10^{-16})。RoPE 没有位置嵌入表,也就没有 max_len 这个硬上限;但模型只在训练长度内见过这些旋转角度——§7.3 会看到这一点的后果。


5. 分组查询注意力 GQA · Grouped-query attention

5.1 动机:KV 缓存

slides 的说法:Transformer 的计算和内存都很密集。第 3 讲 §4.5 看到,推理时每个序列都要为每一层保存所有 token 的 K 和 V,长上下文时缓存比模型还大;而且解码每一步都要把整个缓存从显存读一遍(前置讲 P3 §6.2–6.3:访存受限)。缓存的大小和 KV 头数成正比——能不能少用几个 KV 头?

5.2 定义

GQA(Ainslie et al., 2023)的关键想法:多个查询头共用同一组键头和值头。

K(i)=XWk(i),V(i)=XWv(i),i∈{1,…,hkv}Q(i,j)=XWq(i,j),i∈{1,…,hkv}, j∈{1,…,g}S(i,j)=Q(i,j)(K(i))⊤/dk,A(i,j)=softmax(S(i,j)),X~(i,j)=A(i,j)V(i)X~=concat(X~(i,j)),X′=X~Wo\begin{aligned} K^{(i)} &= XW_k^{(i)},\quad V^{(i)} = XW_v^{(i)}, && i \in \{1, \dots, h_{kv}\}\\ Q^{(i,j)} &= XW_q^{(i,j)}, && i \in \{1, \dots, h_{kv}\},\ j \in \{1, \dots, g\}\\ S^{(i,j)} &= Q^{(i,j)} (K^{(i)})^\top / \sqrt{d_k},\quad A^{(i,j)} = \mathrm{softmax}(S^{(i,j)}),\quad \tilde X^{(i,j)} = A^{(i,j)} V^{(i)}\\ \tilde X &= \mathrm{concat}(\tilde X^{(i,j)}),\qquad X' = \tilde X W_o \end{aligned}
  • hqh_q = 查询头数,hkvh_{kv} = 键/值头数,假设 hqh_q 能被 hkvh_{kv} 整除;g=hq/hkvg = h_q / h_{kv} 是每组的大小(每个 KV 向量配几个查询向量)。
  • slides:“参数矩阵的大小都一样,只是键/值参数矩阵(头)比查询的少。”
  • 两个极端:hkv=hqh_{kv} = h_q 就是普通的多头注意力(MHA);hkv=1h_{kv} = 1 就是多查询注意力(MQA,Shazeer, 2019)。

03_gqa.py 第 1 部分验证:GQA 和”把每个 K、V 头复制 gg 份的 MHA”输出逐位相同。注意力层的参数只省了一点(d=32d = 32、8 个查询头:MHA 4096 → MQA 2304)——GQA 真正省的是推理时的缓存。

5.3 省了多少:Llama-3 8B

Llama-3 8B:32 层、32 个查询头、每头 128 维、BF16 权重 15.0 GiB。03 第 2 部分算了批大小 32、每个序列 8192 个 token 时的情况(H100:80 GB、3.35 TB/s):

结构每个 token 的缓存整批的缓存权重 + 缓存放得进一块 H100?解码一步至少(只算读显存)每秒最多生成的 token
MHA(hkv=32h_{kv} = 32)512 KiB128.0 GiB不能45.8 ms698
GQA(hkv=8h_{kv} = 8,Llama-3 实际用的)128 KiB32.0 GiB能15.1 ms2,126
MQA(hkv=1h_{kv} = 1)16 KiB4.0 GiB能6.1 ms5,266

用 MHA 的话,这一批的缓存连同权重根本放不进一块 H100;GQA 把缓存缩小到 1/4,每一步也快了约 3 倍。MQA 还能再缩小 8 倍,但 Ainslie et al. (2023) 发现它的质量下降更明显、训练也更不稳定;GQA 是两者之间的折中。

5.4 质量与”改装”

03 第 3 部分在农场语言上训练了三个 ModernLM(4 个查询头,其余完全相同,5 个 epoch):

结构参数量每个 token 的 KV 缓存测试集困惑度
MHA(hkv=4h_{kv} = 4)107,8401024 B2.5255
GQA(hkv=2h_{kv} = 2)99,648512 B2.5262
MQA(hkv=1h_{kv} = 1)95,552256 B2.5290

在这个简单任务上,代价几乎可以忽略。

**已经训练好的 MHA 模型能直接改成 GQA 吗?**Ainslie et al. (2023) 的做法(uptraining):把每组 K 头(V 同理)的投影矩阵取平均作为新的 K 头,再用原预训练计算量的一小部分继续训练。我们的结果:

模型测试集困惑度
原来的 MHA2.5255
按组取平均,不继续训练4.0066
再继续训练 1 个 epoch(原训练量的 1/5,学习率 3e-4)2.5017
原来的 MHA 也继续训练 1 个 epoch(公平的对照)2.5010

直接取平均损失很大(原来每个 K 头学到的东西不同),继续训练一小段就恢复了。2.5017 看起来比原来的 MHA 还好,但那是因为它多训练了一个 epoch、而且最后用了更小的学习率(相当于学习率退火);公平的对照(MHA 也多训练一个 epoch)是 2.5010,两者相当。这让已有的 MHA 模型也能享受 GQA 的推理效率。


6. 滑动窗口注意力 · Sliding window attention

6.1 动机与定义

slides:也叫局部注意力,在 Longformer(Beltagy et al., 2020)里提出。问题:普通注意力计算量大、需要很多内存(T×TT \times T 的分数矩阵)。解决办法:用一个因果掩码,只看一个窗口内的 token——窗口里有 12w+1\frac12 w + 1 个 token,最右边的元素是当前 token(对角线上):

X′=softmax ⁣(QK⊤dk+M)V,Mt,j={0t−w2≤j≤t−∞其他X' = \mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}} + M\right) V,\qquad M_{t,j} = \begin{cases} 0 & t - \frac{w}{2} \le j \le t \\ -\infty & \text{其他} \end{cases}

04_sliding_window.py 第 1 部分画出了 slides 里 w=4w = 4(每个 token 看 3 个)和 w=6w = 6(看 4 个)的掩码:每一行只剩对角线及其左边几个位置。(slides 的 ww 是 Longformer 的双向窗口宽度;代码和 Mistral 一样直接用”能看的 token 数” WW 作参数。)

6.2 三种实现

slides 列出了三种实现方式:

  1. 朴素实现:照常做矩阵乘法、再加掩码——但这样仍然很慢;
  2. for 循环实现:渐近更快、更省内存,但在 PyTorch 里因为 for 循环太慢而无法实用;
  3. 滑动分块(sliding chunks):把 QQ 和 KK 切成 w×ww \times w 的块,块之间重叠 12w\frac12 w;在每个块内计算完整的注意力再加掩码(实践中又快又省内存)。

04 第 2 部分实现了三种,结果相同(差 4.4×10−164.4 \times 10^{-16})。分块的做法:把序列切成长度为 WW 的块,第 bb 块的查询只需要看第 b−1b-1 块和第 bb 块的键,每块算一个 W×2WW \times 2W 的小矩阵,全部块一次批量算完。⏱ 本机单线程(W=64W = 64,d=64d = 64):

TT朴素:分数矩阵元素数分块:分数矩阵元素数⏱ 朴素⏱ 分块⏱ for 循环
25665,53632,7680.2 ms0.1 ms2 ms
1,0241,048,576131,0723.0 ms0.3 ms7 ms
4,09616,777,216524,28846.2 ms1.2 ms(太慢,跳过)

朴素实现省了”看太远”,没省计算;for 循环只算需要的分数,但每个查询一次小运算,开销太大(在 GPU 上会更糟);分块的计算量和内存都是 O(TW)O(TW),又能批量执行,TT 越大优势越明显。

6.3 多层叠加:感受野

每个 token 只看最近 WW 个,模型还能用到更远的信息吗?能——间接地。04 第 3 部分(W=4W = 4)改动第 1 个 token,看第 LL 层的输出最远影响到哪里:

层数 LL1234
最远受影响的距离36912

正好是 L(W−1)L(W-1):每一层把信息往右传 W−1W - 1 个位置(和第 5 讲 CNN 的感受野随层数增长是同一个道理)。Mistral 7B 用 W=4096W = 4096、32 层,理论感受野约 13 万个 token。但”间接依赖”不等于”能用好”——信息要经过很多次接力。

6.4 滚动缓存

slides 在 Mistral 那一条里提到:滚动缓冲区缓存(rolling buffer cache)——缓存长到窗口大小后,把位置 ii 写到第 i mod Wi \bmod W 格,覆盖掉最旧的。窗口之外的 K、V 永远不会再被看到,扔掉也不影响结果:缓存大小从”随长度线性增长”变成固定的 WW(练习 3)。

04 第 4 部分验证:生成 40 个 token、每一步之后缓存只保留最近 W−1=5W - 1 = 5 个位置,结果和整段前向一致(差 1.7×10−161.7 \times 10^{-16})。能这样做的前提是 RoPE:缓存里的 K 已经按自己的绝对位置旋转过,放在缓冲区哪一格都没关系。但新 token 必须按它真正的绝对位置旋转,而不是按缓存的长度——缓存截短以后两者不再相等。代码的第一版就在这里出了错(差 6.9×10−46.9 \times 10^{-4}),修正后才逐位一致。

6.5 窗口太小会怎样

04 第 5 部分在农场语言上训练了不同窗口的 ModernLM(2 层)。主谓一致测试里,预测动词的位置离主语 3k3k 个 token:

窗口 WW2 层的理论感受野测试集困惑度k=1k=1(距离 3)k=2k=2(距离 6)k=3k=3(距离 9)
不限全部2.52551.0001.0001.000
8142.53171.0001.0001.000
462.68591.0000.9900.000
222.90470.5600.4950.485

窗口 4 时,距离 9 的主语超出了感受野,一致性掉到 0——模型只能跟着最近的名词走;窗口 2 时连距离 3 都够不着。滑动窗口是一种取舍:把注意力的代价从 O(T2)O(T^2) 降到 O(TW)O(TW),代价是放弃了”任意两个位置直接相连”(第 2 讲 §5 的长度为 1 的通路)。所以 Gemma 2/3、OLMo 3、gpt-oss 等把滑动窗口层和全局注意力层交替使用。


7. 拼起来:现代 TransformerLM · Putting it together

7.1 现代配方 vs GPT 配方

modern_lm.ModernLM 就是原课 HW1 要实现的”带 GQA 和 RoPE 的 TransformerLM”:

部件第 2 讲的 GPT(GPT-2 式)现代开源模型(Llama 式)
归一化LayerNorm(γ\gamma、β\beta)RMSNorm(只有 γ\gamma)
归一化的位置GPT-1 post-norm;GPT-2 起 pre-normpre-norm(Gemma 2、OLMo 2 还在子层输出上再归一化一次)
前馈网络GELU,2 个矩阵,dff=4dd_\text{ff} = 4dSwiGLU,3 个矩阵,dff≈8d/3d_\text{ff} \approx 8d/3
位置编码可学习的绝对位置嵌入(加在输入上)RoPE(每层旋转 qq、kk)
注意力MHAGQA 或 MQA
线性层偏置有无
接口logits, None = model(ids)logits, cache = model(ids, cache)

05_modern_transformer.py 第 1 部分用 前置讲 P1 的 param_count 公式核对:ModernLM(d=64d = 64、2 层、4 个查询头、2 个 KV 头)PyTorch 数出 99,648,公式也是 99,648。Llama-3 8B 的 8.03B 参数里,前馈网络占 70.2%,注意力只占 16.7%(GQA 让 WkW_k、WvW_v 只有 WqW_q 的 1/4),128K 的词表让嵌入层和输出层合起来占约 13%。

7.2 和第 2 讲的 GPT 比

都是 d=64d = 64、2 层、4 个查询头,训练 5 个 epoch:GPT 111,360 个参数、测试困惑度 2.5305;ModernLM 99,648 个参数、2.5262。参数更少、困惑度相当。在这么小的玩具模型上,现代配方的优势很有限;它们的价值主要体现在大模型上的训练稳定性、推理效率(GQA)和长上下文。

7.3 一个意外:RoPE 外推得最差

第 2 讲 §6.5 发现:超出训练长度时(主谓一致的 k≥4k \ge 4),可学习位置嵌入和正弦编码不稳,不加位置编码反而最好。我原本预期 RoPE 会表现得像”不加位置编码”一样好——它只编码相对位置,没有”没训练过的位置向量”。05 第 3 部分(ModernLM,只换位置编码,3 个种子):

位置编码种子测试困惑度k=4k=4k=5k=5k=6k=6k=7k=7k=8k=8
RoPE02.52620.6500.2050.0000.0000.000
RoPE12.52200.9950.9250.4500.4150.295
RoPE22.52100.3050.2250.0000.8350.945
可学习02.52491.0000.9900.9550.9000.715
可学习12.51791.0001.0000.7500.7850.770
可学习22.51891.0001.0000.9950.9750.815
不加02.52850.9951.0001.0000.9800.990
不加12.52751.0001.0001.0001.0001.000
不加22.52041.0001.0001.0001.0001.000

RoPE 反而最差(3 个种子里最低 0.000;可学习 0.715;不加 0.980)。诊断:在预测动词的位置,所有头里分给主语的最大注意力权重(种子 0):

位置编码k=3k = 3(训练见过)k=6k = 6(没见过)
RoPE0.9970.061
可学习0.9260.466
不加0.9510.949

原因在于这门语言的结构:主语永远是第 3 个 token(“<s> the 主语”)。可学习的绝对位置嵌入可以直接学会”去看下标 2”,这条规则对任何长度都成立(虽然它只部分做到了);不加位置编码的模型也能借助因果掩码认出句首。RoPE 只告诉模型相对距离,“主语”对它来说是”往回 3k3k 个位置”,k≥4k \ge 4 时这个距离(12–24)在训练中从未在主语和动词之间出现过。

所以相对位置编码并非处处更好:它擅长”相对位置固定”的依赖(自然语言里大量的局部搭配),而对”锚定在绝对位置上”的信息反而要外推。现代模型选 RoPE,是因为真实文本里前者占多数,而且它和 KV 缓存、长上下文扩展(第 19 讲)配合得好。这个玩具实验也再次说明:超出训练分布的行为,必须用多个种子、配合诊断来看。


8. 小结 · Summary

  1. 预训练:在大量(通常无标注的)数据上训练;微调:用预训练的参数初始化,加一个小的预测头,在少量标注数据上训练。2006 年的逐层无监督预训练(自编码器)点燃了深度学习;今天的 LLM 用生成式预训练,流程是预训练 → 中期训练 → 后训练。实验中,预训练模型用 16 个标注样本就能做到从零训练用 256 个都做不到的事;但小数据上的全量微调可能破坏预训练的表示,只训练分类头反而最稳。
  2. 现代开源 Transformer 的常见改动:pre-norm 的 RMSNorm、SwiGLU、去掉偏置、RoPE、GQA/MQA、滑动窗口(常与全局注意力交替)。
  3. RoPE:把 qq、kk 切成二维小块,按各自的绝对位置 mm 旋转 mθim\theta_i;Rj⊤Rt=Rt−jR_j^\top R_t = R_{t-j} 让分数只依赖相对距离。旋转保持长度;不同频率避免混叠;块对角结构让它只需 O(d)O(d) 运算;和 KV 缓存天然兼容。两边都转 t−jt - j 的”错误版”会让位置信息完全抵消。
  4. GQA:gg 个查询头共用一组 K、V 头;MHA、MQA 是两个极端。它几乎不省参数,但把 KV 缓存和解码带宽缩小 hq/hkvh_q/h_{kv} 倍;已有的 MHA 模型可以按组取平均后少量继续训练来改装。
  5. 滑动窗口注意力:每个 token 只看最近 WW 个;分块实现把计算和内存降到 O(TW)O(TW);LL 层的感受野是 L(W−1)L(W-1);配合 RoPE 可以用固定大小的滚动缓存。窗口太小会切断长程依赖。
  6. 相对位置编码不是在所有任务上都更好:在我们的玩具语言里,主语锚定在绝对位置上,RoPE 外推得最差。

9. 常见误区 · Common pitfalls

  1. “微调就是把所有参数都再训练一遍,越多越好。” 标注数据很少时,全量微调可能过拟合、破坏预训练的表示;线性探针或参数高效微调可能更好(§2.8)。
  2. “RoPE 是把位置向量加到输入上。” RoPE 不加任何东西,它在每一层旋转 qq 和 kk;vv 不旋转。
  3. “RoPE 用相对位置旋转。” 每个向量按自己的绝对位置旋转;相对位置是在点积里出现的。两边都按 t−jt - j 旋转会让位置信息完全消失(§4.3)。
  4. “RoPE 的两种实现(相邻配对 / 前后两半配对)不一样。” 数学上等价;但加载权重时必须用训练时的那一种。
  5. “GQA 主要是为了省参数。” 它省的主要是推理时的 KV 缓存和显存带宽;参数只少了一点。
  6. “MQA 最省,所以最好。” MQA 的质量下降和训练不稳定更明显;GQA 是折中。
  7. “滑动窗口注意力的朴素实现能省计算。” 先算完整矩阵再加掩码,计算量还是 O(T2)O(T^2);要用分块实现。
  8. “滑动窗口让模型看不到窗口之外的信息。” 多层叠加后感受野是 L(W−1)L(W-1),但信息要经过多次接力,越远越弱(§6.5 的窗口 4 在距离 9 处失败)。
  9. “滚动缓存截短后,新 token 的位置就是缓存的长度。” 必须按它真正的绝对位置旋转(§6.4)。
  10. “相对位置编码一定外推得更好。” 取决于任务需要的是哪种位置信息(§7.3)。

10. 练习 · Exercises

练习 1(手算 RoPE)。 d=2d = 2,只有一个频率 θ=1\theta = 1。q=k=[1,0]q = k = [1, 0]。(a) 查询在位置 t=1t = 1、键在位置 j=0j = 0 时,旋转后的点积是多少?(b) 换成 t=5t = 5、j=4j = 4 呢?(c) 用 Rj⊤Rt=Rt−jR_j^\top R_t = R_{t-j} 解释。

参考答案

(a) q~1=[cos⁡1,sin⁡1]\tilde q_1 = [\cos 1, \sin 1],k~0=[1,0]\tilde k_0 = [1, 0],点积 =cos⁡1=0.5403= \cos 1 = 0.5403。(b) q~5=[cos⁡5,sin⁡5]\tilde q_5 = [\cos 5, \sin 5],k~4=[cos⁡4,sin⁡4]\tilde k_4 = [\cos 4, \sin 4],点积 =cos⁡5cos⁡4+sin⁡5sin⁡4=cos⁡(5−4)=0.5403= \cos 5 \cos 4 + \sin 5 \sin 4 = \cos(5 - 4) = 0.5403,相同。(c) k~j⊤q~t=k⊤Rj⊤Rtq=k⊤Rt−jq\tilde k_j^\top \tilde q_t = k^\top R_j^\top R_t q = k^\top R_{t-j} q,只依赖 t−j=1t - j = 1。

练习 2(RoPE 的转速范围)。 d=128d = 128、base = 10000 时,最快和最慢的一对每个位置转多少弧度?周期各是多少个位置?Llama 3 把 base 改成 500,000,最慢的那对周期变成多少?为什么长上下文模型要把 base 调大?

参考答案

θ1=1\theta_1 = 1(周期 2π≈6.32\pi \approx 6.3);θ64=10000−126/128=1.15×10−4\theta_{64} = 10000^{-126/128} = 1.15 \times 10^{-4},周期约 54,410 个位置。base = 500,000 时 θ64=2.46×10−6\theta_{64} = 2.46 \times 10^{-6},周期约 256 万个位置。上下文变长后,需要有足够慢的”指针”在整个上下文范围内都不转完一圈,否则远处的位置会和近处的混叠;调大 base 让所有频率都变慢(第 19 讲)。

练习 3(Mistral 的缓存)。 Mistral 7B:32 层、8 个 KV 头、每头 128 维、BF16、滑动窗口 4096。(a) 每个 token 的 KV 缓存多大?(b) 用滚动缓存时,一个序列的缓存最多多大?(c) 如果不用滚动缓存,32K 个 token 的序列要多大?

参考答案

(a) 2×32×8×128×2=131,0722 \times 32 \times 8 \times 128 \times 2 = 131{,}072 字节 = 128 KiB。(b) 最多保留 4096 个位置:512 MiB,和序列多长无关。(c) 32,768 × 128 KiB = 4 GiB。

练习 4(GQA 的参数)。 d=4096d = 4096、32 个查询头、每头 128 维。分别求 MHA(32 个 KV 头)和 GQA(8 个 KV 头)的注意力层参数量(不计偏置)。

参考答案

MHA:Wq,Wk,Wv,WoW_q, W_k, W_v, W_o 都是 4096×40964096 \times 4096,共 4×16.8M=67.14 \times 16.8\text{M} = 67.1M。GQA:WqW_q、WoW_o 仍是 4096×40964096 \times 4096,WkW_k、WvW_v 是 4096×10244096 \times 1024,共 2×16.8M+2×4.2M=41.92 \times 16.8\text{M} + 2 \times 4.2\text{M} = 41.9M。少了约 38%——但在整个模型里(前馈网络占大头),这个差别不大。

练习 5(滑动窗口省了多少)。 T=32,768T = 32{,}768、W=4096W = 4096。(a) 普通因果注意力”有用”的分数占 T2T^2 的多少?(b) 滑动窗口实际需要的分数占多少?(c) §6.2 的分块实现计算 2TW2TW 个分数,占多少?

参考答案

(a) T(T+1)/2÷T2≈50%T(T+1)/2 \div T^2 \approx 50\%。(b) 每个查询最多看 WW 个,前 W−1W-1 个查询看得更少:(TW−W(W−1)/2)/T2≈11.7%(TW - W(W-1)/2)/T^2 \approx 11.7\%。(c) 2TW/T2=2W/T=25%2TW/T^2 = 2W/T = 25\%——比需要的多算了一倍(块内有一半被掩码屏蔽),但和 100% 相比已经省了很多,而且全是规整的矩阵乘法。

练习 6(感受野)。 Mistral 7B 有 32 层、窗口 4096。按 §6.3 的公式,最后一层理论上能间接依赖多远的 token?一个 2 层、窗口 4 的模型呢?

参考答案

L(W−1)=32×4095=131,040L(W-1) = 32 \times 4095 = 131{,}040,约 13 万(Mistral 论文的说法是”约 131K”)。2 层、窗口 4:2×3=62 \times 3 = 6——这就是 §6.5 里距离 9 的主语够不着的原因。

练习 7(“错误版”的 RoPE)。 证明:如果查询和键都乘以同一个旋转矩阵 RR,点积不变。这对 slides 上那一版公式意味着什么?

参考答案

(Rk)⊤(Rq)=k⊤R⊤Rq=k⊤q(Rk)^\top (Rq) = k^\top R^\top R q = k^\top q,因为旋转矩阵是正交矩阵,R⊤R=IR^\top R = I。slides 那一版让 qtq_t 和 kjk_j 都旋转 Rt−jR_{t-j},于是分数和完全不加位置信息时一模一样(§4.3 的实验:差 10−1510^{-15} 量级)。

练习 8(SwiGLU 的中间维度)。 GELU 前馈网络有 2 个 d×4dd \times 4d 的矩阵,SwiGLU 有 3 个 d×dffd \times d_\text{ff} 的矩阵。要让两者参数量相同,dffd_\text{ff} 应该是多少?d=4096d = 4096 时,向上取到 256 的倍数是多少?

参考答案

3d⋅dff=2⋅d⋅4d⇒dff=8d/33 d \cdot d_\text{ff} = 2 \cdot d \cdot 4d \Rightarrow d_\text{ff} = 8d/3。d=4096d = 4096 时 8×4096/3=10922.78 \times 4096/3 = 10922.7,向上取到 256 的倍数是 11,008——正是 Llama 2 7B 的中间维度。(Llama 3 8B 用的是 14,336,比这个更大。)

练习 9(RMSNorm vs LayerNorm)。 不带缩放参数,求 x=[1,2,3,4]x = [1, 2, 3, 4] 的 RMSNorm 和 LayerNorm。

参考答案

RMSNorm:rms=(1+4+9+16)/4=7.5=2.7386\mathrm{rms} = \sqrt{(1 + 4 + 9 + 16)/4} = \sqrt{7.5} = 2.7386,输出 [0.365,0.730,1.095,1.461][0.365, 0.730, 1.095, 1.461]——只缩放,不改变均值(输出仍然全是正数)。LayerNorm:先减去均值 2.5 再除以标准差 1.118,输出 [−1.342,−0.447,0.447,1.342][-1.342, -0.447, 0.447, 1.342](第 2 讲练习 5)。

练习 10(为什么线性探针更好)。 §2.8 里,16 个样本时线性探针 1.000、全量微调 0.910。用”可训练参数的个数”和”样本数”解释;如果把样本数加到 256,你预计两者的差距会怎样?实测呢?

参考答案

线性探针只训练 64×2+2=13064 \times 2 + 2 = 130 个参数,16 个样本足以确定;需要的信息(主语的单复数)已经在冻结的表示里。全量微调要更新约 11 万个参数,16 个样本远不足以约束它们,模型可以用很多”捷径”拟合训练集、同时破坏原有的表示。样本增加后两者的 k = 1–3 准确率都是 1.000,但外推(k = 4–6)上全量微调仍然更差(0.932 vs 1.000):微调后的模型更依赖训练分布里的细节。


11. 延伸阅读 · Further reading

  • 预训练的起点:Hinton & Salakhutdinov (2006), Reducing the Dimensionality of Data with Neural Networks;Bengio et al. (2006), Greedy Layer-Wise Training of Deep Networks;Erhan et al. (2010), Why Does Unsupervised Pre-training Help Deep Learning?。
  • 数据与流程:Gao et al. (2020), The Pile;Soldaini et al. (2024), Dolma;OLMo 2 技术报告(OLMo et al., 2024)中关于中期训练(Dolmino)的部分。
  • RoPE:Su et al. (2021), RoFormer;EleutherAI 的博客 Rotary Embeddings: A Relative Revolution。
  • GQA / MQA:Shazeer (2019), Fast Transformer Decoding: One Write-Head is All You Need;Ainslie et al. (2023)。
  • 滑动窗口:Beltagy et al. (2020), Longformer;Jiang et al. (2023), Mistral 7B;Child et al. (2019), Sparse Transformers。
  • 其他现代改动:Zhang & Sennrich (2019), Root Mean Square Layer Normalization;Shazeer (2020), GLU Variants Improve Transformer;Touvron et al. (2023), LLaMA。
  • 位置编码与外推:Press et al. (2022), ALiBi;Kazemnejad et al. (2023),第 2 讲已引用。

12. 下一讲预告 · Next lecture

第 5 讲进入图像。我们会:

  • 从零实现卷积层(填充、步长、多通道、反向传播、池化),理解 CNN 的归纳偏置;回顾 LeNet → AlexNet → VGG → ResNet;
  • 看计算机视觉的任务谱系(分类、检测、分割、生成……);
  • 认识仅编码器的 Transformer:去掉因果掩码的 BERT,以及它的掩码语言模型预训练;
  • 把图像切成小块,当成 token 喂给 Transformer——ViT;并用一个自己生成的”形状世界”数据集比较 MLP、CNN、ViT 的归纳偏置和数据需求。
← 返回课程目录