第 11 讲 · 上下文学习、提示工程、指令微调与 RLHF · In-Context Learning, Prompting, Instruction Fine-Tuning & RLHF

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

课程源码 ZIP ↓

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

本篇目录

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

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

  1. 说清上下文学习(ICL)是什么、它和微调的区别;解释”为什么训练数据要有某种结构,上下文学习才会出现”。
  2. 用贝叶斯推断的语言描述上下文学习:例子在帮模型排除哪些”任务假设”。
  3. 说出上下文学习对哪些因素敏感(顺序、标签覆盖),以及”随机标签几乎不影响结果”在什么条件下成立。
  4. 解释提示工程的两个经验:提示的写法影响结果;挑困惑度最低的提示。说出思维链为什么能帮忙(以及它的推理过程不一定”忠实”)。
  5. 描述指令微调:数据格式(对话模板)、只在回答上算损失、多种说法(模板)的作用、它和预训练的分工。
  6. 写出 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 讲都从同一张表开始:你有一个很小的数据集 {(xi,yi)}i=1N\{(x_i, y_i)\}_{i=1}^N 和一个很大的预训练语言模型。

  • A. 监督微调(SFT):用标准监督目标和反向传播更新参数。缺点:反向传播约 3 倍于前向的显存和计算;可能拿不到权重。(第 10 讲)
  • B. 上下文学习(ICL):把训练样本写进提示,让模型在推理时从中找规律,取它接下来写出的内容当预测。优点:不需要反向传播,每个例子只”过”一遍;有 API 就行。缺点:提示可能很长,Transformer 处理长度为 N 的上下文要 O(N2)O(N^2) 的时间和空间。

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(黄圆 的标签 | 例子)
(还没有例子)50D、C、B、A 各 0.22(还有 0.12 在自然标签上)
红圆→B12B 0.50,其余各 0.17
红圆→B 蓝方→C4B 0.50,D 0.25,A 0.25
红圆→B 蓝方→C 红角→B2D 0.50,A 0.50
红圆→B 蓝方→C 红角→B 黄十→D1D 1.00

第 3 个例子之后只剩两种可能——“红圆和红角都是 B”说明任务看的是颜色;第 4 个例子告诉我们黄 = D。上下文学习在做的,就是这种”用例子排除假设”的推理。

1.3 它是突然出现的

代码 01 第 2 部分记录了训练过程中两类符号题的准确率(8 个例子;“可照抄”= 查询物品本身在例子里出现过;“要推断”= 物品没出现过,但同颜色或同形状的出现过):

训练步数自然标签(1 个例子)符号·可照抄符号·要推断
4001.000.270.24
28001.000.240.27
32001.000.820.48
36001.001.000.85
40001.001.000.92
100001.001.000.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(贝叶斯 ‖ 模型)
符号标签10.4340.4350.010
符号标签20.5880.5860.041
符号标签40.8360.8760.106
符号标签80.9880.9950.011
自然标签11.0001.0000.000
自然标签 + 说明(零样本)01.0001.0000.000

“贝叶斯(期望)“是完美推理者的期望准确率(平均的 max⁡yP(y∣例子)\max_y P(y \mid \text{例子}))。模型的预测分布和贝叶斯后验的 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.8770.8400.9157.5%
自然标签1.0001.0001.0000%

贝叶斯最优只看”有哪些例子”,不看顺序。所以顺序敏感是模型自己的毛病——它不是一个完美的推理者,不同的排列让它走了不同的”近似”。真实大模型上这个问题严重得多:Lu et al. 报告同一组例子换个顺序,准确率可以从接近瞎猜到接近最好。

2.2 标签平衡、覆盖了几种标签

slides:上下文学习对标签是否平衡(比如正例和负例各多少)、例子覆盖了几种标签敏感。代码 02 第 2 部分(符号任务,4 个例子):

例子标签见过:模型 / 贝叶斯标签没见过:模型 / 贝叶斯没见过时放在”已出现标签”上的概率
覆盖 1 种(4 个例子同一个标签)0.988 / 0.9920.343 / 0.3340.5%
覆盖 2 种(2:2)0.973 / 0.9830.502 / 0.5003.4%
覆盖 2 种(3:1)0.987 / 0.9840.491 / 0.5005.9%
覆盖 3 种0.949 / 0.9590.826 / 0.98117.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 = 01248
自然标签 + 说明1.0001.0001.0001.0001.000
自然标签(无说明)0.0001.0001.0001.0001.000
符号标签0.2860.4580.5690.8640.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%251.000
颜色什么色19.9%1011.000
颜色色彩0.1%15,2051.000
颜色看这里从没出现过601,6070.000
形状形状80.0%301.000
形状什么形19.9%1091.000
形状外形0.1%8,0201.000

