在上一节中,我们明确了偏好优化的必要性。传统的解决方案是 RLHF(Reinforcement Learning from Human Feedback):先训练一个奖励模型,再用 PPO 等强化学习算法优化策略。但这个流程复杂且不稳定。
DPO(Direct Preference Optimization) 的核心贡献是:通过一个精巧的数学推导,证明了可以完全跳过奖励模型和 RL 训练,直接在偏好对数据上用一个简单的监督损失来优化策略。
本节将完整推导这一过程。
推导路线图:RLHF 目标 → 闭式最优策略 → 奖励的策略表达 → 代入 Bradley-Terry 模型 → DPO 损失函数。每一步都建立在前一步的基础上,最终得到一个只依赖策略模型和参考模型的简洁损失函数。
RLHF 的目标是找到一个策略 πθ,使得生成的回复获得尽可能高的人类奖励,同时不偏离参考策略 πref 太远。数学上表示为:
πθmaxEx∼D,y∼πθ(⋅∣x)[r(x,y)]−βKL[πθ(y∣x)∥πref(y∣x)]
其中:
- πθ(y∣x):当前策略模型,即我们要优化的语言模型
- πref(y∣x):参考策略,通常是 SFT 之后的模型(冻结参数)
- r(x,y):奖励函数,衡量回复 y 对于提示 x 的质量
- β>0:KL 惩罚系数,控制策略偏离参考模型的程度
- D:提示(prompt)的分布
为什么需要 KL 约束? 如果没有 KL 约束,策略模型会无限制地追求高奖励,导致:
- 奖励黑客(Reward Hacking):模型学会利用奖励模型的漏洞,生成奖励分数高但实际质量低的回复
- 模式坍缩(Mode Collapse):模型只生成少数几种"高分模板",丧失多样性
- 语言退化(Language Degradation):模型输出变得不自然,充满不连贯的高分 token 组合
KL 约束确保优化后的策略不会偏离参考模型太远,起到正则化的作用。
将目标函数完整展开:
πθmaxEx∼D[Ey∼πθ(⋅∣x)[r(x,y)−βlogπref(y∣x)πθ(y∣x)]]
等价地,对于固定的 x,内层优化问题是:
πθ(⋅∣x)maxy∑πθ(y∣x)[r(x,y)−βlogπref(y∣x)πθ(y∣x)]
这是一个带约束的优化问题(πθ(⋅∣x) 必须是合法的概率分布,即 ∑yπθ(y∣x)=1 且 πθ(y∣x)≥0)。
使用拉格朗日乘子法,对 πθ(y∣x) 求导并令其为零:
∂πθ(y∣x)∂πθ(y∣x)(r(x,y)−βlogπref(y∣x)πθ(y∣x))+λ1−y′∑πθ(y′∣x)=0
求导得到:
r(x,y)−βlogπref(y∣x)πθ(y∣x)−β−λ=0
整理后:
logπref(y∣x)πθ(y∣x)=β1(r(x,y)−λ−β)
从上式可得最优策略:
π∗(y∣x)=πref(y∣x)⋅exp(βr(x,y))⋅Z(x)1
其中配分函数 Z(x) 确保概率归一化:
Z(x)=y∑πref(y∣x)⋅exp(βr(x,y))
直觉理解:最优策略是参考策略的一个**能量模型(Energy-Based Model)**修正版本。奖励高的回复 y 会被"上调"概率(exp(r/β) 大),奖励低的回复会被"下调"概率。β 控制调整的幅度——β 越小,高奖励回复被放大得越多,策略偏离参考模型越远。
这个闭式解告诉我们:
- 当 β→∞ 时,π∗→πref:KL 惩罚极强,策略完全不动
- 当 β→0 时,π∗ 趋向于只给最高奖励的 y 赋予概率:完全贪婪
- Z(x) 只依赖于 x,不依赖于具体的 y:这在后续推导中非常关键
从第二步的最优策略表达式出发,两边取对数:
logπ∗(y∣x)=logπref(y∣x)+βr(x,y)−logZ(x)
移项得到奖励的策略表达式:
r(x,y)=βlogπref(y∣x)π∗(y∣x)+βlogZ(x)
这一步是 DPO 的核心洞察! 传统 RLHF 需要一个显式的奖励模型 r(x,y)。但这个公式告诉我们:奖励函数可以完全用最优策略和参考策略的对数概率比来表示。换言之,最优策略本身就隐式地"编码"了奖励信息。
这个变换被称为重参数化技巧(Reparameterization Trick):我们不再需要显式地学习奖励函数 r(x,y),而是直接学习策略 πθ,然后通过上述公式隐式地得到奖励。
注意,在实践中我们用参数化策略 πθ 来近似最优策略 π∗:
r(x,y)=βlogπref(y∣x)πθ(y∣x)+βlogZ(x)
在3.1节中我们介绍了 Bradley-Terry 偏好模型。给定偏好对 (yw,yl)(yw 被偏好),人类偏好的概率为:
P(yw≻yl∣x)=σ(r(x,yw)−r(x,yl))
其中 σ(z)=1+e−z1 是 sigmoid 函数。
将第三步得到的奖励表达式代入 Bradley-Terry 模型:
r(x,yw)−r(x,yl)=βlogπref(yw∣x)πθ(yw∣x)+βlogZ(x)−βlogπref(yl∣x)πθ(yl∣x)−βlogZ(x)
关键的一步:βlogZ(x) 项只依赖于提示 x,在 yw 和 yl 之间做差时完全消去!
因此:
r(x,yw)−r(x,yl)=βlogπref(yw∣x)πθ(yw∣x)−βlogπref(yl∣x)πθ(yl∣x)
最终,DPO 通过最大化偏好数据的对数似然来训练策略,即最小化负对数似然:
LDPO(πθ;πref)=−E(x,yw,yl)∼D[logσ(βlogπref(yw∣x)πθ(yw∣x)−βlogπref(yl∣x)πθ(yl∣x))]
这就是 DPO 的全部! 一个看似复杂的 RLHF 问题,通过四步推导,变成了一个简洁的监督学习损失。不需要训练奖励模型,不需要 PPO,不需要价值网络——只需要在偏好对上最小化这个损失。
让我们定义隐式奖励边际(Implicit Reward Margin):
r^θ(x,y)=βlogπref(y∣x)πθ(y∣x)
那么 DPO 损失可以简写为:
LDPO=−E[logσ(r^θ(x,yw)−r^θ(x,yl))]
直觉:DPO 本质上是在训练一个隐式的奖励模型,奖励定义为策略与参考策略的对数概率比。训练目标是让 chosen 回复的隐式奖励高于 rejected 回复的隐式奖励。
当优化进展顺利时:
- r^θ(x,yw)>r^θ(x,yl):模型正确地给 chosen 更高的隐式奖励
- σ(⋅) 的输入为正值,σ>0.5
- logσ>log0.5≈−0.693
- 损失值较小
当优化不佳时:
- r^θ(x,yw)<r^θ(x,yl):模型错误地给 rejected 更高的奖励
- σ(⋅) 的输入为负值,σ<0.5
- logσ<−0.693
- 损失值较大,梯度推动模型修正
对 DPO 损失求关于参数 θ 的梯度:
∇θLDPO=−βE权重项σ(r^θ(x,yl)−r^θ(x,yw))提升 chosen∇θlogπθ(yw∣x)−抑制 rejected∇θlogπθ(yl∣x)
这个 sigmoid 项决定了梯度的强度:
- 当模型已经正确排序(chosen 的隐式奖励 >> rejected),权重项接近 0,梯度很小——"已经学好了,不用再调"
- 当模型排序错误(rejected 的隐式奖励 > chosen),权重项接近 1,梯度很大——"还没学会,需要大幅调整"
这是一种自适应学习机制:模型自动聚焦在还没学好的样本上。
梯度推动模型增加 chosen 回复 yw 在给定提示 x 下的生成概率。
梯度推动模型降低 rejected 回复 yl 在给定提示 x 下的生成概率。
DPO 的梯度结构与对比学习(Contrastive Learning)非常相似:
- 正样本(chosen)被"拉近"——增加其概率
- 负样本(rejected)被"推远"——降低其概率
- 学习力度由当前模型的排序能力动态调节
| 方面 | RLHF (PPO) | DPO |
|---|
| 需要的模型 | 4个(策略、参考、奖励、价值) | 2个(策略、参考) |
| 训练阶段 | 3个(SFT → RM → PPO) | 2个(SFT → DPO) |
| 奖励模型 | 显式训练 | 隐式(策略即奖励模型) |
| RL 循环 | 需要(PPO) | 不需要 |
| 训练稳定性 | 低(奖励黑客、KL 爆炸) | 高(简单的监督损失) |
| 内存需求 | 极高(4个模型) | 中等(2个模型) |
| 实现复杂度 | 高 | 低 |
| 在线探索 | 有(策略生成新回复) | 无(固定数据集) |
- 简洁性:一个公式,一个损失函数,没有 RL 的复杂性
- 稳定性:不存在奖励黑客问题(没有显式奖励模型可以被利用)
- 高效性:只需加载2个模型,内存需求约为 PPO 的一半
- 易于实现:用标准的深度学习框架即可实现,不需要 RL 基础设施
- 离线数据限制:标准 DPO 使用固定的偏好数据集,无法探索策略空间中的新区域
- 分布偏移:随着策略优化,训练数据可能变得"过时"——数据中的 (yw,yl) 可能与当前策略的生成分布相差甚远
- 需要参考模型:标准 DPO 需要维护一个冻结的参考模型,增加内存开销
这些局限催生了 DPO 变体:SimPO 解决了参考模型依赖问题,KTO 解决了偏好对数据稀缺问题,在线 DPO 解决了分布偏移问题。我们将在下一节详细介绍。
将四步推导串联起来:
maxπθEx,y∼πθ[r(x,y)]−βKL[πθ∥πref]
含义:最大化奖励,同时约束不偏离参考模型太远。
π∗(y∣x)=Z(x)1πref(y∣x)⋅exp(βr(x,y))
含义:最优策略是参考策略的指数加权版本。
r(x,y)=βlogπref(y∣x)πθ(y∣x)+βlogZ(x)
含义:奖励可以用策略比值来表示,不需要显式奖励模型。
LDPO=−E[logσ(βlogπref(yw∣x)πθ(yw∣x)−βlogπref(yl∣x)πθ(yl∣x))]
含义:纯监督损失,直接优化偏好排序,无需 RL。
def dpo_loss(policy_model, ref_model, chosen, rejected, beta=0.1):
"""
计算 DPO 损失
Args:
policy_model: 当前策略模型 π_θ
ref_model: 参考模型 π_ref (冻结)
chosen: (prompt, chosen_response) 批次
rejected: (prompt, rejected_response) 批次
beta: KL 惩罚系数
"""
# 计算策略模型的对数概率
pi_logprobs_chosen = policy_model.log_prob(chosen)
pi_logprobs_rejected = policy_model.log_prob(rejected)
# 计算参考模型的对数概率(无梯度)
with torch.no_grad():
ref_logprobs_chosen = ref_model.log_prob(chosen)
ref_logprobs_rejected = ref_model.log_prob(rejected)
# 计算对数概率比(隐式奖励)
chosen_reward = beta * (pi_logprobs_chosen - ref_logprobs_chosen)
rejected_reward = beta * (pi_logprobs_rejected - ref_logprobs_rejected)
# DPO 损失
loss = -F.logsigmoid(chosen_reward - rejected_reward).mean()
return loss
这段代码清晰地展示了 DPO 的实现简洁性——不到20行核心代码就实现了完整的偏好优化。