对应:Stanford CS336 Spring 2026 Lecture 15(“After pretraining”:mid/post-training,Tatsunori Hashimoto 的幻灯片)。Spring 2025 的第 15 讲内容相近,有公开录像。 配套代码:
code/lecture15/预计阅读时间:3 小时 硬件说明:全部在 CPU 上运行。第一次运行会训练并缓存几个小模型(共约 3 分钟);01、03 号脚本各约 3~4 分钟,其余更快。
0. 本讲导航
0.1 学完本讲,你应该能够
- 说清”预训练模型”和”助手”之间差了什么,以及标准的后训练流程:先模仿(SFT),再优化(RLHF)。
- 描述指令数据的演变(FLAN → Alpaca → OpenAssistant → Tulu 3 → 带工具调用的数据),以及数据的风格、知识、安全性如何影响模型。
- 实现对话模板和损失掩码,解释为什么 SFT 用很少的数据就能让基座模型”听话”。
- 解释”中期训练”(把指令数据混进预训练)的动机。
- 说出 RLHF 数据收集的难点:标注噪声、标注者是谁、长度偏差、用大模型当标注者。
- 推导 Bradley–Terry 奖励模型和 DPO,并亲手验证 DPO 的推导。
- 解释”过度优化”和”模式坍缩”,并在实验中观察它们。
0.2 先修知识
| 知识点 | 用在哪里 | 最低要求 |
|---|---|---|
| 第 3、10 讲 | 全讲 | Transformer 语言模型;KV 缓存生成 |
| 第 12 讲 | 第 5、6 节 | Chatbot Arena 的 Bradley–Terry 模型;AlpacaEval 的长度控制 |
| 交叉熵、sigmoid | 第 6、7 节 | 知道 log sigmoid 是什么 |
| KL 散度 | 第 7、8 节 | KL(p‖q) = Σ p log(p/q),衡量两个分布差多远 |
0.3 本讲地图
第1节 从 GPT-3 到 InstructGPT:为什么需要后训练
第2节 SFT 的数据:里面有什么?什么样的数据好?
第3节 SFT 的方法:对话模板、损失掩码、中期训练 ← 01 号文件
第4节 从模仿到优化:为什么需要 RLHF
第5节 RLHF 的数据:成对比较、标注者、长度偏差 ← 02 号文件
第6节 奖励模型 ← 02 号文件
第7节 怎样优化:PPO(概念)与 DPO ← 03 号文件
第8节 要小心的事:过度优化、模式坍缩 ← 03、04 号文件
第9节 小结
1. 从 GPT-3 到 InstructGPT
到目前为止,我们学完了预训练:数据、架构、系统、规模定律。它能把你带到 GPT-3——一个非常强大的”续写机器”。但从 GPT-3 到 ChatGPT(InstructGPT,Ouyang et al. 2022)之间,还差了一步:让模型听指令。
指令跟随是一种了不起的”控制”方式。你用一句话就能让模型做几乎任何事:写一首满足某种格式的诗、用某种语气改写一段文字、按要求调用工具……而基座模型只会续写:你给它一个问题,它可能接着写出更多的问题(因为网上的问题列表就是这样的)。
预训练数据并不是我们想要的样子,但它能规模化。所以问题是:能不能收集一些”我们想要的行为”的数据,在上面继续训练? 三个问题贯穿本讲:
- 这种数据长什么样?
- 怎样最好地利用它?
- 需要很大的规模吗?
一个提醒:后训练的公开信息很少。ChatGPT 之前的论文有丰富的细节(Stiennon et al. 2020 公开了标注指南;Anthropic 的 HH 数据集论文 Bai et al. 2022 详细描述了安全标注);如今,开源模型大量使用”蒸馏”(用更强模型生成的数据),闭源模型把数据当作”秘方”。
标准做法(InstructGPT):先模仿(监督微调,SFT),再强化(基于人类反馈的强化学习,RLHF)。本讲的前半部分讲 SFT,后半部分讲 RLHF。
我们的玩具世界。配套代码把第 10 讲那个 4 层、字节级的故事模型当作”基座模型”(它在第 3 讲的合成小故事上预训练过),目标是把它变成一个听指令写故事的助手:
用户:Write a story about a brave fox named Kalomi who loves to sing.
助手:Once upon a time, there was a brave fox named Kalomi. Kalomi loved to sing in the beach. ...<|end|>
回答写 24 句。故事发生在哪里(地点)指令里没说,留给模型自由发挥——后面”人的偏好”就体现在这里。我们还假想了一个”用户真正想要什么”的真实奖励:按指令写得 2 分,地点合心意加 -1+1 分(海滩最好、集市最差),超过 2 句每多一句扣 0.4 分(用户喜欢简洁)。现实中这个函数是拿不到的——正因为是玩具世界,我们才能看清”优化代理指标”和”优化真实目标”之间的差距。
2. SFT 的数据
2.1 指令数据的演变
开源世界里指令数据的大致演变:
FLAN → Self-Instruct → Alpaca → ShareGPT / Vicuna → OpenAssistant → WizardLM → Tulu 3 → Nemotron → 工具调用……
几个代表的风格(课件里的随机样例):
- FLAN(2021~2022):把大量现成的 NLP 数据集改写成”指令”形式——“给这封邮件写个标题”、“这段新闻属于哪一类?选项:世界 / 体育 / 商业 / 科技”、“用这些字段写一句描述餐厅的话”。数据是有效的,但回答往往只有几个词。人不想和一个 NLP 基准聊天。
- Alpaca(2023):用 text-davinci-003 按 Self-Instruct 的方法生成 5.2 万条指令和回答——“给出保持健康的三个建议”、“解释’算法’是什么意思”、“写一个求平均数的函数”。更像聊天,回答更长。
- OpenAssistant(2023):志愿者写的对话,回答详细得多,甚至会列出参考文献。
- Nemotron-SFT-OpenCode 等近两年的数据:大量的工具调用和智能体轨迹——回答里不是文字,而是”调用 bash 技能”、“写一个待办清单”这样的结构化动作。
2.2 这些数据在哪些方面不同?
- “健谈”程度:FLAN 简短、Alpaca 中等、OpenAssistant 详尽。后来的数据越来越长、越来越详细;
- 细节与知识:OpenAssistant 的回答包含大量事实性知识(这既是优点也是隐患,见 2.4 节);
- 工具使用:SFT 数据正在大量转向工具调用和智能体应用;
- 不那么显眼、但同样重要的:规模和安全性。
2.3 风格:长度与格式
不同的指令数据训练出的模型,回答长度差别很大(Wang et al. 2023,“How Far Can Camels Go?”)。用偏好来评估时,风格非常重要:人类和 GPT-4 评委都强烈偏爱更长的回答(Dubois et al. 2023,AlpacaFarm)——这就是第 12 讲 AlpacaEval 要做”长度控制”的原因。但对于知识类、推理类的基准测试(MMLU 之类),这些风格因素大多无关紧要。
2.4 知识、事实性与”幻觉”
OpenAssistant 里有这样一条:用户问”请简要介绍经济学里’买方垄断’的含义,并引用相关研究”,回答的最后列出了一篇参考文献(Bivens & Mishel, 2013)。这条数据在教模型什么?
- 教模型”Bivens 和 Mishel 写过这篇论文”这个知识;
- 教模型”被要求引用时,就输出引用”这个行为。
问题在于第 2 点:如果模型本来不知道这篇论文,SFT 教会它的是”被要求引用时,就编一个像样的引用出来”——也就是幻觉。流传的说法(Schulman 2023 的演讲):在模型不知道的事实上做微调,会让它更爱编造。Gekhman et al. 2024 做了受控实验:微调数据里”模型本来不知道的知识”越多,模型学得越慢,而一旦学会,幻觉就越严重。
要点:
- 即使你的应用就是”回答长尾知识”,也可能不应该在长尾知识上做 SFT;
- 原则上,“对 / 错”式的反馈(强化学习)可以帮忙——它奖励”说对的”,而不只是”说得像”;
- 语言模型里知识的存储和提取是复杂而微妙的,还没有被完全理解。
2.5 安全
语言模型被部署给大量用户,需要一些安全控制:虚假信息、诈骗和垃圾信息……公开的细节很少:Llama 2 的安全 SFT 数据大约只有几千条。最详细的流程之一,是从真实用户的请求中提取”危险场景”,再写出合适的回答。
一个重要的发现(Bianchi et al. 2024,“Safety-Tuned LLaMAs”):只加入约 500 条安全示范,就能显著改善模型对有害请求(仇恨言论、Anthropic HH 中的有害问题)的表现。当然,安全数据太多会导致”过度拒绝”(连正常请求也拒绝),这是一个需要权衡的地方。
2.6 小结:SFT 的数据
- SFT 最擅长提取预训练中已经学到的行为,而不是添加新行为;
- 加入(即使是事实正确的!)知识,有时反而有害;
- 少量”对的”行为数据(安全、指令跟随、风格)作用很大;但长尾的能力需要更多数据。
3. SFT 的方法
3.1 就是梯度下降
SFT 的训练方法本身非常简单:在”指令 → 回答”上做梯度下降,和预训练一模一样。在很多学术研究中,这就是全部。细节在于数据怎样喂进去。
对话模板。模型要知道”哪里是用户说的、哪里是助手说的、助手什么时候说完”。做法是引入特殊 token。01_chat_template_sft.py 的演示 1:
<|user|>Please write a short story about Mifi, a curious bird who enjoys dancing.<|assistant|>Once upon a time, there was a curious bird named Mifi. Mifi loved to dance in the park. One day, Mifi found a blue kite.<|end|>
- 基座模型的词表只有 256 个字节,所以要给嵌入层和输出层各加 3 行(
posttrain.extend_vocab,用已有行的平均值初始化,训练起来更平稳); <|end|>让助手学会”写完就停”——基座模型从来不停;- 损失掩码:只在回答(助手说的话)上计算损失。这条数据的提示词有 75 个 token、回答 121 个,只有这 121 个位置计入损失。
3.2 基座模型:看不懂指令,但”会写”
演示 2 用三种方式考基座模型:
| 提问方式 | 结果 |
|---|---|
| (a) 用对话模板(它从没见过这些特殊 token) | 胡言乱语,接着写别的故事的后半段 |
| (b) 把指令当普通文字,接一个换行 | 写了一个故事,但 100 条指令中第一句的形容词、动物、名字全对的:0 条 |
| (c) “提示工程”:用它熟悉的格式把故事开个头 | 100 个开头中,接下来一句正确地沿用了主角名字的:100 个 |
基座模型”知道”怎样写这些故事、怎样沿用名字——这是预训练学到的能力;它只是不知道”指令”意味着什么。SFT 要做的,是在”指令”和”已经会的能力”之间搭一座桥。
3.3 SFT 的学习曲线:预训练有多重要?
演示 3 用同样的 4000 条指令、同样的 400 步训练两个模型:
| 步数 | 从预训练模型出发 | 从随机初始化出发 |
|---|---|---|
| 100 | 4% | 0% |
| 200 | 95% | 0% |
| 400 | 100% | 29% |
从随机初始化出发的模型也学会了句式和”写完就停”,形容词、动物、爱好这些来自小词表的词也能照抄(都是 100%),唯独随机造出来的名字要逐个字母地复制,只有 29%——而这正是基座模型在预训练中练了几千个故事的能力。SFT 数据通常比预训练小几个数量级,它之所以有效,是因为能力主要来自预训练,SFT 只是”解锁”。
3.4 需要多少数据?
演示 4(都训练 400 步,从预训练模型出发):
| 不同指令的条数 | 按指令写的比例 |
|---|---|
| 16 | 0%(各项正确率只比瞎猜略高) |
| 256 | 84% |
| 4000 | 100% |
只有 16 条时,这 16 条在 400 步里被看了几百遍,模型却没学会一般的规律;几百条就已经相当不错——LIMA(Zhou et al. 2023)用 1000 条精心挑选的数据就做出了不错的助手。但指令越多样、要求越细,需要的数据越多(长尾)。
3.5 提示词要不要算进损失?
演示 5:两种做法”听指令”的能力都是 100%。但提示词也算进损失时,只给模型一个 <|user|>,50 次采样中它 50 次都自己编出了一条像样的指令(“Write a story about a kind dog named Lovinu who loves to read.”)——它学会了扮演用户;只对回答算损失的模型 0 次。标准做法是只对回答计算损失:模型不需要学”用户会说什么”,而且在很多数据里(例如带长文档的问答)提示词很长,会占掉大部分梯度。也有工作发现给提示词一个很小的权重有好处,这是一个可以调的超参数。
3.6 中期训练:把指令数据变成预训练数据
如果你有大量的算力和指令数据,想把指令微调”规模化”呢?直接在海量指令数据上做 SFT,模型可能会灾难性遗忘预训练学到的知识。一个越来越流行的思路:
- 在网页等预训练数据上预训练;
- 把指令数据混进预训练数据中(通常在训练后期、学习率衰减阶段,配合高质量数据);
- 最后做一轮真正的(但很短的)指令微调。
这就是中期训练(mid-training)或”两阶段训练”。这个配方在很多大模型公司里是常识,但很少写进论文;MiniCPM、JetMoE 等模型公开描述过它,如今大多数模型都在用。它和第 11 讲的 WSD 学习率调度(在衰减阶段换成高质量数据)、第 14 讲的数据混合是同一个思路。
4. 从模仿到优化
SFT 是模仿:拟合 p̂(y|x) ≈ p*(y|x),p* 是某个参考分布(示范数据)。
- 纯粹的生成建模视角;
- 需要从参考策略(人或更强的模型)那里拿到样本。
RLHF 是优化:找 p̂(y|x) 使得 max_p E_p[R(y, x)],R 是一个我们能衡量的奖励。
- 最大化一个可以衡量的奖励;
- 语言模型是策略,而不再是”某个分布的模型”。
为什么要优化?生成 - 验证差距(G-V gap)。人写出来的,未必是人最喜欢的。Zhang et al. 2023 在新闻摘要上发现,人们更喜欢语言模型写的摘要,甚至胜过专门请自由撰稿人写的参考摘要。判断哪个好,比自己写出最好的更容易——所以与其收集”最好的回答”,不如收集”哪个更好”的判断,再去优化它。
5. RLHF 的数据
5.1 成对比较
标准的设置:同一条指令,模型写两个(或多个)回答,标注者选出更好的那个。InstructGPT 的标注指南要求标注者从有帮助、真实、无害三个方面判断。
5.2 众包的难处
- 很难找到真正高质量、可以核验的标注者;
- 很难让他们真正去检查事实是否正确(检查比感觉”写得好不好”费力得多);
- 要提防标注者自己用 AI 来完成标注;
- 标注者的报酬差别很大,“专家标注”(请领域专家)正在快速增长;大规模数据收集也有伦理问题(劳动条件、心理伤害)。
5.3 标注者是谁,很重要
- Santurkar et al. 2023(“Whose Opinions Do Language Models Reflect?”):RLHF 之后的模型在观点上更接近某些特定人群;
- Hosking, Blunsom & Bartolo 2024:标注者会被回答的风格左右(例如自信的语气),即使内容有错。
5.4 在我们的玩具世界里
02_reward_model.py 让 SFT 模型对 2000 条新指令各写两个回答(温度 1),由模拟的标注者比较。标注者大体认同用户,但偏爱长回答:心里的分数 = 真实奖励 + 每多一句 0.8 分(用户是每多一句扣 0.4 分,所以标注者净偏好每句 +0.4)。标注者按 Bradley–Terry 模型做选择:分数差距小的时候接近抛硬币。
- 被选中的回答更长的有 821 对,更短的只有 483 对;
- 在真实奖励有高低之分的 1857 对里,标注者选中”真实奖励更高”那个的比例只有 63%;
- 即使完全知道标注者心里的分数,也只能预测对约 68% 的标注——这是任何奖励模型的上限。
演示 4 模拟了两个口味相反的标注者群体(一群喜欢海滩、一群喜欢集市):同一群人的两位标注者对同一对回答的判断一致率只有 61%,不同群体之间只有 46%。奖励模型最终学到的,是”数据里那些标注者”的平均口味。
5.5 用大模型当标注者
GPT-4 是一个出奇好的成对比较者:和人类的一致率接近人类标注者之间的一致率,系统层面的排名几乎完全一致(AlpacaFarm 等)。所以前沿实践中AI 反馈用得很多:UltraFeedback 数据集(用 GPT-4 对多个模型的回答打分)被 Zephyr、Tulu 3、OLMo 等使用。Constitutional AI(Bai et al. 2022)更进一步:让模型按照一组原则(“宪法”)自我批评、自我修改,生成偏好数据。
5.6 长度效应
长度是 RLHF 最显著的副作用之一:RLHF 之后回答普遍变长,而且奖励的提升有很大一部分来自长度(Singhal et al. 2024,“A Long Way to Go”;Chen et al. 2024)。我们的实验会一再看到这一点。
6. 奖励模型
Bradley–Terry 模型(第 12 讲 Chatbot Arena 用的也是它):
训练损失:, 是被选中的回答, 是被拒绝的。
结构(InstructGPT 的做法):用 SFT 模型初始化一个 Transformer,去掉输出层,读最后一个 token 的隐藏状态,经过一个线性层输出一个分数。用 SFT 模型初始化,是因为它已经”读得懂”这些回答了。
02_reward_model.py 演示 2、3(在 1600 对上训练,394 对上测试):
- 和标注者的一致率 66%(对照:“完全知道标注者心思”的预测者在这些测试对上是 72%)。看起来不高,但 InstructGPT 报告标注者之间的一致率也只有约 73%——偏好数据天生很吵;
- 有意思的是,奖励模型选中”真实奖励更高”那个的比例(71%)高于标注者本人(66%):它学到的是 1600 次标注的平均偏好,单次标注的随机噪声被平均掉了——但标注者共同的偏差(偏爱长回答)平均不掉:
| 句数 | 奖励模型平均分 | 真实奖励平均 |
|---|---|---|
| 2 | 0.63 | 2.02 |
| 3 | 0.80 | 1.60 |
| 4 | 1.48 | 1.24 |
- 地点的口味学得不错(口味与奖励模型平均分的相关系数 0.89);
- 但对单个回答,尤其是训练数据里很少见的回答,打分可能很离谱:一个名字写错了的回答(用户眼里完全不合格,真实奖励 0)得 1.72 分,正确的 2 句回答才 1.99 分;地点换成没见过的 “moon”(用户无所谓,真实奖励 2)只得 0.38 分。
奖励模型只在”SFT 模型会写出来的那些回答”附近是准的。一旦策略被优化得偏离这个范围,它就不再可信——这是第 8 节”过度优化”的根源。
7. 怎样优化:PPO 与 DPO
7.1 RLHF 的目标
KL 项让策略别离参考模型(SFT 模型)太远——既是为了不让奖励模型”失效”,也是为了保住 SFT 模型的其他能力。
7.2 PPO(简要)
InstructGPT 用 PPO 优化这个目标。概念上的三步(第 16 讲细讲):
- 策略梯度:——但方差太大;
- TRPO:在当前策略附近把问题线性化,加一个 KL 约束;
- PPO:把概率比值裁剪在 [1-ε, 1+ε] 之内。
这个公式看起来人畜无害,但实现起来非常”挑剔”:要采样、要训练价值模型、要调很多超参数。
7.3 能不能不做强化学习?
很多人想过绕开 PPO 的办法:
- 带控制 token 的 SFT:被选中的回答前加 [GOOD],被拒绝的加 [BAD],推理时用 [GOOD];
- 只在被选中的回答上做 SFT;
- 训练奖励模型,采样很多回答,只在最好的上做 SFT(“专家迭代”);
- 训练奖励模型,采样 1024 个回答,交出最好的那个(best-of-n,第 8 节)。
7.4 DPO:没有眼泪的 RLHF?
DPO(Rafailov et al. 2023)想同时去掉奖励模型和所有”在线”的东西(采样、外层循环),代之以:在好回答上做对数损失的梯度上升,在坏回答上做(适当加权的)梯度下降。
推导:
- 非参数假设:假设 π 可以是任意分布,RLHF 目标有闭式解
- 解出”隐式奖励”:
- 代入 Bradley–Terry:两个回答的奖励相减时, 抵消了:
- 最大化偏好数据的似然,就得到 DPO 损失:
关键的三步:(1) 非参数假设把 π 和 r 用闭式联系起来;(2) 用策略来参数化奖励;(3) 用监督学习的损失优化奖励(也就优化了策略)。概念上:在非参数假设和换一种参数化之下,对成对奖励做最大似然估计。(Kimi k1.5 的强化学习算法用的也是这种等价关系,第 16 讲。)
梯度:“好的那个正梯度,坏的那个负梯度”,按隐式奖励模型的”预测误差” 加权。
03_dpo.py 演示 1 在一个只有 5 个回答的小例子上验证了每一步:闭式解 π* 的目标函数值(1.3452)比随机尝试的 1000 个其他策略都高(最好的 1.3077);隐式奖励 恰好等于 ;只用 DPO 损失从偏好概率中学出的策略,和 π* 的最大差距只有 1e-4。
变体:变体非常多,Tulu 3 论文里值得一提的两个是 SimPO(不要参考模型)和长度归一化的 DPO(用 log π(y)/|y| 代替 log π(y),抑制长度增长)。
DPO 在开源模型里:Llama 3 等使用”DPO + 专家迭代”的组合做后训练。
PPO 还是 DPO? 也有结果显示 PPO 做得更好(Ivison et al. 2024)。强化学习相关的实证结果高度依赖于具体的实验设置。
7.5 在故事助手上做 DPO
03_dpo.py 演示 2:在 1570 对偏好数据上做 DPO(学习率 3e-5,400 步),每个评估点让策略回答 200 条新指令各 2 次:
| β | 步数 | 真实奖励 | 按指令写 | 平均句数 | KL | 地点熵 | 海滩 | 偏好准确率 |
|---|---|---|---|---|---|---|---|---|
| — | 0(SFT) | 1.54 | 98% | 2.98 | 0.00 | 2.10 | 12% | — |
| 0.5 | 50 | 1.49 | 98% | 3.40 | 0.14 | 2.07 | 15% | 65% |
| 0.5 | 300 | 1.78 | 95% | 3.48 | 1.10 | 1.74 | 34% | 68% |
| 0.5 | 400 | 1.74 | 94% | 3.65 | 1.74 | 1.66 | 40% | 69% |
| 0.02 | 200 | 1.45 | 92% | 3.98 | 1.84 | 1.83 | 26% | 67% |
| 0.02 | 300 | 0.43 | 48% | 4.15 | 18.11 | 1.41 | 33% | 66% |
| 0.02 | 400 | -0.34 | 16% | 4.00 | 51.66 | 0.64 | 22% | 70% |
| 只在被选中的回答上 SFT | 400 | 1.59 | 98% | 3.17 | 0.17 | 2.06 | 15% | 69% |
读这张表:
- 最先学到的是长度:第 50 步,回答就从 2.98 句变成 3.40 句,真实奖励反而从 1.54 降到 1.49。长度是最容易学的”捷径”;
- β = 0.5:之后慢慢学到了地点的口味(海滩从 12% 升到 40%),真实奖励在第 300 步达到 1.78,KL 只有 1.10;
- β = 0.02(约束很弱):前 200 步和 β = 0.5 差不多,之后急剧恶化——KL 达到 51.7,按指令写的只剩 16%,真实奖励跌到 -0.34,大部分回答已经写坏了(最常见的”地点”是解析不出来);
- 最危险的是:β = 0.02 的训练指标(偏好准确率 70%)看起来一切正常,模型却已经坏掉了。只看训练损失和偏好准确率,是发现不了的;
- 被选中和被拒绝的回答,对数概率都在下降(β = 0.5 在第 400 步:-0.79 和 -1.76),只是被拒绝的降得更多。DPO 只关心两者的差,概率质量被挪到了别的地方——包括数据里没有的、坏掉的回答;
- 只在被选中的回答上 SFT:KL 只有 0.17,真实奖励 1.59,几乎没变——它不知道”坏回答坏在哪里”。
另外,DPO 对学习率很敏感:这里用 1e-4 时,真实奖励和 KL 会剧烈震荡;3e-5 就平稳得多(大模型的 DPO 常用 5e-7 这样小得多的学习率)。
8. 要小心的事
8.1 过度优化
Gao et al. 2023(“Scaling Laws for Reward Model Overoptimization”):用一个代理奖励模型去优化时,代理分数一路上升,而”真实”奖励先升后降。这对各种 RLHF 式的优化器都成立;对人类偏好、带噪声的 AI 偏好都会过拟合,只有无噪声的 AI 偏好(奖励本身就是要优化的目标)不会(AlpacaFarm 的结果)。这就是 Goodhart 定律:“一个指标一旦变成优化目标,就不再是好的指标。”
Best-of-n(拒绝采样)是最简单的”优化”:写 n 个回答,交出奖励模型打分最高的。它和原来的 SFT 模型之间的 KL 有一个上界:
04_best_of_n.py(100 条指令,每条 64 个回答;用精确的组合公式计算期望,没有模拟误差):
| n | KL 上界 | 代理分数 | 真实奖励 | 平均句数 | 海滩 | 如果用真实奖励挑 |
|---|---|---|---|---|---|---|
| 1 | 0.00 | 0.91 | 1.60 | 2.96 | 13% | 1.60 |
| 4 | 0.64 | 1.94 | 1.95 | 3.25 | 36% | 2.32 |
| 16 | 1.84 | 2.62 | 2.18 | 3.48 | 71% | 2.76 |
| 64 | 3.17 | 2.99 | 2.28 | 3.62 | 93% | 2.99 |
- 代理分数一路上升(0.91 → 2.99);
- 真实奖励也在上升,但越来越慢:n 每翻一倍,依次增加 +0.18、+0.17、+0.13、+0.10、+0.07、+0.03;
- “用代理挑”和”用真实奖励挑”的差距从 0.23 拉大到 0.71:优化的力度越大,代理的误差被利用得越多;
- 被挑中的回答越来越长(2.96 → 3.62 句):奖励模型的长度偏好被放大了;它也挑出了更多海滩——奖励模型对的地方同样被放大。
Best-of-n 是一种很”温和”的优化(KL ≤ 3.2 nat,只能在 SFT 模型会写的回答里挑),所以真实奖励还没有开始下降;而 DPO 在 β 很小时 KL 能到几十,模型就被”优化坏”了(7.5 节)。
应对办法:KL 约束(β)、提前停止、更好更大的奖励模型、定期在新策略的回答上重新收集偏好数据——以及,如果任务允许,换成可以验证的奖励(第 16 讲)。
8.2 模式坍缩与校准
RLHF 之后的模型不再是”概率模型”:它的输出分布变尖、变单一(我们的实验里地点熵从 2.10 降到 0.64),默认情况下不再校准——GPT-4 技术报告显示,预训练模型对选择题答案的置信度和正确率吻合得很好,RLHF 之后明显过度自信。需要多样性(例如生成多种写法、做合成数据)或需要概率(例如置信度估计)时,要小心使用 RLHF 之后的模型。
9. 小结
SFT:
- 指令数据从”改写的 NLP 数据集”演变为”长而详细的对话”,再到”工具调用与智能体轨迹”;
- SFT 最擅长提取预训练已有的行为(我们的实验:预训练模型 400 步 100%,随机初始化 29%);少量数据就很有效,长尾需要更多;
- 在模型不知道的知识上微调可能增加幻觉;少量安全数据作用很大;
- 中期训练把指令数据混进预训练,以扩大规模、避免遗忘。
RLHF:
- RLHF 数据的收集同样困难:噪声、标注者是谁、长度等混杂因素;
- RLHF 算法比 SFT 复杂——尤其是 PPO;DPO 用一个巧妙的推导把它变回了监督学习;
- 要警惕对奖励的(过度)优化:代理指标会被”钻空子”,训练指标可能看不出来。
10. 与作业 5 的关系
CS336 的作业 5 关于”对齐”:主体是在数学推理任务上做 SFT、专家迭代和 GRPO(第 16 讲),往届还有关于指令微调与 DPO 的补充部分(以当年的作业说明为准)。本讲的代码对应其中的:
- 对话模板与损失掩码:
posttrain.pack_right、masked_lm_loss(作业里对应”只对回答计算损失”的 SFT); - 批量生成与回答的对数概率:
posttrain.generate、response_logprobs(作业里用 vLLM 生成,这里用第 10 讲的 KV 缓存思路自己写); - DPO 损失:
03_dpo.train_dpo。
11. 练习
练习 1(损失掩码):一条 SFT 数据,提示词 300 个 token、回答 50 个 token。如果提示词也算进损失,梯度中有多大比例来自提示词?这会带来什么问题?
参考答案
300 / 350 ≈ 86%。模型的大部分”学习力”花在了预测用户会说什么上(它会学会扮演用户,见演示 5),真正要学的”怎样回答”反而只占一小部分梯度。只对回答计算损失时,100% 的梯度都用在回答上。
练习 2(SFT 与知识):你想让助手回答”某公司 2025 年的营收是多少”这类问题。你收集了 1 万条这样的问答做 SFT,其中很多事实模型在预训练中从未见过。可能出什么问题?你会怎么做?
参考答案
模型学到的主要是”被问到数字时就给出一个具体、自信的数字”,对它不知道的公司,就会编造(幻觉)。更好的做法:让 SFT 数据只包含模型已知的事实(或者在不知道时示范”我不确定”);需要新知识时用检索(RAG)把事实放进上下文;或者用”对 / 错”式的奖励(事实核查)做强化学习,惩罚编造。
练习 3(Bradley–Terry):奖励模型给回答 A 打 1.5 分、B 打 0.5 分。按 Bradley–Terry 模型,A 被选中的概率是多少?如果给所有回答的分数都加 10,概率会变吗?这对 DPO 意味着什么?
参考答案
σ(1.5 - 0.5) = σ(1) ≈ 0.73。整体加常数不改变概率——Bradley–Terry 只看分数差。这正是 DPO 推导中 β log Z(x) 能被消掉的原因:隐式奖励只确定到”每条提示词一个常数”的程度,而成对比较对这个常数不敏感。
练习 4(DPO 的推导):在 03 号文件演示 1 的例子里(π_ref = [0.40, 0.25, 0.15, 0.12, 0.08],r = [0, 1, 2, -1, 3]),把 β 从 1 改成 0.1 和 10,π* 会怎样变化?直观地解释 β 的作用。
参考答案
π* ∝ π_ref·exp(r/β)。β = 0.1:exp(r/0.1) 让奖励最高的第 5 个回答(r = 3)几乎独占全部概率(π* ≈ [0, 0, 0, 0, 1])——追求奖励、不在乎 KL;β = 10:exp(r/10) 变化很小,π* ≈ π_ref——几乎不动。β 是”奖励”和”别离参考模型太远”之间的汇率:β 越小,越激进(03 号文件中 β = 0.02 的模型被优化坏了)。
练习 5(为什么两个对数概率都下降):DPO 训练中,被选中和被拒绝的回答的对数概率常常都在下降。为什么这不违反 DPO 的目标?这可能带来什么风险?
参考答案
DPO 只要求 Δ_w - Δ_l 变大(被选中的相对上升、被拒绝的相对下降),不要求 Δ_w 本身为正。两个回答往往有大量相同的部分(同样的开头、同样的名字),压低被拒绝回答的梯度也会压低这些共同的 token;于是两者都下降,只是被拒绝的降得更多。风险:概率质量流向了偏好数据里没有的回答——可能是好的,也可能是坏掉的(β = 0.02 时按指令写的比例降到 16%)。
练习 6(Best-of-n 的 KL):best-of-n 的 KL 上界是 log n - (n-1)/n。算一算 n = 2、16、1000 时的值。如果想要 KL = 10 nat 的”优化力度”,best-of-n 需要多大的 n?这说明了什么?
参考答案
n = 2:0.69 - 0.5 = 0.19;n = 16:2.77 - 0.94 = 1.84;n = 1000:6.91 - 1.0 = 5.91。KL = 10 需要 log n ≈ 11,n ≈ e^11 ≈ 6 万个样本——代价随 KL 指数增长。所以 best-of-n 只适合”温和”的优化;要走得更远,就得训练策略(PPO、DPO),而那样也更容易过度优化。
练习 7(动手):
(a) 在 story_chat.py 中把 ANNOTATOR_LENGTH_BONUS 改成 0(标注者不再偏爱长回答),删掉 checkpoints/ 中的偏好数据和奖励模型缓存,重新运行 02、03、04 号文件:DPO 还会让回答变长吗?best-of-n 的真实奖励和代理分数的差距呢?
(b) 在 03_dpo.py 中实现长度归一化的 DPO(把序列的对数概率除以回答长度),与标准 DPO 比较回答长度。
(c) 在 01_chat_template_sft.py 中把 SFT 的指令模板减少到只有 1 种说法,训练后用另外 3 种说法测试。
12. 延伸阅读
- CS336 Spring 2026 Lecture 15 幻灯片(
stanford-cs336/lectures中的lecture_15.pdf)。 - Ouyang et al.,Training Language Models to Follow Instructions with Human Feedback(2022,InstructGPT);Stiennon et al.,Learning to Summarize from Human Feedback(2020)。
- 指令数据:Wei et al.(2021,FLAN);Wang et al.,Self-Instruct(2022);Taori et al.(2023,Alpaca);Köpf et al.(2023,OpenAssistant);Lambert et al.(2024,Tulu 3);Zhou et al.,LIMA: Less Is More for Alignment(2023);Wang et al.,How Far Can Camels Go?(2023)。
- 知识与幻觉:Gekhman et al.,Does Fine-Tuning LLMs on New Knowledge Encourage Hallucinations?(2024)。
- 安全:Bianchi et al.,Safety-Tuned LLaMAs(2024);Bai et al.(2022,Anthropic HH;Constitutional AI)。
- 偏好数据:Santurkar et al.,Whose Opinions Do Language Models Reflect?(2023);Hosking, Blunsom & Bartolo,Human Feedback is not Gold Standard(2024);Dubois et al.(2023,AlpacaFarm);Singhal et al.,A Long Way to Go(2024);Zhang et al.,Benchmarking Large Language Models for News Summarization(2023)。
- 优化:Schulman et al.(2017,PPO);Rafailov et al.,Direct Preference Optimization(2023);Meng et al.(2024,SimPO);Ivison et al.,Unpacking DPO and PPO(2024)。
- 过度优化:Gao et al.,Scaling Laws for Reward Model Overoptimization(2023)。
13. 下一讲预告
RLHF 的根本限制是:奖励来自一个学出来的、会被”钻空子”的奖励模型,所以没法放开手脚去优化。如果奖励是可以验证的呢?——数学题有标准答案,代码有测试用例。下一讲(RLVR:可验证奖励的强化学习):
- PPO 的实现细节,以及为什么大家转向了更简单的 GRPO;
- GRPO 的偏差(标准差归一化、长度归一化)与 Dr. GRPO 的修正;
- 案例:DeepSeek-R1(R1-Zero 的”顿悟时刻”、蒸馏)、Kimi k1.5(长度惩罚、课程学习、强化学习基础设施)、Qwen3(思考模式融合)、智能体强化学习;
- 在一个心算任务上亲手训练:模型会自己发现”先想后答”更好。
下一讲之前,建议你:跑通 code/lecture15/ 下的 4 个脚本,完成练习 1、3、4、6。