(带说明的序列只占训练数据的 10%,所以”色彩”总共只出现了几十次。为了让模型学到 P(说明),训练时除了标签,也在 <s> 之后的第一个词上算损失。)

困惑度的排序和训练频率完全一致,从没见过的说法困惑度最高、准确率是 0;但三个见过的说法准确率都是 1.000——在这个小世界里,见过几十次就够认识一个说法了,困惑度只是把”没见过的”挑了出来。真实大模型上这个标准更有用:提示有成千上万种写法,模型对它们的熟悉程度差别很大,而困惑度不需要任何标注数据就能算。

3.2 说明和例子打架

如果任务说明说”颜色”,例子的标签却全是形状词,模型听谁的?代码 03 第 2 部分:

形状例子的个数 k按说明回答(说颜色)按例子回答(说形状)
01.0000.000
10.0270.966
20.0001.000
40.0001.000

只要有一个例子,模型就改听例子的。训练数据里说明和例子从不矛盾,它没有学过”该信哪个”;而例子里的标签空间(形状词)是一个很强的证据。真实的指令微调模型被专门训练成”听指令”,行为会不一样——但这个实验提醒我们:提示里的不同部分会互相”投票”,模型听谁的取决于训练数据。

3.3 同样 k 个例子:放进提示 vs 拿来微调

slides 第 10 讲说”即使对很大的模型,微调也常常胜过上下文学习”——GPT-3 的例子里,微调用了 39.3 万个样本,少样本只放得下 6 个。如果样本数一样呢?代码 03 第 3 部分:60 个新的符号任务,每个给 k 个例子;上下文学习把它们放进提示,微调则把每个例子做成” 物品 标签”,全量微调 60 步,测试时只给” 查询物品”:

k上下文学习微调(全量,60 步)微调:查询物品训练过查询物品没出现过:微调 / 上下文学习
20.5770.3741.000(占 14%)0.272 / 0.507
40.8590.5451.000(占 22%)0.414 / 0.818
80.9920.7491.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直接回答思维链中间结果全对的比例思维链要生成的词数
21.0001.0001.0004
60.9500.9800.9088
80.8020.9900.98810
100.6880.9860.97412
120.5820.9840.95214
140.5040.9540.82816
160.5040.9040.75218

直接回答到 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 个中间结果处强行写入一个错的值,然后让模型接着写,看最终答案是”跟着错的链条走”还是”仍然答对”:

改错的是第几个中间结果答案跟着错答案仍然对
10.1600.840
60.5340.466
110.8240.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 外都要求和标准答案逐词相同):

任务没见过的两种说法训练时的说法没见过的说法
subjectgive me the subject / find the subject1.000.98
verbgive me the verb / find the verb1.000.80
objectgive me the object / find the object0.980.99
timegive me the time / find the time1.001.00
pluralgive me the plural / write it plural0.960.52
singulargive me the singular / write it singular0.980.49
shortgive me a shorter sentence / write it shorter0.950.58
repeatgive me the sentence / write it again1.000.48
describegive me a sentence about / say something about1.000.40

新说法里带着训练时见过的任务关键词(subject、object、time)的,几乎都对;关键词不在训练用的说法里(repeat 的新说法是 give me the sentence、write it again),或者和别的任务撞了词(write 只在 describe 的训练说法里出现过)的,就差得多——模型抓的是关键词。

对照实验(第 3 部分,9 种任务的平均准确率):

做法可训练参数训练时的说法没见过的说法
主模型(4 种说法、只算回答、全量微调)116,0960.9860.693
只用 1 种说法训练116,0960.8530.224
整条序列都算损失116,0960.7540.604
从随机初始化开始116,0960.8920.626
LoRA r = 8(全部线性层)+ 嵌入和输出层30,3360.8660.560
只有 300 条数据116,0960.2430.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 倍。“三步:

  1. 示范数据 → 指令微调(SFT):约 1.3 万条示范,让模型的行为像一个聊天助手。但交互的多样性仍受限于训练数据的内容。
  2. 比较数据 → 奖励模型(RM):取 3.3 万个提示,让第 1 步的模型对每个提示采 K 个回答(K ∈ {4, …, 9}),由标注员排序;用排序训练一个奖励模型。
  3. 强化学习:把奖励模型当作”真实的奖励”,用强化学习(PPO)微调第 1 步的模型(第 12 讲)。

