DPO:直接偏好优化 本节摘要:RLHF 有效,但要训三个模型(SFT、奖励、策略)、管 PPO 的不稳定、调 KL 惩罚。DPO 问:能不能跳过这一切?直接在偏好对上优化语言模型,无需奖励模型,无需 PPO,一个训练循环,效果相当。2023 年 5 月 Stanford 的 Rafailov 等人证明了「你的语言模型暗地里就是个奖励模型」——最优奖励函数由模型自身的 token 概率数学决定。本节带你推导 DPO 损失,从零实现,对比 RLHF,并介绍 DPO 启发的简化对齐家族(KTO、ORPO、SimPO),每一代都再砍掉一块复杂度。 学习目标 阅读完本节,你应当能够: 实现 DPO 训练,无需独立奖励模型直接在偏好对上优化语言模型。
本节摘要:RLHF 有效,但要训三个模型(SFT、奖励、策略)、管 PPO 的不稳定、调 KL 惩罚。DPO 问:能不能跳过这一切?直接在偏好对上优化语言模型,无需奖励模型,无需 PPO,一个训练循环,效果相当。2023 年 5 月 Stanford 的 Rafailov 等人证明了「你的语言模型暗地里就是个奖励模型」——最优奖励函数由模型自身的 token 概率数学决定。本节带你推导 DPO 损失,从零实现,对比 RLHF,并介绍 DPO 启发的简化对齐家族(KTO、ORPO、SimPO),每一代都再砍掉一块复杂度。
阅读完本节,你应当能够:
你在第 07 节搭了 RLHF 流水线。三阶段、三模型:SFT、奖励、用 PPO 优化的策略。光奖励模型就要数千人类偏好对和单独训练循环。PPO 要仔细调 KL 系数、学习率、裁剪比、轮数。
实践中 PPO 训练以不稳定著称——小超参变动就发散。奖励模型是人类偏好的不完美代理,策略会找办法利用它的弱点。KL 惩罚有用但要自己调(太低奖励黑客,太高模型几乎不学)。这种复杂度正是 InstructGPT 发表后多年里多数开源模型搞不定 RLHF 的原因——三阶段流水线脆弱,每阶段各有失败模式,错误叠加。
2023 年 5 月,Rafailov、Sharma 与 Stanford 同事发表《直接偏好优化:你的语言模型暗地里就是个奖励模型》。关键洞见:你不需要单独的奖励模型。最优奖励函数在数学上由语言模型自身的 token 概率决定,可以完全跳过奖励模型,直接在偏好对上优化语言模型。DPO 把 RLHF 降为单步监督学习——一个模型、一个损失、一个循环,无强化学习。Zephyr-7B(首批大规模用 DPO 的模型之一)在多个基准上匹配或超越全 RLHF 训练的模型。Meta 把 DPO 纳入 Llama 3 对齐流水线。
RLHF 优化这个目标:
最大化:E[R(x,y)] - beta * KL(π || π_ref)
DPO 论文证明此目标有闭式最优解。对任意奖励函数 R,最优策略为:
π*(y|x) = π_ref(y|x) * exp(R(x,y)/beta) / Z(x)
整理得:R(x,y) = beta * log(π*(y|x)/π_ref(y|x)) + beta * log Z(x)。这是突破——奖励完全用策略模型概率与参考模型概率表达,无需训练单独奖励模型,奖励隐式地藏在概率比里。代入 Bradley-Terry 偏好模型,归一化常数 Z(x) 因两响应条件于同一提示 x 而相消,剩下的只是策略与参考在偏好与拒绝响应上的对数概率函数。
L_DPO = -log(sigmoid(beta * (log π(y_w|x)/π_ref(y_w|x) - log π(y_l|x)/π_ref(y_l|x))))
各部分:y_w=偏好(赢)响应、y_l=拒绝(输)响应、x=提示、π=当前模型(被训练)、π_ref=参考模型(冻结 SFT 检查点)、beta=控制偏离参考的温度参数(通常 0.1~0.5)。对数概率比 log π(y|x)/π_ref(y|x) 为正,表示当前模型给响应 y 的概率高于参考;为负则低。DPO 损失推模型:提高偏好响应的对数概率比,降低拒绝响应的。beta 控制偏离参考的激进程度——小 beta 允许大偏离,大 beta 保持模型贴近参考。
| 方面 | RLHF(PPO) | DPO |
|---|---|---|
| 要训模型 | 3(SFT + 奖励 + 策略) | 1(仅策略) |
| 训练循环 | 3(SFT、RM、PPO) | 2(SFT、DPO) |
| 超参 | lr、KL 系数、裁剪比、RM lr、轮数×3 | lr、beta、轮数 |
| 奖励模型 | 必需(单独训练) | 隐式在模型概率里 |
| RL 算法 | PPO(复杂、不稳) | 监督学习(稳定) |
| GPU 内存 | PPO 时 3~4 个模型 | 2 个(当前 + 参考) |
DPO 训练时内存只需两个模型——当前与冻结参考。RLHF 要三四个:策略、参考、奖励模型,可选价值函数基线。70B 模型 FP16 每份 140GB,去掉奖励模型省的内存可观。
小数据集:5,000~20,000 偏好对,DPO 常匹配或超越 RLHF——RLHF 奖励模型需要足够数据泛化,数据少则过拟合产出不可靠信号,DPO 根本不需奖励模型。算力有限:DPO 约为全 RLHF 的三分之一算力(一个循环而非三个)。快速迭代:想试 10 种偏好数据集看哪个产出最好模型?DPO 每个实验数小时;RLHF 每个数据集要重训奖励模型。
大规模训练:GPT-4 或 Claude 规模,RLHF 独立奖励模型能捕捉更细致偏好信号——奖励模型充当学习到的损失函数,适应复杂质量标准。复杂奖励信号:「更好」涉及多维度(有用、无害、诚实)时,奖励模型能学这种多目标权衡;DPO 把每对当作二元信号(一个更好一个更差)而不建模为何。迭代对齐:RLHF 能用当前策略生成新响应、让人评级、在线重训奖励模型;DPO 作用在固定偏好对数据集上。Anthropic 的 Constitutional AI 大量用 RLHF 的这种迭代性。
DPO 启发了一个简化对齐方法家族。KTO(Kahneman-Tversky 优化,2024):连配对都不需要,用非配对反馈——给每个响应标「好」或「坏」无需对比替代,用前景理论的损失厌恶(坏响应惩罚多于好响应奖励)。ORPO(赔率比偏好优化,2024):把 SFT 与对齐合成单步——修改 SFT 损失加偏好项,一轮训练而非两轮。SimPO(简单偏好优化,2024):完全去掉参考模型——用按长度归一化的平均对数概率作隐式奖励,省内存、简化训练,长度归一化防模型偏好更短响应。
| 方法 | 年 | 内存模型 | 需配对? | 需参考? | 训练循环 |
|---|---|---|---|---|---|
| RLHF | 2022 | 3~4 | 是(训 RM) | 是 | 3 |
| DPO | 2023 | 2 | 是 | 是 | 2 |
| KTO | 2024 | 2 | 否(非配对) | 是 | 2 |
| ORPO | 2024 | 1 | 是 | 否 | 1 |
| SimPO | 2024 | 1 | 是 | 否 | 1 |
趋势清晰:每代再砍一块复杂度。RLHF 要奖励模型和 PPO,DPO 都砍掉;KTO 砍配对数据;ORPO 砍独立 SFT 阶段;SimPO 砍参考模型。对齐税(从基座到对齐的算力与复杂度成本)持续下降。
同 RLHF 格式——(提示,偏好,拒绝)三元组。DPO 直接消费,无需中间奖励模型。
DPO 损失需算给定提示下响应的总对数概率——在完整(提示+响应)序列上跑模型,累加每个响应 token 的对数概率。
def compute_sequence_log_prob(model, prompt_tokens, response_tokens, max_seq_len=128): full = prompt_tokens + response_tokens input_ids = full[:-1]; target_ids = full[1:] logits = model.forward(input_ids) log_probs = log_softmax(logits) # 只累加响应部分的 log_probs return sum(log_probs[i, target_ids[i]] for i in range(response_start, response_end))
这是 DPO 的工作马。每个偏好对跑四次:模型在偏好响应、模型在拒绝响应、参考在偏好、参考在拒绝。即每样本 4 次前向,对比 RLHF 的生成+奖励打分+价值估计+PPO 更新——更简单、更快、更稳。
论文核心,代码版。一个函数,一个损失,无奖励模型。
def dpo_loss(pi_logp_w, pi_logp_l, ref_logp_w, ref_logp_l, beta=0.1): pref_ratio = pi_logp_w - ref_logp_w # 偏好响应对数比 rej_ratio = pi_logp_l - ref_logp_l # 拒绝响应对数比 logit = beta * (pref_ratio - rej_ratio) loss = -np.log(sigmoid(logit) + 1e-8) return loss, {"implicit_pref_reward": beta*pref_ratio, "implicit_rej_reward": beta*rej_ratio, "reward_margin": beta*(pref_ratio - rej_ratio)}
implicit_*_reward 是 DPO 损失隐式分配的奖励,可提取验证训练是否有效——偏好与拒绝的奖励间隔应随训练增大。
标准监督训练循环,无 PPO、无奖励模型,只有前向与梯度更新。每偏好对:算四个对数概率(两模型两响应),代入 DPO 损失,算梯度,更新策略。无生成步骤,无奖励模型推理,无优势估计,无裁剪。
度量隐式奖励间隔与对数概率偏移,把 DPO 与第 07 节的 RLHF 模型对比。
beta 是 DPO 的 KL 系数等价物,控制模型偏离参考的程度。小 beta(0.01)让模型自由偏离参考——学得快但有退化解风险;大 beta(1.0)保持模型贴近参考——稳但慢。多数应用的甜点在 0.1~0.3。
HuggingFace TRL 的 DPOTrainer 几行封装:
from trl import DPOTrainer, DPOConfig trainer = DPOTrainer(model=policy, ref_model=reference, args=DPOConfig(beta=0.1), train_dataset=pref_ds) trainer.train()
它自动处理四对前向、对数概率计算、DPO 损失。底层与我们手写相同。Zephyr-7B(HuggingFace 2023 年 10 月)就用 TRL 的 DPOTrainer:Mistral 7B 基座 → UltraChat(200K)SFT → UltraFeedback(60K 偏好对)DPO,MT-Bench 得 6.47,当时 7B 最高——对比 Llama 2 Chat 70B 的 6.86,Zephyr 用纯 DPO 对齐达到了体量大 10 倍模型的 94% 水平。
本节产出 outputs/prompt-alignment-method-selector.md——一个帮你选对齐方法(SFT、RLHF、DPO、KTO、ORPO、SimPO)的提示。给定数据可得性、算力预算、对齐目标,它推荐方法与训练计划。
(Easy) 实现 KTO:不需配对,只标每响应「好」或「坏」,好响应损失 -log(sigmoid(beta*log_ratio)),坏响应带 1.5× 损失厌恶,对比 DPO 准确率。
(Medium) 实现长度归一化 DPO:对数概率除以响应 token 数 normalized = total/num_tokens,防模型偏好更短响应,对比有无归一化的隐式奖励间隔。
(Medium) 构建 ORPO 式组合损失:在偏好响应上加标准下一 token 预测损失 L = L_sft(偏好) + alpha*L_dpo,试 alpha=0.1、0.5、1.0,展示组合产出既遵循指令又偏好更好响应。
(Hard) 实现迭代 DPO:跑 3 轮 DPO,用训好的模型生成新响应,与原偏好响应配成新偏好对,再跑 DPO,两轮「自博弈」,对比第 1、2 轮后的偏好准确率。
(Hard) 对比不同参考模型:用(a)基座模型(预 SFT)、(b)DPO 第 1 轮检查点、(c)策略的指数移动平均作参考,报告哪个偏好准确率最高、训练曲线最稳。
R(x,y)=beta*log(π(y|x)/π_ref(y|x)),最优奖励由模型自身 token 概率决定。下一节,Constitutional AI:把 RLHF 里的人类换成模型自己——写一串原则,让模型自评自改,DeepSeek-R1 把它推到极致,几乎不用人类偏好数据。