DPO:把偏好模型折叠进策略目标¶
Direct Preference Optimization 针对 RLHF 的一个核心摩擦:如果已经有 chosen/rejected 偏好对,是否必须先拟合 scalar reward,再运行在线 RL?DPO 给出的答案不是“偏好不再需要奖励假设”,而是利用 KL 正则化最优策略的形式,把 reward 差直接改写成 policy/reference log-ratio。
从 KL 正则化策略开始¶
固定 prompt \(x\),考虑
其最优策略满足
因此
对同一 prompt 的 chosen/rejected 做差,\(\log Z(x)\) 抵消。代入 Bradley–Terry preference model,定义
得到
reference 不是可随意丢弃的常数:它随回答变化,定义 policy 相对原行为的移动坐标。
最小可执行语义¶
下面的 aligned_sequence_logp 接收已经左移对齐的 logits 与 target:logits[b,t] 预测 target[b,t]。前两个序列是 chosen,后两个是 rejected。mask 保证 prompt/padding 不进入序列概率。
import torch
import torch.nn.functional as F
def aligned_sequence_logp(logits, target, mask):
token_logp = logits.log_softmax(-1).gather(-1, target[..., None]).squeeze(-1)
return (token_logp * mask).sum(-1)
def dpo_loss(policy_logp, ref_logp, batch_size, beta=0.2):
pi_w, pi_l = policy_logp[:batch_size], policy_logp[batch_size:]
ref_w, ref_l = ref_logp[:batch_size], ref_logp[batch_size:]
margin = beta * ((pi_w - ref_w) - (pi_l - ref_l))
return -F.logsigmoid(margin).mean(), margin
torch.manual_seed(0)
B, T, V = 2, 3, 5
target = torch.tensor([[1, 2, 0], [2, 3, 4], [0, 1, 0], [4, 1, 2]])
mask = torch.tensor([[1., 1., 0.], [1., 1., 1.], [1., 1., 0.], [1., 1., 1.]])
reference = torch.zeros(2 * B, T, V)
policy = reference.clone().requires_grad_(True)
ref_score = aligned_sequence_logp(reference, target, mask)
pi_score = aligned_sequence_logp(policy, target, mask)
loss, margin = dpo_loss(pi_score, ref_score, B)
assert torch.allclose(margin, torch.zeros(B))
assert torch.allclose(loss, torch.log(torch.tensor(2.0)))
loss.backward()
assert torch.all(policy.grad[mask == 0] == 0)
updated = (policy - 0.5 * policy.grad).detach()
new_score = aligned_sequence_logp(updated, target, mask)
new_loss, new_margin = dpo_loss(new_score, ref_score, B)
assert new_loss < loss and torch.all(new_margin > 0)
这里使用序列 log-probability 的总和。改成 token mean 会改变长度归纳偏置和原始序列概率语义,不能作为不记录的实现细节。
DPO 简化了什么¶
- 不需要单独训练并部署 scalar reward model;
- 不需要在训练环中持续向当前 policy rollout;
- 不需要 value model、GAE 或 PPO 的 on-policy 状态;
- 固定 pair 可以稳定重放,目标易于做手算与单元测试。
它由此降低了系统复杂度,也把能力上限更直接地交给离线 pair 的覆盖、质量与 reference support。
论文实际支持什么¶
原论文在 sentiment control、summarization 和 single-turn dialogue 等实验中表明,DPO 可以用简单分类式目标取得有竞争力的偏好优化结果,并在其设置中比所比较的 RLHF 基线更易训练。
这些实验支持“在若干固定偏好数据任务中,显式 reward model 与在线 PPO 不是获得良好结果的必要步骤”。数学推导依赖 KL-regularized optimum 与 Bradley–Terry 假设;实验只能检验由此得到的目标在受测任务中是否可训练、是否有竞争力,不能反过来证明假设普遍成立。
论文没有证明什么¶
- 没有证明离线偏好能发现 pair support 中从未出现的新策略;
- 没有证明 online RL、探索或环境交互已经没有价值;
- 没有证明 Bradley–Terry 能完整描述有 tie、循环偏好或群体分歧的反馈;
- 没有自动解决 pair 污染、生成策略偏差、模板不一致和长度捷径;
- 没有证明远离 reference 后的隐式 reward 仍可靠;
- 没有覆盖多步工具环境中的状态转移和长时信用分配。
当当前 policy 已明显偏离 pair 生成策略,或任务有低成本可执行 reward 时,重新采样偏好、rejection sampling 或在线 RL 可能更合适。
公开实现边界¶
作者参考实现公开了论文训练代码;TRL 的 DPOTrainer 提供了持续演进的工程实现。两者不是同一个复现实验环境,默认 loss、长度归一化、数据 collator、reference 处理和后续变体可能不同。
使用任何实现时都应冻结并记录:
policy / reference revisions
tokenizer and chat template
chosen / rejected generator and annotation protocol
prompt and response masks
sum / mean sequence reduction
beta convention and loss variant
truncation, packing and grouped split
它留下的问题¶
DPO 把固定偏好数据利用得更简单,但没有回答“怎样主动发现更好的 reasoning trajectory”。数学、代码等任务若有可执行 verifier,可以让当前策略在线生成候选并获得新 reward;这一分支在 DeepSeek-R1 中形成 reasoning RL 与 distillation 闭环。
整条历史见从续写到偏好与在线学习。更完整的假设、IPO/KTO/SimPO 与验证方法见离线偏好优化,在线数据与 old/reference 契约见在线 RL。