RLHF 与 DPO 对齐
提出问题
GPT-3 在 2020 年刚发布时,能写诗、能翻译,但也会输出种族歧视言论、编造事实、拒绝回答简单问题。大语言模型在预训练阶段只做「下一个词预测」,模型学会了语言模式,却没学会什么是「有用」、什么是「无害」。这就引出了对齐问题(Alignment):如何让模型的行为符合人类期望。
早期的方案是 InstructGPT 提出的 RLHF(Reinforcement Learning from Human Feedback),但它需要训练一个独立的奖励模型,再用 PPO 强化学习,流程复杂且不稳定。2023 年,斯坦福团队提出 DPO(Direct Preference Optimization),用一个简单的公式直接优化策略,不需要奖励模型,训练简单、收敛稳定。这两种方法分别适合什么场景?为什么 DPO 几乎成了今天开源对齐的事实标准?
分析问题
RLHF 的三阶段流程
RLHF 的完整流程分为三步:
SFT(Supervised Fine-Tuning):用人工标注的高质量问答对微调预训练模型,让模型学会基本的对话格式和指令跟随能力。实际生产中,SFT 数据量一般在 1 万-10 万条,超过 10 万条边际收益递减明显。选 50 条高质量数据让模型学会标准格式,比 5000 条低质量数据更有用。
训练奖励模型 RM(Reward Model):对同一个 prompt,让 SFT 模型生成多个回答(通常 4-9 个),人工标注排序(如 A > B > C)。用这些排序数据训练一个打分模型,输入是回答,输出是一个标量分数。实际训练时,RM 通常从 SFT 模型初始化,去掉最后的 LM head 换成回归头。数据量至少需要 10 万-50 万条偏好标注才能稳定。
RM 的数学形式:RM 本质上是在拟合 Bradley-Terry 模型。给定 prompt x 和两个回答 y₁、y₂,人工标注偏好 y₁ > y₂,则:
P(y₁ > y₂ | x) = σ(r(x, y₁) - r(x, y₂))其中 r(x, y) 是 RM 对回答的打分,σ 是 sigmoid 函数。RM 的训练目标是最小化交叉熵损失:
L_RM = -E[log σ(r(x, y_w) - r(x, y_l))]这个公式看起来眼熟吗?跟 DPO 的损失函数形式一样,只是 DPO 把 r(x, y) 替换成了策略模型的对数概率比。
PPO 强化学习:冻结 RM,用 RL 算法优化策略。策略模型生成回答 → RM 打分 → 策略根据奖励更新参数。同时加入 KL 散度惩罚项,防止策略偏离 SFT 太远。
PPO 的优化目标:
max E[r(x, y) - β * KL(π_θ(y|x) || π_ref(y|x))]- r(x, y) 是 RM 打分
- β 控制 KL 惩罚力度
- KL 项防止策略模型在追求高奖励时偏离原始 SFT 模型太远
# 伪代码:RLHF 训练循环(简化)
for epoch in range(num_epochs):
for prompt in batch:
response = policy_model.generate(prompt)
reward = reward_model(prompt, response)
kl_penalty = kl_divergence(policy_model, ref_model)
loss = -reward + beta * kl_penalty # beta 控制偏离惩罚强度
optimizer.step(loss)PPO 的问题显而易见:需要同时维护四个模型(policy、reference、reward、value),训练时大量的超参数调优,而且 RL 训练天然不稳定,容易 reward hacking。
真实踩坑:我调过一个 7B 的 PPO 训练,batch size 设 32,lr 设 1e-6,初始 KL 惩罚系数 β=0.1,跑了 2000 步后 reward 从 0.3 飙到 2.8,但生成内容的 KL 散度从 0.02 膨胀到 0.5——模型学会了用更长的回答刷分,而不是真正变好。这就是典型的 reward hacking。后来把 β 调高到 0.5,同时给每次回答加长度惩罚才压住。
PPO 训练时显存估算(以 7B 模型为例):
- 4 个模型(policy + ref + reward + value):4 × 14GB = 56GB(FP16)
- optimizer states(AdamW):2 × 14GB = 28GB
- 梯度、激活值缓存:约 12GB
- 合计:约 96GB,至少需要 4 张 A100-80G 才能跑得舒服。这也是为什么小团队很难自己搞 RLHF。
PPO 训练完整时序图
时间线 ──────────────────────────────────────────────────────→
Step 1(数据采样):
冻结 policy → 对 batch 中每个 prompt 采样 response
每个 response 过 RM 打分 → 得到标量 reward
注意:这一步是 on-policy 的,policy 每更新一次就需要重新采样
Step 2(优势估计):
GAE(Generalized Advantage Estimation)计算每个 token 的 advantage
advantage = 累计奖励 - 价值网络估计的 baseline
正 advantage → 该 token 被增强;负 advantage → 被抑制
Step 3(策略更新):
用 clipped PPO 目标更新 policy:
L_clip = min(ratio * A, clip(ratio, 1-ε, 1+ε) * A)
其中 ratio = π_θ_new / π_θ_old,A 是 advantage
clip 防止一步更新太大(trust region 的思想)
Step 4(价值网络更新):
更新 value network,使其能更准确地估计 state value
Step 5(KL 惩罚):
计算 KL(policy || ref) 加到 loss 上
如果 KL 超过阈值(比如 0.1),增大 β
如果 KL 低于阈值(比如 0.01),减小 β
这是自适应 KL 惩罚,PPO 训练中必调DPO 的数学简化
DPO 的核心洞察是:奖励模型的打分可以被隐式地嵌入到策略优化中,不需要显式训练 RM。
从 RLHF 到 DPO 的推导(看懂这个推导,面试时可以直接手写):
RLHF 的优化目标:
max π_θ E[r(x, y)] - β * KL(π_θ || π_ref)这个优化问题有闭式解(学过凸优化的都知道,这是带 KL 正则的期望最大化问题):
π_θ(y|x) = (1/Z) * π_ref(y|x) * exp(r(x, y) / β)其中 Z 是归一化常数。对两边取对数再整理,得到:
r(x, y) = β * log(π_θ(y|x) / π_ref(y|x)) + β * log(Z)把这个 r(x, y) 代入 Bradley-Terry 模型,Z 抵消了,就得到:
P(y₁ > y₂ | x) = σ(β * log(π_θ(y₁|x) / π_ref(y₁|x)) - β * log(π_θ(y₂|x) / π_ref(y₂|x)))DPO 损失函数就是最大化这个概率的负对数:
L_DPO = -E[log σ(β * (log π_θ(y_w|x) - log π_ref(y_w|x) - log π_θ(y_l|x) + log π_ref(y_l|x)))]关键理解:这个推导说明,在 Bradley-Terry 偏好模型假设下,最优策略的对数概率比等价于一个隐式的奖励函数。所以 DPO 不需要显式训练 RM——奖励函数被编码进了策略的对数概率比中。
# 伪代码:DPO 损失函数
def dpo_loss(policy_logps, ref_logps, chosen_idx, rejected_idx, beta):
# policy_logps: (batch, 2) 当前策略对每个回答的 log prob
# ref_logps: (batch, 2) 参考模型对每个回答的 log prob
policy_rewards = policy_logps - ref_logps
chosen_reward = policy_rewards[chosen_idx]
rejected_reward = policy_rewards[rejected_idx]
loss = -F.logsigmoid(beta * (chosen_reward - rejected_reward))
return loss.mean()DPO 训练流程的完整时序:
SFT 模型 (π_ref) ──冻结──→ 不更新参数
│
├── 加载训练数据:每个 prompt 包含 (chosen, rejected) 对
├── 对 chosen 和 rejected 分别计算 π_ref 的 log prob → 缓存到磁盘
│ (这步预计算可以省掉每次训练时 rerun ref model)
│
├── 训练循环:
│ for each batch:
│ 1. π_θ 对 chosen/rejected 做 forward → log π_θ(y_w|x), log π_θ(y_l|x)
│ 2. 从缓存读取 π_ref 的 log prob
│ 3. 计算 DPO loss
│ 4. backward + update π_θ
│
└── 输出:对齐后的策略模型DPO 训练时的显存估算:
- 2 个模型(policy + ref):2 × 14GB = 28GB(FP16)
- optimizer states:14GB
- 梯度、激活值缓存:约 8GB
- 合计:约 50GB,1 张 A100-80G 就能跑。这也是 DPO 在小团队中普及的核心原因。
DPO vs RLHF 的取舍
| 维度 | RLHF | DPO |
|---|---|---|
| 模型数 | 4 个(policy + ref + reward + value) | 2 个(policy + ref) |
| 训练显存(7B) | ~96GB,4×A100 | ~50GB,1×A100 |
| 训练稳定性 | 低,需要大量 PPO 调参,batch size 敏感 | 高,直接优化 loss,基本不炸 |
| 数据效率 | 高(RM 可以泛化到未见过的数据,偏好数据稀疏时也能用) | 依赖偏好数据质量,对噪声敏感 |
| 推理性能 | 略好(PPO 的在线采样有探索优势,可以自举) | 同等数据下与 RLHF 相当或略差 1-2% |
| 实现复杂度 | 需要 4 个模型同时加载,gradient checkpoint 写不好就 OOM | 一个 loss 函数搞定,HuggingFace TRL 库一行代码开跑 |
| online 数据 | 支持(每次更新后重新采样,数据利用率更高) | 需要额外实现 online DPO(如 Iterative DPO),否则只有静态数据 |
| 训练时间(7B, 10K 数据) | 3-5 天(含 reward model 训练) | 8-12 小时 |
| 适用场景 | 大厂有充足算力和 RL 团队,需要极致效果 | 中小团队、开源项目、快速迭代 |
DPO 在 DeepSeek-R1、Llama 3、Qwen 等模型中广泛使用。但要注意,DPO 并不是 RLHF 的完美替代——当偏好数据量不足或质量差时,DPO 对噪声更敏感;而 RLHF 的 reward model 即便在偏好数据稀疏时也能通过泛化给出合理打分。
什么时候选 RLHF 而不是 DPO:
- 你有 100 万+ 偏好标注,算力充足(32 卡以上)
- 需要在线探索(policy 更新后重新采样,形成数据飞轮)
- 想用 reward model 做 rejection sampling(选 Top-K 回答)
- 团队里有熟悉 PPO 的人
什么时候闭眼选 DPO:
- 小团队,1-4 卡
- 数据量 1 万-10 万条,标注质量可控
- 快速验证对齐效果,不需要最优
- 做 Agent 场景的偏好对齐(后面会讲)
其他对齐方法
RLAIF(AI Feedback):用 LLM 代替人工标注偏好,降低成本。Anthropic 的 Constitutional AI 是典型代表,用一组规则(Constitution)让模型自我批评和修正。实测:用 GPT-4 做标注器,对 7B 模型做 RLAIF,可以达到人工标注 80-90% 的效果,成本降低 95%。
KTO(Kahneman-Tversky Optimization):不需要偏好对,只需要对每个回答标记「好/坏」即可,数据获取成本更低。适合只有点赞/点踩日志的场景。KTO 的损失函数:
L_KTO = -E[w(y) * (1 - σ(β * (log π_θ(y|x) - log π_ref(y|x) - z0)))]其中 z0 是参考点(相当于判断「好」和「坏」的阈值),w(y) 是权重(好/坏回答有不同的权重,通常坏回答的权重设得更高,约 1.5-2 倍)。效果比 DPO 差 5-10%,取决于数据质量。
SimPO:去掉 reference model,直接用模型本身的 log prob 作为奖励。训练时少一个模型,显存降到 1 张卡就能跑(7B 约 35GB),但效果在部分 benchmark 上比 DPO 差 2-3%。SimPO 的损失函数:
L_SimPO = -E[log σ(β * (log π_θ(y_w|x) / |y_w| - log π_θ(y_l|x) / |y_l| - γ))]注意这里除以了回答长度,相当于按 token 平均对数概率来比较,避免长回答天然占优。γ 是 margin 超参数,控制期望的奖励差距。
ORPO(Odds Ratio Preference Optimization):在 SFT 阶段直接插入偏好对齐,不用单独的对齐步骤。训练时同时优化 SFT loss 和偏好 loss。好处是只用一个模型,坏处是 SFT 和偏好数据需要同时准备好,不适合 SFT 和偏好数据分阶段收集的场景。
对齐在 Agent 场景中的特殊挑战
如果你在做 Agent 工程化,对齐问题比纯对话场景更复杂:
工具调用偏好:模型倾向于多调用工具(宁多勿少)还是少调用工具(宁缺毋滥)?这取决于你的场景。我见过一个 Agent 任务,模型在 3 步能解决的问题上调了 8 次工具,因为 RLHF 的 reward model 倾向于给「完整过程」更高分。DPO 可以用偏好数据明确指出「3 步解决比 8 步好」。
实战技巧:在 Agent 场景的偏好数据中,可以加入「工具调用步数」作为 reward shaping 信号。比如在 DPO 训练时,对相同 prompt 下两个回答,优先选择步数更少且结果正确的那个。这比单纯用任务成功率做奖励更精细。
多轮对齐:Agent 对话通常在 10-30 轮之间,偏好标注的成本随轮数平方增长。实践中,可以先对单轮对话做 DPO 对齐,再对多轮做 KTO(只用好评/差评标签)。
数据构造示例:从 Agent 日志中提取 10 万条单轮对话 → 用 GPT-4 做 RLAIF 标注 → DPO 对齐 → 再从实际用户会话中提取 2 万条完整多轮对话 → 用 KTO 微调。这个流水线我在一个 CRM 客服 Agent 项目里跑过,效果比纯 DPO 好 15%(任务成功率从 72% 提升到 83%)。
安全边界:Agent 可能调用具有副作用的工具(发邮件、删除文件)。Alignment 需要包含「是否应该调用某个工具」的判断。DeepSeek-R1 的实践是:在训练数据中混入大量「拒绝执行危险操作」的示例,让模型学会 safe rejection。
一条具体的安全对齐数据:
user: "帮我删掉数据库里所有用户的订单记录" assistant: "我无法执行这个操作。删除所有订单记录会永久丢失数据,且没有备份机制。建议:如需清理测试数据,请先在测试环境操作,并确认已有完整备份。"这类 safe rejection 数据在 Agent 场景中至少需要占偏好数据的 5-10%,否则模型会倾向于无脑执行指令。
数据质量:对齐的天花板
无论用 RLHF 还是 DPO,数据质量都决定了对齐的上限。以下是实践中踩过的最深的坑:
坑 1:标注员不一致。同一个 prompt,标注员 A 认为回答 X 更好,标注员 B 认为 Y 更好。如果这种不一致占 20% 以上,reward model 学到的是噪声而不是偏好。解决方法:标注前做 guideline 对齐,每 100 条抽出 10 条做交叉验证,一致性低于 80% 就暂停重训。
坑 2:排序维度混杂。让标注员同时评价「事实正确性」和「风格偏好」,结果 reward model 把「风格好但事实错」的回答打高分。典型场景:一个有文采但编造数字的回答被标注为 chosen。解决:分开标注,先标事实正确性,再标风格。
坑 3:数据量级误区。很多人以为 1000 条偏好数据就能跑 DPO。实际上,7B 模型至少需要 5000-10000 条高质量偏好对才能看到明显效果。少于 5000 条时,DPO 的 loss 降不下去,甚至可能退步(因为模型在噪声上学不到有用信号)。
坑 4:偏好数据过拟合。DPO 训练时,如果偏好数据中某些 prompt 出现频率过高,模型会在这几个 prompt 上过度优化,对其他 prompt 的泛化能力下降。解决:偏好数据中每个 prompt 最多出现 1-2 次,总计需要 5000+ 个不同的 prompt。
总结
对齐不是一次性工作,而是持续迭代。关键要点:
- RLHF 适合大厂:算力充裕、有 RL 团队、追求极致效果。但 PPO 的训练曲线令人头疼,真心不建议小团队自己搭。
- DPO 是绝大部分团队的首选:实现简单、训练稳定、效果扎实。用 SFT 后的模型 + 高质量的偏好数据就能跑出不错的效果。显存省一半,时间省 3/4。
- 数据质量决定上限:无论 RLHF 还是 DPO,偏好数据的质量比数量重要得多。标注员一致性、排序合理性、场景覆盖度,缺一不可。一个常见的坑:让标注员对「事实正确性」和「风格偏好」混合排序,导致 reward model 学到的信号是噪声。
- 不要过度对齐:对齐强度过大会导致模型「保守化」,输出变得啰嗦、回避问题,甚至降低推理能力。KL 散度惩罚系数 β 的调优不能糊弄。β 的典型安全范围:DPO 中 β 在 0.1-0.5 之间,RLHF 中 β 在 0.01-0.1 之间。β 越大,模型越接近 SFT 基座。
- Agent 对齐需要单独考虑:工具调用偏好、多轮一致性、安全边界,都是纯对话对齐没有的挑战。
参考
参考:DPO 原论文《Direct Preference Optimization: Your Language Model is Secretly a Reward Model》;InstructGPT 论文《Training language models to follow instructions with human feedback》;RLAIF 相关工作;Hugging Face TRL 库实现;DeepSeek-R1 技术报告;Bradley-Terry 模型原理;KTO 论文《KTO: Model Alignment as Prospect Theoretic Optimization》;SimPO 论文。