为什么要排序? slides:偏好信号是一个表达力更强的监督接口——对人来说,挑出自己更喜欢的回答,比亲手写一个好回答容易得多。slides 展示了 Anthropic(Bai et al., 2022)给众包标注员的界面:两个回答并排,选更好的那个。

6.2 奖励模型

slides:奖励模型是第 1 步语言模型的一份拷贝,只是把输出层”对词表的 softmax”换成一个标量——奖励。训练目标是让排在前面(赢)的回答的奖励大于排在后面(输)的:

loss(θ)=−1(K2) E(x, yw, yl)∼D[log⁡σ(rθ(x,yw)−rθ(x,yl))]\text{loss}(\theta) = -\frac{1}{\binom{K}{2}}\, \mathbb E_{(x,\, y_w,\, y_l)\sim D}\Big[\log \sigma\big(r_\theta(x, y_w) - r_\theta(x, y_l)\big)\Big]

其中 x 是提示,yw,yly_w, y_l 是赢和输的回答,D 是人类排序的数据集。同一个提示的全部 (K2)\binom{K}{2} 对放在同一个批次里:K 个回答各前向一次就得到 (K2)\binom{K}{2} 对的损失;InstructGPT 论文说,如果把这些对打散成独立样本,每个回答会被看 K−1 次,一个 epoch 就会过拟合。σ(rw−rl)\sigma(r_w - r_l) 就是 Bradley–Terry 模型(第 12 讲细讲):两个回答的”实力”差越大,赢的概率越接近 1。

6.3 我们的奖励模型(代码 06)

“人类”是一位标注员,他心里有一个打分 r∗r^*(chat_lab.human_reward):喜欢”吃东西”(+1)和”在早上”(+0.5),讨厌”吵闹”(−1),答非所问或说错话(主语不对、不合语法、不符合这种动物的习性——比如狗在夜里追狐狸)最差(−2)。他排序时会犯错:真实分数差 Δ 时把好的排在前面的概率是 σ(Δ/0.5)\sigma(\Delta / 0.5)。

对 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 个新提示上检验):

提示数每个提示训练的对数测试集:和标注一致测试集:和 r∗r^* 一致和 r∗r^* 的相关
102 个回答100.6020.7720.516
104 个回答600.5790.7380.527
252 个回答250.5610.6860.297
254 个回答1500.5800.7290.525
1002 个回答1000.6550.8560.707
1004 个回答6000.6340.8490.681
4002 个回答4000.6570.8900.701
4004 个回答2,4000.6540.8800.698
4004 个回答(6 对打散成独立样本)2,4000.6620.8890.691

“和标注一致”的上限是 0.756:一个完全知道 r∗r^* 的完美奖励模型,也只能和带噪声的标注一致到这个程度。

  • 400 个提示的奖励模型和真实分数 r∗r^* 排序一致 0.880,相关系数 0.698——学到了偏好的大方向。
  • 排 4 个 vs 比 2 个:我们预期排序一次 K 个回答就得到 (K2)\binom K2 个比较,提示少时应该明显更好;实际结果有正有负(25 个提示时 0.729 vs 0.686,10 个提示时反而 0.738 vs 0.772)。提示很少时,结果主要取决于抽到了哪几个提示;而且同一个提示的 6 对来自同样 4 个回答,彼此并不独立,信息量远没有”6 倍”。提示多了以后,两者都学会了这个简单偏好的大方向。
  • 打散成独立样本:没有看到 InstructGPT 说的过拟合(0.889 vs 0.880)——我们的奖励模型很小、只训练 3 个 epoch。放在同一批的确定好处是计算上省。

