第17章:对齐训练
上一章我们完成了 SFT(Supervised Fine-Tuning,监督微调),模型已经学会了"按指令回答"的基本格式。但很快你会发现一个令人不安的问题:SFT 之后的模型仍然可能输出有害内容、捏造事实、或者说违心的话。
原因在于 SFT 只教会了模型模仿训练集的风格和格式,却没有教它什么是好的回答。模型并不真正理解"诚实"或"无害"的含义——它只是在拟合文本分布。
这就引出了本章的核心问题:如何让模型的输出真正符合人类的价值观和偏好?
17.1 RLHF 原理与 PPO 实现
基本思路:用人类反馈作为信号
RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)的核心思路很朴素:
- 让模型对同一个问题生成多个候选答案
- 让人类标注员对这些答案进行偏好排序(A 比 B 好)
- 训练一个奖励模型来学习人类的偏好判断
- 用强化学习让语言模型的输出向高奖励方向靠拢
奖励模型(Reward Model, RM)
奖励模型的任务是:给定一个问题 和一个回答 ,输出一个标量分数 ,表示这个回答有多好。
训练数据是成对的偏好样本 ,其中 是被人类偏好的回答(winner), 是较差的回答(loser)。
训练目标采用 Bradley-Terry 偏好模型:
直觉上:我们希望 ,两者差值越大越好,而 sigmoid 函数将差值转化为概率。
:::info 奖励模型的结构 通常将语言模型的最后一层替换为线性层,输出单个标量。奖励模型一般与被训练的语言模型大小相当或更大,以确保打分能力。 :::
PPO 算法:强化学习驱动的优化
有了奖励模型,下一步是用它来优化语言模型(称为 actor/policy)。PPO(Proximal Policy Optimization,近端策略优化)是目前最成熟的选择。
语言模型生成 token 的过程本质上是一个序列决策过程:
- 状态(state):当前已生成的 token 序列
- 动作(action):选择下一个 token(词表大小的离散空间)
- 奖励(reward):回答结束时由 RM 给出的分数
PPO 的核心目标:最大化期望奖励,同时约束每次更新步幅不能太大:
其中 是优势函数(Advantage function),衡量某个动作比平均水平好多少。
KL 散度惩罚:防止 Reward Hacking
一个严重问题:如果只优化 RM 的分数,模型会很快找到"走捷径"的方式——比如输出一堆看似流畅但毫无内容的废话,却恰好骗过了奖励模型。这种现象叫做 reward hacking(奖励黑客)。
解决方法:在奖励中加入 KL 散度惩罚,约束优化后的模型不能偏离 SFT 初始化太远:
其中 是 SFT 后的参考模型(冻结参数), 控制惩罚力度。KL 散度衡量两个分布之间的差异:
:::warning 实现的复杂性 完整的 RLHF-PPO 需要同时维护 4 个模型:
- Actor():被优化的语言模型,产生动作
- Critic():价值函数,估计状态的期望奖励
- Reference():SFT 模型,计算 KL 惩罚(冻结)
- Reward Model():打分模型(冻结)
这意味着在训练时需要 4 倍的显存,工程实现非常复杂。这直接催生了更简单的方法。 :::
17.2 DPO:直接偏好优化
核心洞见:RM 和最优策略之间的解析对应
2023 年,Stanford 的研究者发现了一个关键数学事实:在有 KL 约束的 RL 问题中,最优策略可以用奖励模型解析地表达出来:
其中 是归一化常数。
反过来,这意味着奖励可以用策略来表达:
直接优化偏好对
DPO(Direct Preference Optimization,直接偏好优化)的关键步骤:将上面的奖励表达式代入 Bradley-Terry 偏好模型, 会在 中相互抵消!
最终得到一个不需要显式奖励模型的损失函数:
直觉解释:
- :好答案相对于参考模型被"抬高"了多少
- :差答案相对于参考模型被"抬高"了多少
- DPO 要求:好答案被抬高的幅度 > 差答案被抬高的幅度
RLHF vs DPO 对比
| 维度 | RLHF + PPO | DPO |
|---|---|---|
| 模型数量 | 4 个(actor/critic/ref/RM) | 2 个(policy/ref) |
| 训练稳定性 | 较难,超参数敏感 | 稳定,接近监督学习 |
| 工程复杂度 | 极高 | 低 |
| 在线采样 | 支持(actor 持续生成新数据) | 不支持(离线数据集) |
| 效果 | 略优(特别是推理任务) | 接近,对话/无害性任务表现好 |
| 数据格式 | 偏好对即可 | 偏好对即可 |
# DPO 损失函数的核心实现(PyTorch 伪代码)
import torch
import torch.nn.functional as F
def dpo_loss(policy_logprobs_w, policy_logprobs_l,
ref_logprobs_w, ref_logprobs_l, beta=0.1):
"""
policy_logprobs_w: log π_θ(y_w|x)
policy_logprobs_l: log π_θ(y_l|x)
ref_logprobs_w: log π_ref(y_w|x)
ref_logprobs_l: log π_ref(y_l|x)
"""
log_ratio_w = policy_logprobs_w - ref_logprobs_w
log_ratio_l = policy_logprobs_l - ref_logprobs_l
logits = beta * (log_ratio_w - log_ratio_l)
loss = -F.logsigmoid(logits).mean()
return loss
:::tip DPO 的局限性 DPO 无法在线采样新数据——它只能在固定的偏好数据集上训练。而对于推理、数学等任务,我们往往希望模型能自己生成答案并从对错中学习。这个需求催生了 GRPO。 :::
17.3 GRPO 与推理模型训练
为什么需要新方法
数学解题和代码生成有一个 DPO 无法充分利用的特性:答案有明确的对错判断。
- 数学题:最终数值答案是否正确?
- 代码:能否通过单元测试?
- 逻辑推理:结论是否能从前提推出?
这些任务不需要人类标注员来判断好坏,可以用程序自动验证。更重要的是,我们可以实时生成数据——让模型对同一道题生成 个答案,检验对错,然后立即用这些数据来训练。
GRPO 算法
GRPO(Group Relative Policy Optimization,组内相对策略优化)由 DeepSeek 团队提出。
核心步骤:
- 对同一问题 ,用当前策略采样 个答案
- 用验证函数给每个答案打分:
- 组内归一化计算优势:
- 用归一化优势作为信号更新策略,同时保持 KL 约束
与 PPO 的关键区别:
GRPO 不需要 Critic 网络。PPO 的优势函数 依赖 Critic 来估计状态价值,而 GRPO 直接用组内相对奖励代替——同一批答案中,对的答案获得正优势,错的答案获得负优势。这将模型数量从 4 个减少到 2 个(policy + reference)。
:::info 可验证奖励的设计
典型的可验证奖励(Verifiable Reward)设计:
| 任务类型 | 奖励信号 |
|---|---|
| 数学解题 | 答案数值是否正确(+1/0) |
| 代码生成 | 测试用例通过数 / 总用例数 |
| 格式遵从 | 是否符合要求的输出格式 |
| 逻辑推理 | 结论是否从前提合法推出 |
奖励函数完全由程序判定,不依赖任何人工标注,因此可以无限扩展训练数据。 :::
17.4 o1 / R1 的慢思考范式
两种思维模式
心理学家 Kahneman 将人类思维分为两种:
- System 1(快思考):直觉、自动、快速
- System 2(慢思考):逻辑、审慎、耗时
传统语言模型类似 System 1——看到问题直接生成答案,没有中间推理过程。而 o1/R1 等推理模型模拟 System 2:先生成一段思维链(Chain-of-Thought),再给出最终答案。
Test-Time Compute:想得越久,答得越好
一个关键发现:给模型更多"思考时间"(即更长的推理 token 预算)可以显著提升答题质量。
这种现象被称为 Test-Time Compute Scaling(测试时计算扩展)。与训练时扩展(更大模型、更多数据)不同,它在推理阶段投入计算资源:
实验表明,一个较小的推理模型在足够长的思维链下,可以超越更大的直接回答模型。
DeepSeek-R1:纯 RL 训练出推理行为
DeepSeek-R1 的重要发现:不需要人工标注思维链,通过纯 RL 训练,模型可以自发学会推理行为。
训练流程:
- 以 SFT 模型为起点
- 用 GRPO 在大量数学/代码题上训练(使用可验证奖励)
- 只要求最终答案正确,不约束中间推理过程
- 模型自然涌现出"先思考、再回答"的行为
:::info 涌现的推理行为
在训练过程中,DeepSeek-R1 自发出现了以下行为,这些行为从未被人工标注:
- 自我反思(Self-reflection):发现推理有误后主动回溯,例如"等等,我之前的计算似乎有问题……"
- 验证(Verification):生成答案后自我检验,例如"让我验证一下这个结果是否代入原方程成立"
- 多路径探索:尝试不同解法,比较哪种更简洁
这些行为的涌现说明:当奖励信号足够明确、训练数据足够丰富时,模型可以自己发现"思考"比"直接猜"更有效。 :::
R1 训练的关键设计
| 设计要素 | 说明 |
|---|---|
| 奖励来源 | 可验证任务(数学/代码),程序自动判断对错 |
| 优化算法 | GRPO,无需 Critic 网络,工程效率高 |
| 思维链格式 | 使用 <think>...</think> 标记区分推理和答案 |
| 格式奖励 | 额外奖励正确使用 <think> 标签的输出 |
| 数据扩展 | 强模型生成思维链 → 蒸馏训练小模型(R1-Distill) |
# R1 典型输出格式
用户:计算 √(2 + √(2 + √2)) 的近似值
助手:<think>
让我逐层计算。
最内层:√2 ≈ 1.4142
中间层:√(2 + 1.4142) = √3.4142 ≈ 1.8478
最外层:√(2 + 1.8478) = √3.8478 ≈ 1.9616
等等,让我验证:1.9616² ≈ 3.8479 ✓
</think>
√(2 + √(2 + √2)) ≈ **1.9616**
本章小结
| 方法 | 核心思路 | 模型数量 | 数据需求 | 适用场景 |
|---|---|---|---|---|
| RLHF + PPO | 训练 RM,用 RL 优化策略 | 4 | 人工偏好标注 | 通用对话,无害性 |
| DPO | 将 RM 消去,直接优化偏好对 | 2 | 人工偏好标注 | 对话,无害性,简单偏好 |
| GRPO | 组内相对奖励,无需 Critic | 2 | 可验证任务(自动) | 数学,代码,推理 |
| GRPO + CoT | 纯 RL 涌现推理链 | 2 | 可验证任务(自动) | 复杂推理,慢思考模型 |
对齐训练的演进逻辑:RLHF 确立了用人类偏好优化模型的框架 → DPO 简化了实现,降低了工程门槛 → GRPO 利用可验证奖励摆脱了人工标注的瓶颈 → 慢思考范式开辟了"推理时扩展"这一全新的能力维度。
下一章我们将离开训练阶段,转向推理加速:当模型训练完成后,如何让它更快、更省地服务大量用户请求?这涉及 KV Cache 优化、量化、推测解码等一系列系统技术。