对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Spring 2026;Aran Nayebi、Matt Gormley),Lecture 11 · Wed 18-Feb · In-Context Learning / Prompt Engineering / Instruction Fine-tuning / RLHF(slides:lecture11-ift-rlhf;slides 注明部分取自 Pat Virtue、Henry Chai)。 阅读材料:Brown et al. (2020), Language Models are Few-Shot Learners(GPT-3);Min et al. (2022), Rethinking the Role of Demonstrations;Wei et al. (2022), Chain-of-Thought Prompting;Wei et al. (2021), Finetuned Language Models Are Zero-Shot Learners(Flan);Ouyang et al. (2022), Training language models to follow instructions with human feedback(InstructGPT);Bai et al. (2022), Training a Helpful and Harmless Assistant with RLHF。 依据说明:本讲按原课第 11 讲公开的 slides 展开:少样本场景下的两条路;GPT-3 的少样本上下文学习;上下文学习对顺序、标签平衡、标签覆盖的敏感性;Min et al. 的”正确标签和更多例子不一定重要”;提示工程(OPT-175B 在 AG News 上的提示差异、按困惑度挑提示);思维链提示(Wei et al.、Kojima et al.);聊天模型的提示模板、基座模型和聊天模型的区别;指令微调的动机和名字;指令数据从哪里来(InstructGPT、Dolly、Flan、MultiInstruct);RLHF 的三步、奖励模型及其损失、Anthropic 的标注界面与结果;把 LLM 微调写成强化学习问题、RLHF 的目标函数(“下一讲细讲”)。论文里的数字写成”某某报告”。所有实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:
code/lecture11/(6 个脚本 + 2 个模块;01第一次约 8 分钟(训练并缓存两个模型),之后的02–06都在 3 分钟以内) 预计阅读时间:4 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说清上下文学习(ICL)是什么、它和微调的区别;解释”为什么训练数据要有某种结构,上下文学习才会出现”。
- 用贝叶斯推断的语言描述上下文学习:例子在帮模型排除哪些”任务假设”。
- 说出上下文学习对哪些因素敏感(顺序、标签覆盖),以及”随机标签几乎不影响结果”在什么条件下成立。
- 解释提示工程的两个经验:提示的写法影响结果;挑困惑度最低的提示。说出思维链为什么能帮忙(以及它的推理过程不一定”忠实”)。
- 描述指令微调:数据格式(对话模板)、只在回答上算损失、多种说法(模板)的作用、它和预训练的分工。
- 写出 RLHF 的三步和奖励模型的损失函数;说明为什么要用”排序”而不是”打分”或”示范”,以及奖励模型可能在哪里出错。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲只给直觉,后面再展开 Previewed only |
|---|---|
| 第 3 讲:语言模型的训练与解码 | RLHF 的第 3 步:REINFORCE、PPO(第 12 讲) |
| 第 4 讲:预训练 + 微调;第 9 讲 §10:零样本与少样本 | DPO:跳过奖励模型(第 12 讲) |
| 第 10 讲:全量微调和 LoRA | 推理模型、长思维链(第 20 讲) |
| 前置讲 P2:贝叶斯公式、后验 | 多样本上下文学习(第 19 讲) |
0.3 本讲地图 Map
§1 上下文学习:它是什么、它为什么会出现 ← 代码 01
§2 上下文学习对什么敏感 ← 代码 02
§3 提示工程;上下文学习 vs 微调 ← 代码 03
§4 思维链 ← 代码 04
§5 指令微调 ← 代码 05
§6 RLHF(上):偏好数据与奖励模型;把微调写成强化学习 ← 代码 06
§7–11 小结、误区、练习、延伸阅读、下一讲
本讲的代码用了两个小世界:
- ICL 世界(
icl_lab.py):16 个”物品”= 4 种颜色 × 4 种形状(红圆、蓝方……),一段序列是一串”物品 → 标签”的例子,整段共用同一个任务。任务先选一个特征(颜色或形状),再选标签的写法:自然标签(标签就是特征的名字,红 / 圆……——“模型早就认识的任务”)或符号标签(A / B / C / D,特征值到符号的对应每段随机重排——“全新的任务”,只能从这一段的例子里推断)。任务一共只有 50 种,所以能精确算出贝叶斯最优的预测。 - 农场聊天世界(
chat_lab.py):把农场语言做成一个指令数据集——9 种任务(找主语、改复数、去掉修饰、描述某个动物……),每种 6 种说法;用于指令微调和奖励模型,第 12 讲的 RLHF / DPO 也用它。
1. 上下文学习 · In-context learning
1.1 两条路
slides 第 10、11 讲都从同一张表开始:你有一个很小的数据集 和一个很大的预训练语言模型。
- A. 监督微调(SFT):用标准监督目标和反向传播更新参数。缺点:反向传播约 3 倍于前向的显存和计算;可能拿不到权重。(第 10 讲)
- B. 上下文学习(ICL):把训练样本写进提示,让模型在推理时从中找规律,取它接下来写出的内容当预测。优点:不需要反向传播,每个例子只”过”一遍;有 API 就行。缺点:提示可能很长,Transformer 处理长度为 N 的上下文要 的时间和空间。
GPT-3 论文(Brown et al., 2020)的少样本格式:先写一句任务描述,再按顺序列出几个训练集里的”输入 → 输出”对,最后写上要预测的输入:
Translate English to French: ← 任务描述
sea otter => loutre de mer ← 例子
peppermint => menthe poivrée
cheese => ← 提示(模型接着写)
零样本(zero-shot)只有任务描述,单样本(one-shot)给一个例子,少样本(few-shot)给几个。全程不更新任何参数。
1.2 它为什么会出现?
第 9 讲我们试过:农场语言的小 GPT 怎么提示都没有上下文学习。为什么 GPT-3 有、它没有?
一个解释(Xie et al., 2022;Chan et al., 2022):只有当训练数据里同一段上下文共享某个隐藏的”任务”或”主题”,而且这个任务只能从上下文里推断出来时,“从前文推断任务、再用它预测后文”才是降低损失的好办法。网页文本就是这样——一篇文章的前半部分告诉你它在讲什么、用什么风格,后半部分的词就更好预测。农场语料的句子彼此独立,前一句完全不提供后一句的任何信息,模型没有理由学会”看前文”。
为了检验这个解释,我们造了 ICL 世界(§0.3),训练一个 4 层、d = 128 的 GPT:每步 64 段新序列,80% 是符号任务、20% 是自然任务。一段训练序列长这样:
<s> 什么色 蓝十 蓝 黄十 黄 红角 红 红圆 红 …… 自然标签·颜色(开头带一个任务说明)
<s> 黄圆 D 绿圆 B 绿十 B 绿圆 B 黄圆 D 红圆 A …… 符号标签·颜色(红=A、绿=B、黄=D……)
贝叶斯最优是什么样的? 符号任务有 2(特征)× 24(排列)= 48 种可能,看到的每个例子都会排除一批(代码 01 第 1 部分,真实任务是”颜色,红 = B、绿 = A、蓝 = C、黄 = D”,查询物品是黄圆):
| 已经看到的例子 | 还对得上的任务(共 50 个) | P(黄圆 的标签 | 例子) |
|---|---|---|
| (还没有例子) | 50 | D、C、B、A 各 0.22(还有 0.12 在自然标签上) |
| 红圆→B | 12 | B 0.50,其余各 0.17 |
| 红圆→B 蓝方→C | 4 | B 0.50,D 0.25,A 0.25 |
| 红圆→B 蓝方→C 红角→B | 2 | D 0.50,A 0.50 |
| 红圆→B 蓝方→C 红角→B 黄十→D | 1 | D 1.00 |
第 3 个例子之后只剩两种可能——“红圆和红角都是 B”说明任务看的是颜色;第 4 个例子告诉我们黄 = D。上下文学习在做的,就是这种”用例子排除假设”的推理。
1.3 它是突然出现的
代码 01 第 2 部分记录了训练过程中两类符号题的准确率(8 个例子;“可照抄”= 查询物品本身在例子里出现过;“要推断”= 物品没出现过,但同颜色或同形状的出现过):
| 训练步数 | 自然标签(1 个例子) | 符号·可照抄 | 符号·要推断 |
|---|---|---|---|
| 400 | 1.00 | 0.27 | 0.24 |
| 2800 | 1.00 | 0.24 | 0.27 |
| 3200 | 1.00 | 0.82 | 0.48 |
| 3600 | 1.00 | 1.00 | 0.85 |
| 4000 | 1.00 | 1.00 | 0.92 |
| 10000 | 1.00 | 1.00 | 0.99 |
- 自然标签的任务一开始就学会了(模型”认识”颜色和形状)。
- 符号任务在前 2800 步一直在瞎猜(4 选 1 是 0.25),然后几百步之内就学会了;照抄比推断先学会一点。
- 这种”长长的平台之后突然出现”和 Olsson et al. (2022) 在真实 Transformer 上观察到的归纳头(induction head)相变很像:归纳头做的正是”找到前面出现过的同一个词,把它后面那个词抄过来”——照抄题正需要它。
我们的另一次训练(训练目标稍有不同,见 README)在约 3200–5600 步之间有一个准确率 0.35–0.55 左右的中间平台,到 6000 步才跳上去。相变出现在哪一步、中间有没有平台,取决于很多细节;“突然出现”这一点两次都一样。
1.4 学会以后:几乎就是贝叶斯推理
代码 01 第 3 部分(每格 1000 道题):
| 任务 | k | 模型准确率 | 贝叶斯(期望) | KL(贝叶斯 ‖ 模型) |
|---|---|---|---|---|
| 符号标签 | 1 | 0.434 | 0.435 | 0.010 |
| 符号标签 | 2 | 0.588 | 0.586 | 0.041 |
| 符号标签 | 4 | 0.836 | 0.876 | 0.106 |
| 符号标签 | 8 | 0.988 | 0.995 | 0.011 |
| 自然标签 | 1 | 1.000 | 1.000 | 0.000 |
| 自然标签 + 说明(零样本) | 0 | 1.000 | 1.000 | 0.000 |
“贝叶斯(期望)“是完美推理者的期望准确率(平均的 )。模型的预测分布和贝叶斯后验的 KL 只有 0.01–0.1 nats——一个训练了几分钟的小 Transformer,在”推断任务”这件事上已经很接近完美推理者。这就是”上下文学习 ≈ 隐式的贝叶斯推断”(Xie et al., 2022)的含义:预训练让模型学会了”什么样的任务是可能的”(先验),提示里的例子让它算出”现在是哪个任务”(后验)。
不只是照抄(第 4 部分,4 个例子):查询物品本身出现过时 1.000;物品没出现过、但同颜色(或同形状)的出现过时 0.921(贝叶斯 0.957)——模型要先推断”这个任务看的是颜色还是形状”,再找对应的例子;连取值都没出现过时,只能在没用过的符号里猜(0.641,贝叶斯 0.711)。
对照(第 5 部分):同样的模型,训练数据里每个例子各自一个任务(前面的例子对后面毫无帮助)。符号任务 8 个例子时只有 0.267、2 个例子时 0.271——和瞎猜一样;它的损失从第 1200 步起就不再下降。它没有任何理由学会看前文。第 9 讲农场 GPT 的训练数据就是这样:每句话彼此独立——所以它没有上下文学习。
2. 上下文学习对什么敏感 · What ICL is sensitive to
slides 列了几个来自真实大模型的发现。我们在 ICL 世界里一一检验——好处是有贝叶斯最优可以对照,能分清”完美推理者也会这样”和”模型自己的毛病”。
2.1 例子的顺序
slides(Lu et al., 2022):上下文学习对例子的顺序敏感。代码 02 第 1 部分:200 组例子(符号任务,每组 4 个),每组试遍 24 种排列:
| 任务 | 平均准确率 | 每组都挑最差的排列 | 每组都挑最好的排列 | 答案随排列改变的组 |
|---|---|---|---|---|
| 符号标签 | 0.877 | 0.840 | 0.915 | 7.5% |
| 自然标签 | 1.000 | 1.000 | 1.000 | 0% |
贝叶斯最优只看”有哪些例子”,不看顺序。所以顺序敏感是模型自己的毛病——它不是一个完美的推理者,不同的排列让它走了不同的”近似”。真实大模型上这个问题严重得多:Lu et al. 报告同一组例子换个顺序,准确率可以从接近瞎猜到接近最好。
2.2 标签平衡、覆盖了几种标签
slides:上下文学习对标签是否平衡(比如正例和负例各多少)、例子覆盖了几种标签敏感。代码 02 第 2 部分(符号任务,4 个例子):
| 例子 | 标签见过:模型 / 贝叶斯 | 标签没见过:模型 / 贝叶斯 | 没见过时放在”已出现标签”上的概率 |
|---|---|---|---|
| 覆盖 1 种(4 个例子同一个标签) | 0.988 / 0.992 | 0.343 / 0.334 | 0.5% |
| 覆盖 2 种(2:2) | 0.973 / 0.983 | 0.502 / 0.500 | 3.4% |
| 覆盖 2 种(3:1) | 0.987 / 0.984 | 0.491 / 0.500 | 5.9% |
| 覆盖 3 种 | 0.949 / 0.959 | 0.826 / 0.981 | 17.0% |
| 覆盖 4 种 | 0.916 / 0.961 | — | — |
“标签没见过”= 查询物品的相关特征取值不在例子里。符号任务是一一对应的,所以正确答案一定是例子里没出现过的符号——贝叶斯放在”已出现标签”上的概率是 0。
- 覆盖得越少,“标签没见过”的题越难:覆盖 1 种时只能在剩下 3 个符号里猜(贝叶斯 0.334),覆盖 3 种时只剩 1 个(贝叶斯 0.981)。这一点完美推理者也一样——不是模型的毛病,而是例子没提供信息。slides 说”覆盖了几种标签”很重要,原因就在这里。
- 模型的毛病:例子覆盖的标签越多,它越容易把”没见过”的查询错配到已经出现的标签上(17%),覆盖 3 种时准确率 0.826,比贝叶斯低 0.155。
- 标签不平衡:3:1 的例子里,模型放在多数标签上的概率只有 1.4%——几乎没有”多数标签偏好”。slides 说真实大模型对标签平衡很敏感(Zhao et al., 2021 称之为 majority label bias);我们的模型在训练时见过大量随机的符号任务,学到的是相当精确的推断,这种偏差就小得多。
2.3 正确的标签和更多的例子,不一定重要
slides(Min et al., 2022):“你以为这两件事很重要——A. 例子的标签是不是正确的(而不是随机的);B. 例子越多越好——但并不总是这样。” Min et al. 发现,把例子的标签换成随机标签,很多任务的效果只掉一点点。
代码 02 第 3、4 部分:
| k | 任务 | 例子的标签 | 查询的准确率 |
|---|---|---|---|
| 4 | 自然标签 | 正确标签 | 1.000 |
| 4 | 自然标签 | 同一类里随机(颜色任务配随机的颜色词) | 1.000 |
| 4 | 自然标签 + 说明 | 同一类里随机 | 1.000 |
| 4 | 自然标签 | 换成另一类的词(颜色任务配形状词) | 0.000 |
| 4 | 符号标签 | 正确标签 | 0.848 |
| 4 | 符号标签 | 随机 | 0.255 |
| 8 | 符号标签 | 正确标签 | 0.987 |
| 8 | 符号标签 | 随机 | 0.250 |
| 任务 | k = 0 | 1 | 2 | 4 | 8 |
|---|---|---|---|---|---|
| 自然标签 + 说明 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 |
| 自然标签(无说明) | 0.000 | 1.000 | 1.000 | 1.000 | 1.000 |
| 符号标签 | 0.286 | 0.458 | 0.569 | 0.864 | 0.988 |
(不带说明、也没有例子时,模型先验上更相信是符号任务——训练数据里 80% 是——所以自然任务 k = 0 是 0。)
还有一个细节:自然任务的随机例子里,如果查询物品本身就出现过(197 题),模型几乎从不照抄那个错误的标签——它仍然回答物品真正的颜色,这个知识在权重里,比上下文里的一个错误例子更”牢”。符号任务就不同了:这时模型有 71% 的时候照抄错误的标签,因为对全新的任务,例子是它唯一的信息来源。
为什么自然任务对随机标签不敏感、符号任务却很敏感?自然标签的任务模型早就”认识”,例子只用来告诉它”现在要做的是哪个任务”——而随机标签仍然来自同一类词(颜色词还是形状词),这个信息没丢。符号任务只能从例子的对应关系里学,标签一乱就什么也学不到。这正是”任务识别”(task recognition)和”任务学习”(task learning)的区别(Pan et al., 2023):真实大模型在常见任务上主要做的是任务识别,所以 Min et al. 的结论成立。
一个更直接的证据:把颜色任务的标签换成另一类的词(形状词),模型就老老实实地回答查询物品的形状——它没有”犯糊涂”,只是被标签空间告知了一个不同的任务。对认识的任务来说,例子里最重要的是标签空间和格式,而不是每个标签对不对。
“例子越多越好”也只对需要从例子里学规则的任务成立:带说明的自然任务 k = 0 就已经全对,多给例子没有用。
3. 提示工程 · Prompt engineering
3.1 换一种说法,结果就不一样
slides 的例子:OPT-175B 做 AG News 新闻分类(零样本),其他一切不变、只换提示的写法,准确率差别很大。那怎样挑一个好的提示?slides 给出 Gonen et al. (2022) 的答案:挑模型觉得困惑度最低(似然最高)的那个提示——slides 还展示了 Bloom 在法语单词翻译上同样的规律。直觉:模型越”眼熟”的说法,它在训练时见得越多,越可能正确理解。好处是不需要任何标注数据就能挑。
代码 03 第 1 部分:ICL 世界里每个特征有三种说法,在训练数据里的频率是 80% / 19.9% / 0.1%,外加一个训练时从没出现过的说法”看这里”:
| 任务 | 说明 | 训练时的频率 | 困惑度 1/P(说明) | 零样本准确率 |
|---|---|---|---|---|
| 颜色 | 颜色 | 80.0% | 25 | 1.000 |
| 颜色 | 什么色 | 19.9% | 101 | 1.000 |
| 颜色 | 色彩 | 0.1% | 15,205 | 1.000 |
| 颜色 | 看这里 | 从没出现过 | 601,607 | 0.000 |
| 形状 | 形状 | 80.0% | 30 | 1.000 |
| 形状 | 什么形 | 19.9% | 109 | 1.000 |
| 形状 | 外形 | 0.1% | 8,020 | 1.000 |
(带说明的序列只占训练数据的 10%,所以”色彩”总共只出现了几十次。为了让模型学到 P(说明),训练时除了标签,也在 <s> 之后的第一个词上算损失。)
困惑度的排序和训练频率完全一致,从没见过的说法困惑度最高、准确率是 0;但三个见过的说法准确率都是 1.000——在这个小世界里,见过几十次就够认识一个说法了,困惑度只是把”没见过的”挑了出来。真实大模型上这个标准更有用:提示有成千上万种写法,模型对它们的熟悉程度差别很大,而困惑度不需要任何标注数据就能算。
3.2 说明和例子打架
如果任务说明说”颜色”,例子的标签却全是形状词,模型听谁的?代码 03 第 2 部分:
| 形状例子的个数 k | 按说明回答(说颜色) | 按例子回答(说形状) |
|---|---|---|
| 0 | 1.000 | 0.000 |
| 1 | 0.027 | 0.966 |
| 2 | 0.000 | 1.000 |
| 4 | 0.000 | 1.000 |
只要有一个例子,模型就改听例子的。训练数据里说明和例子从不矛盾,它没有学过”该信哪个”;而例子里的标签空间(形状词)是一个很强的证据。真实的指令微调模型被专门训练成”听指令”,行为会不一样——但这个实验提醒我们:提示里的不同部分会互相”投票”,模型听谁的取决于训练数据。
3.3 同样 k 个例子:放进提示 vs 拿来微调
slides 第 10 讲说”即使对很大的模型,微调也常常胜过上下文学习”——GPT-3 的例子里,微调用了 39.3 万个样本,少样本只放得下 6 个。如果样本数一样呢?代码 03 第 3 部分:60 个新的符号任务,每个给 k 个例子;上下文学习把它们放进提示,微调则把每个例子做成” 物品 标签”,全量微调 60 步,测试时只给” 查询物品”:
| k | 上下文学习 | 微调(全量,60 步) | 微调:查询物品训练过 | 查询物品没出现过:微调 / 上下文学习 |
|---|---|---|---|---|
| 2 | 0.577 | 0.374 | 1.000(占 14%) | 0.272 / 0.507 |
| 4 | 0.859 | 0.545 | 1.000(占 22%) | 0.414 / 0.818 |
| 8 | 0.992 | 0.749 | 1.000(占 40%) | 0.580 / 0.986 |
微调把训练过的那几个物品全记住了(1.000),但对没出现过的物品只有 0.58(k = 8):梯度主要改了”这几个物品 → 这几个符号”,没有学到”这个任务看的是颜色”这条规则。上下文学习却能用上预训练时学会的”推断规则”的能力。所以 slides 那句”微调常常胜过上下文学习”要加上条件:那是在有成千上万个标注样本时;只有几个例子、而且模型已经会这种推理时,结果可能反过来。
4. 思维链 · Chain-of-thought prompting
4.1 slides 的内容
- 思维链提示(Wei et al., 2022):少样本的例子里不只写答案,还写出推理过程;模型就会模仿着先推理、再回答,在数学应用题等任务上大幅提高准确率。
- 零样本思维链(Kojima et al., 2022):不给任何带推理的例子,只在问题后面加一句”Let’s think step by step”,模型也会更好。
- slides 的总结:让模型”推理一下”能提高少样本上下文学习的效果;思维链提示在例子里提供了推理;但只是提示它”一步一步想”也有用。
4.2 为什么写出中间步骤有用
一个计算上的解释:Transformer 每生成一个 token,只做固定层数的计算。如果一道题需要的”串行步骤”比层数多,一口气直接给答案就很难;允许它先把中间结果一个个写出来,每一步只需要一点点计算,写下的 token 就成了它的”草稿纸”。
代码 04 用最经典的例子——奇偶校验:n 个 0/1,其中 1 的个数是奇数还是偶数?
直接回答: <s> 1 0 1 1 = 1
思维链: <s> 1 0 1 1 想 1 1 0 1 = 1 ("想"之后依次写出前 1、2、3、4 位的累计奇偶)
同一个 4 层的小 GPT 在两种格式各占一半的数据上训练(n = 2..16),测试时分别用两种格式提问(每个 n 500 道新题):
| n | 直接回答 | 思维链 | 中间结果全对的比例 | 思维链要生成的词数 |
|---|---|---|---|---|
| 2 | 1.000 | 1.000 | 1.000 | 4 |
| 6 | 0.950 | 0.980 | 0.908 | 8 |
| 8 | 0.802 | 0.990 | 0.988 | 10 |
| 10 | 0.688 | 0.986 | 0.974 | 12 |
| 12 | 0.582 | 0.984 | 0.952 | 14 |
| 14 | 0.504 | 0.954 | 0.828 | 16 |
| 16 | 0.504 | 0.904 | 0.752 | 18 |
直接回答到 n = 14 就退回瞎猜(0.5);思维链到 n = 16 还有 0.904。同一个模型、同样的参数,差别只在”允许它先写出中间结果”。代价是多生成 n + 1 个词——用更多的推理计算换准确率,这是第 20 讲”推理模型”的核心思想。链条越长,中间步骤全对的比例越低(n = 16 时 0.752),每一步的小错误会积累。
一个插曲:我们先用 2 层的模型试过,思维链在 n ≥ 10 时也开始出错。原因是写第 j 个中间结果时要找到”第 j 位”,它离当前位置的距离随 n 变化,2 层的模型很难算准这个距离。换成 4 层就好了(见 README)。
4.3 写下的推理过程是”真的”吗
代码 04 第 3 部分做了一个干预实验:n = 12,在第 j 个中间结果处强行写入一个错的值,然后让模型接着写,看最终答案是”跟着错的链条走”还是”仍然答对”:
| 改错的是第几个中间结果 | 答案跟着错 | 答案仍然对 |
|---|---|---|
| 1 | 0.160 | 0.840 |
| 6 | 0.534 | 0.466 |
| 11 | 0.824 | 0.176 |
越早改错,越容易被”修正”回来。直接回答在 n = 4 / 6 时还有 0.930 / 0.950,说明模型能直接算出短前缀的奇偶——所以前几步它并不全靠写下的中间结果,而是看着输入的位重新算;到第 11 步,前缀长到它直接算不准了,只能依赖链条,82% 的答案跟着错的中间结果走。
教训:**写下的推理过程和模型”真正的计算”并不完全是一回事。**真实大模型的思维链是否”忠实”(faithful)反映了它的推理,是一个开放问题(Lanham et al., 2023;第 20、26 讲)。还要注意,这个例子是”构造好的”:训练数据里本来就有一半是思维链格式。真实的大模型从网页、教科书、代码里学到了”一步步推理”的写法,思维链提示只是把这种能力”唤出来”。
5. 指令微调 · Instruction fine-tuning
5.1 从”续写”到”回答”
slides 的两组例子:
- 提示模板:ChatGPT、Llama-2 Chat 这类模型被微调成聊天助手,训练时用了特定的模板,把提示分成系统(system)、助手(assistant)、用户(user)三部分。Llama-2 Chat 用
[INST] <<SYS>> 你是一个乐于助人的 AI 助手…… <</SYS>> [/INST],Alpaca 用### Instruction:/### Response:。用这类模型时要按它训练时的模板写提示。 - 基座模型 vs 聊天模型:同一段故事加上”One-sentence Summary:“,Llama-2-70B(基座)直接接着写出一句摘要;Llama-2-7B Chat 却先说”Sure! Here is a one-sentence summary of the story:“再给摘要——经过指令微调的模型,回答的样子和基座模型很不一样。
动机(slides):语言模型被训练来降低一个大语料(网页、文章、代码……)的困惑度,所以它擅长”补全你的 ______“。但聊天助手不应该只是预测接下来是什么,它应该按对话的方式行事,并且知道何时停下——我们希望模型的行为符合人类用户对”按指令完成任务”的期望。
做法:造一个”聊天助手”训练集,在上面微调。这个技术有很多名字:指令微调(instruction fine-tuning)、聊天微调(chat fine-tuning)、对齐(alignment)、行为微调(behavioral fine-tuning)。
5.2 指令数据从哪里来
slides 的问答:“怎样造一个聊天助手的训练集?“答案分两半——提示从哪里来:人写的(标注员、早期 API 用户)、从现有 NLP 数据集套模板改写的、模型生成的;回答从哪里来:人写的、模型生成的。slides 介绍的数据集:
| 数据集 | 规模 | 提示和回答怎么来的 |
|---|---|---|
| InstructGPT(Ouyang et al., 2022) | 约 1.3 万条 | 标注员写指令和示范回答;一部分指令来自 OpenAI API 的早期用户,由标注员写回答;不公开 |
| Dolly(Databricks) | 1.5 万条 | Databricks 员工写全部的提示和回答,开源;类别包括开放问答、一般问答、封闭问答(给定一段材料)、信息抽取、头脑风暴、摘要、分类、创意写作 |
| Flan(Wei et al., 2021) | slides:新版本约 350 万条 | 把现有的 NLP 数据集改写成指令(12 类任务、62 个数据集),每个数据集写 10 个不同的模板 |
| MultiInstruct(Xu et al., 2023) | 62 个多模态任务 | 来自 21 个开源数据集,统一成多模态指令数据 |
slides 还展示了一张”指令微调模型”的表(Zhang et al., 2023 的综述):这些模型都从一个预训练的基座模型出发,在某个指令数据集上微调;规模不必最大(7B–13B 很常见)也能很好用。
5.3 我们的指令微调(代码 05)
农场聊天世界(§0.3)的对话格式:
<s> <user> make the subject singular : the cats beside the hens see the hens at night . <assistant> the cat beside the hens sees the hens at night . </s>
基座模型就是第 2 讲(和第 10 讲)的农场 GPT,扩充词表加上 <user>、<assistant> 和 37 个指令词——新词的嵌入初始化为旧词嵌入的平均,输出层的新行初始化为 0(Hugging Face 的 resize_token_embeddings 就是干这个的)。4000 条指令数据,每种任务用前 4 种说法,只在回答上算损失,全量微调 1500 步(约 10 秒)。
基座模型 vs 指令微调后(第 1 部分):
预训练模型: say it in plural : the bat near the bat makes noise at night . ⇒ in the morning .
describe : the cats ⇒ in the morning .
指令微调后: say it in plural : the bat near the bat makes noise at night . ⇒ the bats near the bat make noise at night .
describe : the cats ⇒ the cats chase the bat at night .
预训练模型在 9 种任务上的平均准确率是 0;200 条指令里有 165 条它一开口就是时间短语——它把 <assistant> 之后当成了句子的继续,在续写,不是在回答。指令微调后平均 0.986。
准确率(第 2 部分,每格 100 道新题;除 describe 外都要求和标准答案逐词相同):
| 任务 | 没见过的两种说法 | 训练时的说法 | 没见过的说法 |
|---|---|---|---|
| subject | give me the subject / find the subject | 1.00 | 0.98 |
| verb | give me the verb / find the verb | 1.00 | 0.80 |
| object | give me the object / find the object | 0.98 | 0.99 |
| time | give me the time / find the time | 1.00 | 1.00 |
| plural | give me the plural / write it plural | 0.96 | 0.52 |
| singular | give me the singular / write it singular | 0.98 | 0.49 |
| short | give me a shorter sentence / write it shorter | 0.95 | 0.58 |
| repeat | give me the sentence / write it again | 1.00 | 0.48 |
| describe | give me a sentence about / say something about | 1.00 | 0.40 |
新说法里带着训练时见过的任务关键词(subject、object、time)的,几乎都对;关键词不在训练用的说法里(repeat 的新说法是 give me the sentence、write it again),或者和别的任务撞了词(write 只在 describe 的训练说法里出现过)的,就差得多——模型抓的是关键词。
对照实验(第 3 部分,9 种任务的平均准确率):
| 做法 | 可训练参数 | 训练时的说法 | 没见过的说法 |
|---|---|---|---|
| 主模型(4 种说法、只算回答、全量微调) | 116,096 | 0.986 | 0.693 |
| 只用 1 种说法训练 | 116,096 | 0.853 | 0.224 |
| 整条序列都算损失 | 116,096 | 0.754 | 0.604 |
| 从随机初始化开始 | 116,096 | 0.892 | 0.626 |
| LoRA r = 8(全部线性层)+ 嵌入和输出层 | 30,336 | 0.866 | 0.560 |
| 只有 300 条数据 | 116,096 | 0.243 | 0.137 |
- 说法的多样性:只用 1 种说法训练,没见过的说法上只有 0.224(4 种说法时 0.693);subject 和 object 的新说法甚至是 0.00——只见过一种说法,模型记住的是整句话的样子,而不是”subject 这个词是关键”。这就是 Flan 给每个数据集写 10 个模板的原因。
- 只在回答上算损失:整条序列都算时,同样的训练步数里很大一部分梯度花在预测指令和输入句子上(输入是随机抽的,怎么学也预测不准),回答的准确率掉到 0.754。实践中的指令微调通常只在回答上算损失(HW3 也是)。
- 预训练的作用:从随机初始化开始也有 0.892——我们的基座模型很小、预训练语料很单一,4000 条指令数据里的句子本身就足够让新模型学会农场语法。真实的指令微调只有几千到几万条数据,要教会模型的却是整个世界的知识,那些只能来自预训练。
- LoRA(HW3 的做法):因为加了新词,嵌入和输出层也得一起训练(Hugging Face 的
modules_to_save)——这是用 LoRA 做指令微调时容易忘的一步。 - 数据太少:300 条数据训练 1500 步(每条看了 160 遍),只有 0.243——9 种任务、每种三十来条,模型很可能把训练集背了下来。
没见过的任务:训练时完全去掉 short 任务,“make it shorter”只答对 0.28(主模型 0.95),其中 65% 的回答是把输入原样复述(输入本来没有介词短语时复述恰好就对)。Flan 的发现是”在很多任务上做指令微调,能提高没见过的任务上的零样本表现”——前提是模型能从预训练里理解”shorter”这些词的意思。我们的基座模型只读过农场句子,指令词全是新加的,没见过的任务它只能套用最像的那个。
6. RLHF(上)· Reinforcement learning from human feedback
6.1 三步
InstructGPT 用 RLHF 微调预训练的 GPT。slides 引用论文的一句话:“在人类评估中,13 亿参数的 InstructGPT 的输出比 1750 亿参数的 GPT-3 更受欢迎,尽管参数少了 100 倍。“三步:
- 示范数据 → 指令微调(SFT):约 1.3 万条示范,让模型的行为像一个聊天助手。但交互的多样性仍受限于训练数据的内容。
- 比较数据 → 奖励模型(RM):取 3.3 万个提示,让第 1 步的模型对每个提示采 K 个回答(K ∈ {4, …, 9}),由标注员排序;用排序训练一个奖励模型。
- 强化学习:把奖励模型当作”真实的奖励”,用强化学习(PPO)微调第 1 步的模型(第 12 讲)。
为什么要排序? slides:偏好信号是一个表达力更强的监督接口——对人来说,挑出自己更喜欢的回答,比亲手写一个好回答容易得多。slides 展示了 Anthropic(Bai et al., 2022)给众包标注员的界面:两个回答并排,选更好的那个。
6.2 奖励模型
slides:奖励模型是第 1 步语言模型的一份拷贝,只是把输出层”对词表的 softmax”换成一个标量——奖励。训练目标是让排在前面(赢)的回答的奖励大于排在后面(输)的:
其中 x 是提示, 是赢和输的回答,D 是人类排序的数据集。同一个提示的全部 对放在同一个批次里:K 个回答各前向一次就得到 对的损失;InstructGPT 论文说,如果把这些对打散成独立样本,每个回答会被看 K−1 次,一个 epoch 就会过拟合。 就是 Bradley–Terry 模型(第 12 讲细讲):两个回答的”实力”差越大,赢的概率越接近 1。
6.3 我们的奖励模型(代码 06)
“人类”是一位标注员,他心里有一个打分 (chat_lab.human_reward):喜欢”吃东西”(+1)和”在早上”(+0.5),讨厌”吵闹”(−1),答非所问或说错话(主语不对、不合语法、不符合这种动物的习性——比如狗在夜里追狐狸)最差(−2)。他排序时会犯错:真实分数差 Δ 时把好的排在前面的概率是 。
对 describe 任务的 400 个提示,让 05 号脚本的指令微调模型(温度 1)各采 4 个回答,由标注员排序:
提示:describe : the dog
第 1 名:the dog eats bones in the morning . 真实分数 +1.5
第 2 名:the dog eats bones in the field . 真实分数 +1.0
第 3 名:the dog makes noise in the morning . 真实分数 −0.5 ← 标注员手抖了:它比下一个还差
第 4 名:the dog chases the hen every day . 真实分数 +0.0
1600 个训练回答里,真实分数为 −2 的只有 85 个——指令微调后的模型很少说错话。
结果(300 个新提示上检验):
| 提示数 | 每个提示 | 训练的对数 | 测试集:和标注一致 | 测试集:和 一致 | 和 的相关 |
|---|---|---|---|---|---|
| 10 | 2 个回答 | 10 | 0.602 | 0.772 | 0.516 |
| 10 | 4 个回答 | 60 | 0.579 | 0.738 | 0.527 |
| 25 | 2 个回答 | 25 | 0.561 | 0.686 | 0.297 |
| 25 | 4 个回答 | 150 | 0.580 | 0.729 | 0.525 |
| 100 | 2 个回答 | 100 | 0.655 | 0.856 | 0.707 |
| 100 | 4 个回答 | 600 | 0.634 | 0.849 | 0.681 |
| 400 | 2 个回答 | 400 | 0.657 | 0.890 | 0.701 |
| 400 | 4 个回答 | 2,400 | 0.654 | 0.880 | 0.698 |
| 400 | 4 个回答(6 对打散成独立样本) | 2,400 | 0.662 | 0.889 | 0.691 |
“和标注一致”的上限是 0.756:一个完全知道 的完美奖励模型,也只能和带噪声的标注一致到这个程度。
- 400 个提示的奖励模型和真实分数 排序一致 0.880,相关系数 0.698——学到了偏好的大方向。
- 排 4 个 vs 比 2 个:我们预期排序一次 K 个回答就得到 个比较,提示少时应该明显更好;实际结果有正有负(25 个提示时 0.729 vs 0.686,10 个提示时反而 0.738 vs 0.772)。提示很少时,结果主要取决于抽到了哪几个提示;而且同一个提示的 6 对来自同样 4 个回答,彼此并不独立,信息量远没有”6 倍”。提示多了以后,两者都学会了这个简单偏好的大方向。
- 打散成独立样本:没有看到 InstructGPT 说的过拟合(0.889 vs 0.880)——我们的奖励模型很小、只训练 3 个 epoch。放在同一批的确定好处是计算上省。
奖励模型只学到了粗线条。 测试集上按真实分数分组的平均得分: = +1.0 和 +1.5 都是 +1.00(“早上 +0.5”几乎没学到);答非所问( = −2)平均 −0.25,反而比普通的真话( = 0:−0.44)还高。在训练数据之外更糟:
| 回答 | 真实分数 | 奖励模型 |
|---|---|---|
| the dogs eat bones in the morning . | +1.5 | +1.01 |
| the dogs chase the cats every day . | 0.0 | −0.06 |
| the dogs make noise in the field . | −1.0 | −1.00 |
| the cats eat fish in the morning .(主语不对) | −2.0 | +1.01 |
| the dogs bones eat in the morning .(词序乱了) | −2.0 | +1.01 |
| the dogs eat eat in the morning .(只剩关键词) | −2.0 | +1.01 |
| the dogs morning eat the morning eat .(胡言乱语) | −2.0 | +1.01 |
奖励模型学会的是”有 eat 就加分、有 noise 就减分”。指令微调模型很少说不合语法的话,奖励模型几乎没见过这类回答。如果第 3 步的强化学习只盯着奖励模型的分数,策略就可能学会说这种”高分的胡话”——这叫奖励被钻空子(reward hacking),第 12 讲会亲眼看到它发生。
6.4 RLHF 的结果
slides 引用 Bai et al. (2022):RLHF 提高了人类评估的有用性(helpfulness)和无害性(harmlessness);在大多数任务上没有损害零样本、少样本的表现(论文报告:对较大的模型甚至略有提升,较小的模型有一点”对齐税”)。
6.5 把 LLM 微调写成强化学习(预告)
slides(Henry Chai 的版本):
- 状态 :所有可能的 token 序列;动作 :下一个 token(词表);
- 转移:确定性的,——把选的词接在后面;
- 奖励:由人类反馈训练的奖励模型 给出。从强化学习的角度看它有点怪:只有在生成 EOS 时才给 ,其余每一步都是 0;
- 模型:要微调的 LLM 就是策略;一个回合(episode) 是对提示 x 的一次完整回答,以 EOS 结束;LLM 给出回答的分布 。
InstructGPT 第 3 步的目标函数:
slides 的直觉解释:(1) 第一项:在 RL 模型自己采的样本上,奖励高的回答概率要高、奖励低的要低;(2) β 那一项:别让 RL 模型离 SFT 模型太远——这是一个 KL 惩罚(正好防止 §6.3 那种钻空子);(3) γ 那一项:在预训练数据上的普通对数似然,防止模型忘了怎么当一个语言模型。实践中每个期望都用很少几个样本的蒙特卡洛平均来近似。下一讲细讲这个目标怎么优化(REINFORCE、PPO),以及怎样完全绕过奖励模型(DPO)。
7. 小结 · Summary
- 上下文学习不更新参数,靠提示里的例子推断任务。它出现的前提是训练数据里”同一段上下文共享一个只能从上下文推断的任务”;它往往在训练中突然出现。学会以后,小模型的预测已经非常接近精确的贝叶斯推断。
- 上下文学习对例子顺序敏感(这是模型对贝叶斯推断的近似误差);对”认识的任务”,标签空间和格式比标签对不对更重要(任务识别),对”全新的任务”则正确标签不可或缺(任务学习)。
- 提示的写法影响结果;困惑度是一个不需要标注就能挑提示的标准。样本很少、模型又会推理时,上下文学习可能比微调更好。
- 思维链把”一次前向做不完的串行计算”摊到多个生成步骤上;但写下的推理过程不一定”忠实”反映模型的计算。
- 指令微调教会模型”格式和行为”:按对话回答、知道何时停。多种说法、只在回答上算损失、足够多的数据都重要;知识主要来自预训练。
- RLHF 的第 2 步从人类排序里学奖励模型(Bradley–Terry 损失,同一提示的所有对放一批)。奖励模型只在它见过的回答附近可靠——这是第 3 步要加 KL 惩罚的原因。
8. 常见误区 · Common pitfalls
- “上下文学习是在提示里训练模型。” 参数一点没变;它是一次前向里的推断。
- “例子越多越好。” 对认识的任务,零样本就够了;多给例子可能只是更长、更慢。
- “随机标签也行,说明标签不重要。” 只对模型已经认识的任务成立;全新的映射必须靠正确的标签(§2.3)。
- “思维链就是模型的真实想法。” 我们的干预实验里,改错早期步骤,答案常常不跟着变(§4.3)。
- “指令微调教会了模型新知识。” 主要教的是格式和行为;新知识要么来自预训练,要么需要大量数据。
- “只要说法里有关键词,模型就懂。” 只用一种说法训练时,连关键词都抓不住(§5.3)。
- “奖励模型分数高 = 人类喜欢。” 奖励模型在训练分布之外可能给胡话打高分(§6.3)。
- “RLHF 的奖励在每一步都有。” 只有在回答结束(EOS)时才有一个数;中间每一步都是 0。
9. 练习 · Exercises
练习 1(贝叶斯推理)。 在 ICL 世界里,看到一个例子”红圆 → B”之后,为什么还剩 12 个任务?查询”黄圆”时,为什么 P(B) = 0.5、其余三个符号各 1/6?
参考答案
自然标签的任务全部排除(标签是符号)。符号任务里:特征 = 颜色时,要求”红 → B”,其余 3 种颜色对剩下 3 个符号任意排列,3! = 6 种;特征 = 形状时,要求”圆 → B”,同样 6 种。共 12 种,先验相同,后验均匀。查询黄圆:颜色任务里黄对应 A、C、D 之一(各 2 种排列);形状任务里圆 → B(6 种全是 B)。所以 P(B) = 6/12 = 0.5,P(A) = P(C) = P(D) = 2/12 = 1/6。
练习 2(为什么农场 GPT 没有 ICL)。 用一句话说明 01 号脚本的对照模型(每个例子各自一个任务)为什么学不会上下文学习。如果想让农场 GPT 有上下文学习,你会怎样改它的训练数据?
参考答案
在它的训练数据里,前面的例子和后面的标签相互独立,看前文不能降低损失,所以梯度从不鼓励”看前文”。改法:让同一段文本共享一个隐藏的”主题”,例如每段文本描述同一个农场,而不同农场的动物习性不同(像第 10 讲的”冬天的农场”那样随机抽一套习性),这样前面的句子就能告诉模型”这是哪个农场”,帮助预测后面的句子。
练习 3(任务识别 vs 任务学习)。 一个情感分类任务(正面 / 负面),提示里的例子标签是随机的。大模型的准确率只掉了一点。另一个任务,把”正面”写成”foo”、“负面”写成”bar”,再用随机标签。你预计会怎样?为什么?
参考答案
第二个任务会掉很多。第一个任务里模型”认识”情感分类,标签词”正面 / 负面”本身就告诉它任务是什么,例子只是确认格式和标签空间(任务识别)。第二个任务里 foo / bar 和情感的对应只能从例子里学(任务学习),随机标签把这个对应毁了。这正是 §2.3 里自然标签和符号标签的区别。
练习 4(思维链的计算量)。 直接回答 n 位奇偶校验只生成 1 个词;思维链生成 n + 2 个词。如果模型有 L 层,两种方式各做了多少”层 × 位置”的计算(只算新生成的位置)?这和”一次前向的串行深度”有什么关系?
参考答案
直接回答:1 个新位置 × L 层,串行深度 L。思维链:n + 2 个新位置,每个 L 层,而且第 j 个位置依赖前面写下的 token,所以串行深度是 (n + 2)·L。奇偶校验需要的串行步骤随 n 增长,固定的 L 不够用;思维链把串行深度变成了随输出长度增长。
练习 5(只在回答上算损失)。 写出 chat_lab.encode_chat 在 loss_on="response" 时,对序列 <s> <user> verb ? : the cat eats fish . <assistant> eats </s> 的目标(targets)。哪些位置是 IGNORE?
参考答案
ids 去掉最后一个词作为输入,target[i] = ids[i+1]。回答从 “eats”(<assistant> 之后那个词)开始,所以只有”输入是 <assistant>、目标是 eats”和”输入是 eats、目标是 </s>”这两个位置有目标,其余(从 <s> 到 .)都是 IGNORE。注意 </s> 也要算——模型要学会”答完就停”。
练习 6(奖励模型的损失)。 K = 4 时一个提示有几对比较?如果标注员的排序是 ,写出所有 (赢, 输) 对。为什么 InstructGPT 不把它们打散成独立样本?
参考答案
对:(2,4)、(2,1)、(2,3)、(4,1)、(4,3)、(1,3)。放在同一批,4 个回答各前向一次就能算 6 对的损失(打散后要前向 12 次);而且打散后每个回答在一个 epoch 里被看 3 次,InstructGPT 报告这样会过拟合。我们的小实验里过拟合不明显(§6.3),计算上的节省是确定的。
练习 7(Bradley–Terry 与噪声)。 标注员把真实分数差 Δ 的两个回答排对的概率是 。Δ = 0.5(比如”早上”带来的差别)时是多少?为什么奖励模型没学会”早上 +0.5”?
参考答案
——四分之一以上的比较是反的。而且只有时间短语不同、其余相同的回答对很少,“早上”的信号被”吃东西 ±1、吵闹 ±1”这些大差别和噪声淹没了。奖励模型的”分辨率”受标注噪声和数据里有没有足够的”只差这一点”的对比限制。
练习 8(KL 惩罚)。 用 §6.3 的表解释:如果第 3 步的目标里没有 β 那一项,策略可能学会说什么?β 那一项为什么能防止它?
参考答案
奖励模型给”the dogs eat eat in the morning .”这类胡话 +1.01,和最好的真话一样高;没有约束时,策略会把概率挪到任何高分的序列上,包括胡话和答非所问。KL 惩罚 让策略给”SFT 模型几乎不可能说的话”(胡话的 极小)分配概率时付出很大代价,于是它只能在 SFT 模型”本来就会说”的回答里重新分配概率——那正是奖励模型可靠的区域。
10. 延伸阅读 · Further reading
- 上下文学习的来源:Xie et al. (2022), An Explanation of In-context Learning as Implicit Bayesian Inference;Chan et al. (2022), Data Distributional Properties Drive Emergent In-Context Learning in Transformers;Olsson et al. (2022), In-context Learning and Induction Heads;Garg et al. (2022), What Can Transformers Learn In-Context?。
- 上下文学习的敏感性:Lu et al. (2022), Fantastically Ordered Prompts;Zhao et al. (2021), Calibrate Before Use;Min et al. (2022);Pan et al. (2023), What In-Context Learning “Learns” In-Context: Disentangling Task Recognition and Task Learning。
- 提示与思维链:Gonen et al. (2022), Demystifying Prompts in Language Models via Perplexity Estimation;Wei et al. (2022);Kojima et al. (2022), Large Language Models are Zero-Shot Reasoners;Nye et al. (2021), Show Your Work: Scratchpads;Lanham et al. (2023), Measuring Faithfulness in Chain-of-Thought Reasoning。
- 指令微调:Wei et al. (2021), Flan;Longpre et al. (2023), The Flan Collection;Taori et al. (2023), Alpaca;Zhou et al. (2023), LIMA: Less Is More for Alignment;Zhang et al. (2023), Instruction Tuning for Large Language Models: A Survey。
- RLHF:Christiano et al. (2017), Deep RL from Human Preferences;Stiennon et al. (2020), Learning to Summarize from Human Feedback;Ouyang et al. (2022);Bai et al. (2022);Gao, Schulman & Hilton (2023), Scaling Laws for Reward Model Overoptimization。
11. 下一讲预告 · Next lecture
第 12 讲把 RLHF 做完:用 REINFORCE 和 PPO 让农场聊天助手去最大化 06 号脚本的奖励模型——我们会看到奖励被钻空子、KL 惩罚怎样防止它;再推出 DPO:在 KL 约束下最优的策略有闭式解,把它代回 Bradley–Terry 模型,就得到一个不需要奖励模型、不需要强化学习的分类损失。讲义的后半部分转向图像:怎样让图像生成听文字的话(GAN、自回归、扩散三条路线),以及潜空间扩散。