奖励模型只学到了粗线条。 测试集上按真实分数分组的平均得分:r∗r^* = +1.0 和 +1.5 都是 +1.00(“早上 +0.5”几乎没学到);答非所问(r∗r^* = −2)平均 −0.25,反而比普通的真话(r∗r^* = 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 的版本):

  • 状态 ss:所有可能的 token 序列;动作 aa:下一个 token(词表);
  • 转移:确定性的,s′=(s,a)s' = (s, a)——把选的词接在后面;
  • 奖励:由人类反馈训练的奖励模型 rθr_\theta 给出。从强化学习的角度看它有点怪:只有在生成 EOS 时才给 rθ(x,y)r_\theta(x, y),其余每一步都是 0;
  • 模型:要微调的 LLM pθ(a∣s)p_\theta(a \mid s) 就是策略;一个回合(episode)τ=(x,a1,…,aT)\tau = (x, a_1, \ldots, a_T) 是对提示 x 的一次完整回答,以 EOS 结束;LLM 给出回答的分布 pθ(τ)=∏tpθ(at∣st)p_\theta(\tau) = \prod_t p_\theta(a_t \mid s_t)。

InstructGPT 第 3 步的目标函数:

objective(ϕ)=E(x,y)∼DπϕRL[rθ(x,y)−βlog⁡πϕRL(y∣x)πSFT(y∣x)]+γ Ex∼Dpretrain[log⁡πϕRL(x)]\text{objective}(\phi) = \mathbb E_{(x, y)\sim D_{\pi_\phi^{RL}}}\Big[r_\theta(x, y) - \beta \log\frac{\pi_\phi^{RL}(y \mid x)}{\pi^{SFT}(y \mid x)}\Big] + \gamma\, \mathbb E_{x\sim D_{\text{pretrain}}}\big[\log \pi_\phi^{RL}(x)\big]

slides 的直觉解释:(1) 第一项:在 RL 模型自己采的样本上,奖励高的回答概率要高、奖励低的要低;(2) β 那一项:别让 RL 模型离 SFT 模型太远——这是一个 KL 惩罚(正好防止 §6.3 那种钻空子);(3) γ 那一项:在预训练数据上的普通对数似然,防止模型忘了怎么当一个语言模型。实践中每个期望都用很少几个样本的蒙特卡洛平均来近似。下一讲细讲这个目标怎么优化(REINFORCE、PPO),以及怎样完全绕过奖励模型(DPO)。


7. 小结 · Summary

  1. 上下文学习不更新参数,靠提示里的例子推断任务。它出现的前提是训练数据里”同一段上下文共享一个只能从上下文推断的任务”;它往往在训练中突然出现。学会以后,小模型的预测已经非常接近精确的贝叶斯推断。
  2. 上下文学习对例子顺序敏感(这是模型对贝叶斯推断的近似误差);对”认识的任务”,标签空间和格式比标签对不对更重要(任务识别),对”全新的任务”则正确标签不可或缺(任务学习)。
  3. 提示的写法影响结果;困惑度是一个不需要标注就能挑提示的标准。样本很少、模型又会推理时,上下文学习可能比微调更好。
  4. 思维链把”一次前向做不完的串行计算”摊到多个生成步骤上;但写下的推理过程不一定”忠实”反映模型的计算。
  5. 指令微调教会模型”格式和行为”:按对话回答、知道何时停。多种说法、只在回答上算损失、足够多的数据都重要;知识主要来自预训练。
  6. 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 时一个提示有几对比较?如果标注员的排序是 y2≻y4≻y1≻y3y_2 \succ y_4 \succ y_1 \succ y_3,写出所有 (赢, 输) 对。为什么 InstructGPT 不把它们打散成独立样本?

参考答案

(42)=6\binom 4 2 = 6 对:(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)\sigma(\Delta / 0.5)。Δ = 0.5(比如”早上”带来的差别)时是多少?为什么奖励模型没学会”早上 +0.5”?

参考答案

σ(1)≈0.73\sigma(1) \approx 0.73——四分之一以上的比较是反的。而且只有时间短语不同、其余相同的回答对很少,“早上”的信号被”吃东西 ±1、吵闹 ±1”这些大差别和噪声淹没了。奖励模型的”分辨率”受标注噪声和数据里有没有足够的”只差这一点”的对比限制。

练习 8(KL 惩罚)。 用 §6.3 的表解释:如果第 3 步的目标里没有 β 那一项,策略可能学会说什么?β 那一项为什么能防止它?

参考答案

奖励模型给”the dogs eat eat in the morning .”这类胡话 +1.01,和最好的真话一样高;没有约束时,策略会把概率挪到任何高分的序列上,包括胡话和答非所问。KL 惩罚 −βlog⁡πRLπSFT-\beta\log\frac{\pi^{RL}}{\pi^{SFT}} 让策略给”SFT 模型几乎不可能说的话”(胡话的 πSFT\pi^{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、自回归、扩散三条路线),以及潜空间扩散。

← 返回课程目录