土法炼钢兴趣小组的算法知识备份

【强化学习与大模型后训练】10|DPO:把 RLHF 变成一个分类损失

文章导航

分类入口
rl-posttraining
标签入口
#dpo#rlhf#preference-optimization#bradley-terry#implicit-reward#alignment

目录

PPO-RLHF 的工程复杂度很高:要在线采样,要跑奖励模型,要训练 critic,还要控制 KL。

DPO(Direct Preference Optimization)问了一个非常尖锐的问题:如果偏好数据已经告诉我们 \(y_w\)\(y_l\) 好,能不能不显式训练奖励模型,也不跑在线 RL,直接更新语言模型?

答案是可以,但不是拍脑袋把偏好学习写成分类。

DPO 的关键是从 KL 正则的 RLHF 目标出发,推导出最优策略和奖励之间的闭式关系,再把这个关系代回 Bradley-Terry 偏好模型。

这篇文章完整走一遍推导,并解释“隐式奖励”、reference model、梯度方向、离线数据限制和分布漂移风险。

读完你应该能看懂 DPO loss 的每一项为什么存在,而不是只记住一行 logsigmoid

一、从 KL 正则 RLHF 目标开始

上一篇 09|RLHF 全链路 写过,经典 RLHF 不是直接最大化奖励模型。

它最大化的是带 reference KL 约束的目标。

对每个 prompt \(x\),可以写成:

\[ \max_\pi \mathbb{E}_{y\sim\pi(\cdot\mid x)}[r(x,y)] - \beta\,\mathrm{KL}(\pi(y\mid x)\,\|\,\pi_{ref}(y\mid x)) \]

这里先不区分 \(r\) 是人工奖励、奖励模型还是某个理想偏好函数。

把 KL 展开:

\[ \mathrm{KL}(\pi\,\|\,\pi_{ref}) = \mathbb{E}_{y\sim\pi}\left[\log\frac{\pi(y\mid x)}{\pi_{ref}(y\mid x)}\right] \]

于是单个 \(x\) 下的目标是:

\[ \mathbb{E}_{y\sim\pi}\left[r(x,y)-\beta\log\frac{\pi(y\mid x)}{\pi_{ref}(y\mid x)}\right] \]

这个目标还有一个约束:\(\pi(\cdot\mid x)\) 必须是概率分布。

也就是:

\[ \sum_y \pi(y\mid x)=1 \]

DPO 的第一步,是求这个优化问题的闭式最优策略。

把拉格朗日项加进去:

\[ \mathcal{L}(\pi,\lambda)=\sum_y \pi(y\mid x)r(x,y)-\beta\sum_y\pi(y\mid x)\log\frac{\pi(y\mid x)}{\pi_{ref}(y\mid x)}+\lambda\left(\sum_y\pi(y\mid x)-1\right) \]

\(\pi(y\mid x)\) 求导并令其为 0:

\[ r(x,y)-\beta\left(\log\frac{\pi(y\mid x)}{\pi_{ref}(y\mid x)}+1\right)+\lambda=0 \]

整理得到:

\[ \log\frac{\pi(y\mid x)}{\pi_{ref}(y\mid x)}=\frac{1}{\beta}r(x,y)+\frac{\lambda}{\beta}-1 \]

把常数项吸收到归一化因子 \(Z(x)\) 里:

\[ \pi^*(y\mid x)=\frac{1}{Z(x)}\pi_{ref}(y\mid x)\exp\left(\frac{1}{\beta}r(x,y)\right) \]

这就是 DPO 推导的关键式子。

它说明最优策略不是凭空出现的,而是在 reference policy 上做指数倾斜。

奖励越高,\(\pi^*\) 相对 \(\pi_{ref}\) 的概率越大。

\(\beta\) 越小,奖励差异被放大得越厉害。

\(\beta\) 越大,策略越接近 reference。

二、反解奖励:隐式奖励从哪来

上面的式子可以反过来解出奖励。

从:

\[ \pi^*(y\mid x)=\frac{1}{Z(x)}\pi_{ref}(y\mid x)\exp\left(\frac{1}{\beta}r(x,y)\right) \]

两边取对数:

\[ \log\pi^*(y\mid x)=\log\pi_{ref}(y\mid x)+\frac{1}{\beta}r(x,y)-\log Z(x) \]

整理得到:

\[ r(x,y)=\beta\log\frac{\pi^*(y\mid x)}{\pi_{ref}(y\mid x)}+\beta\log Z(x) \]

这句话非常重要。

它说:如果某个策略是 KL 正则奖励最大化的最优策略,那么这个奖励可以由“该策略相对参考策略有多偏好某个回答”表示。

\(\beta\log\frac{\pi^*(y\mid x)}{\pi_{ref}(y\mid x)}\) 就是隐式奖励的主体。

\(\beta\log Z(x)\) 只依赖 prompt,不依赖候选回答。

当我们比较同一个 prompt 下两个回答时,这个项会消掉。

DPO 的直觉就在这里:不训练显式 reward model,而是让当前策略 \(\pi_\theta\) 自己承担 \(\pi^*\) 的角色。

于是定义一个隐式奖励:

\[ r_\theta(x,y)=\beta\log\frac{\pi_\theta(y\mid x)}{\pi_{ref}(y\mid x)} \]

严格说,这里省略了 \(\beta\log Z(x)\),因为偏好比较中它不影响胜负概率。

这也解释了为什么 DPO 仍然需要 reference model。

没有 reference,\(\log\pi_\theta(y\mid x)\) 会同时包含“回答质量”和“语言模型本来就容易生成这句话”的因素。

reference 提供了一个基线,让我们看的是相对偏移。

三、代回 Bradley-Terry:归一化项如何消失

偏好数据通常是一组三元组 \((x,y_w,y_l)\)

\(y_w\) 是 chosen / winner,\(y_l\) 是 rejected / loser。

奖励模型一篇里讲过 Bradley-Terry 模型:

\[ P(y_w \succ y_l\mid x)=\sigma(r(x,y_w)-r(x,y_l)) \]

把刚才反解的奖励代进去:

\[ r(x,y_w)-r(x,y_l) = \beta\log\frac{\pi^*(y_w\mid x)}{\pi_{ref}(y_w\mid x)} - \beta\log\frac{\pi^*(y_l\mid x)}{\pi_{ref}(y_l\mid x)} \]

两个 \(\beta\log Z(x)\) 完全抵消。

\(\pi^*\) 用可训练策略 \(\pi_\theta\) 近似,就得到 DPO 的偏好概率:

\[ P_\theta(y_w \succ y_l\mid x)=\sigma\left(\beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{ref}(y_w\mid x)}-\beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{ref}(y_l\mid x)}\right) \]

最大化偏好数据似然,等价于最小化负对数似然:

\[ \mathcal{L}_{DPO}(\theta)= -\log\sigma\left( \beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{ref}(y_w\mid x)} - \beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{ref}(y_l\mid x)} \right) \]

这就是 DPO loss。

它看起来像分类损失,但每一项都有 RLHF 目标的来源。

winner 的 log-ratio 应该变大。

loser 的 log-ratio 应该变小。

reference 的 log-prob 把“离 SFT 多远”纳入同一个分类边界。

\(\beta\) 控制分类间隔的温度,也对应原 KL 正则里的强度。

四、序列 log-prob:DPO 在语言模型里怎么落地

语言模型里的 \(\pi_\theta(y\mid x)\) 是整段回答概率。

它分解为 token 条件概率之和:

\[ \log\pi_\theta(y\mid x)=\sum_{t=1}^{T}\log\pi_\theta(a_t\mid x,a_{<t}) \]

实现 DPO 时,通常对 winner 和 loser 都做 teacher forcing。

也就是把完整 prompt-response 输入模型,取 response token 位置的 log-prob,按 mask 求和。

示意代码如下:

# 示意:省略 tokenizer、padding、分布式和数值稳定细节
import torch
import torch.nn.functional as F

def sequence_logprob(model, input_ids, labels, response_mask):
    logits = model(input_ids).logits[:, :-1]
    target = labels[:, 1:]
    mask = response_mask[:, 1:].float()
    logp = F.log_softmax(logits, dim=-1)
    token_logp = logp.gather(-1, target.unsqueeze(-1)).squeeze(-1)
    return (token_logp * mask).sum(dim=-1)

def dpo_loss(policy, ref, batch, beta=0.1):
    pi_w = sequence_logprob(policy, batch.w_input_ids, batch.w_labels, batch.w_mask)
    pi_l = sequence_logprob(policy, batch.l_input_ids, batch.l_labels, batch.l_mask)
    with torch.no_grad():
        ref_w = sequence_logprob(ref, batch.w_input_ids, batch.w_labels, batch.w_mask)
        ref_l = sequence_logprob(ref, batch.l_input_ids, batch.l_labels, batch.l_mask)
    logits = beta * ((pi_w - ref_w) - (pi_l - ref_l))
    return -F.logsigmoid(logits).mean()

这段代码只表达损失结构,不代表完整训练脚本。

真实实现要处理 packed sequence、position ids、loss mask、bf16 精度、梯度累积、reference cache 和分布式切分。

最容易错的地方是 response mask。

prompt 部分不应该进入 \(\log\pi(y\mid x)\)

padding 不应该进入求和。

如果 chosen 和 rejected 长度差异很大,序列求和还会带来长度偏置。

DPO 原式使用整段序列 log-prob,这与 RLHF 中完整回答的奖励一致。

但工程上必须意识到:更长的回答有更多 token log-prob 相加,数值上通常更负。

后面的 SimPO 就会显式采用长度归一化的隐式奖励来缓解这一点。

五、DPO 到底省掉了什么

DPO 省掉的第一件事是显式奖励模型。

不需要先训练一个 \(r_\phi(x,y)\),再担心它被策略过优化。

偏好数据直接进入 policy loss。

DPO 省掉的第二件事是在线采样。

训练样本就是离线的 \((x,y_w,y_l)\)

因此训练过程更接近 SFT:teacher forcing、普通反向传播、没有 rollout buffer。

DPO 省掉的第三件事是 value / critic。

没有轨迹回报,也就没有 GAE 和 value target。

DPO 省掉的第四件事是 PPO 的多轮小批量更新与 ratio 裁剪。

它没有 \(\pi_{old}\),也没有 rollout policy 与 update policy 的同步问题。

这带来非常直接的工程收益。

显存更少。

训练流程更短。

指标更容易解释。

复现实验的变量更少。

但省掉这些东西,也意味着 DPO 放弃了一部分在线优化能力。

PPO 可以让当前策略探索新回答,再由 reward model 打分。

DPO 只能从离线偏好对里学习。

如果偏好数据没有覆盖某类 prompt 或某种更优回答,DPO 不会自己发现它。

这就是 DPO 的核心取舍:用更强的离线假设换更低的工程复杂度。

六、梯度怎么理解:推高 winner,压低 loser

设:

\[ z_\theta = \beta\left[\log\frac{\pi_\theta(y_w\mid x)}{\pi_{ref}(y_w\mid x)}-\log\frac{\pi_\theta(y_l\mid x)}{\pi_{ref}(y_l\mid x)}\right] \]

DPO loss 是:

\[ \mathcal{L}=-\log\sigma(z_\theta) \]

\(z_\theta\) 求导:

\[ \frac{\partial \mathcal{L}}{\partial z_\theta}=-(1-\sigma(z_\theta)) \]

当模型已经很确信 winner 更好时,\(z_\theta\) 大,\(\sigma(z_\theta)\) 接近 1,梯度变小。

当模型还把 loser 看得更高时,\(z_\theta\) 小甚至为负,梯度变大。

对 policy log-prob 的方向可以直观看成:

这和 SFT 不同。

SFT 只推高正例。

DPO 同时使用正例和反例,并且只关心二者相对 reference 的差距。

这也和奖励模型训练不同。

奖励模型更新的是 \(r_\phi\)

DPO 直接更新 \(\pi_\theta\)

所以 DPO 可以看成“把 reward learning 和 policy optimization 合并成一个分类目标”。

七、reference model 的角色与常见误用

DPO 训练时 reference model 通常是 SFT 模型的冻结副本。

它有三个作用。

第一,提供 KL 正则的锚点。

推导里 reference 来自 RLHF 的 KL 项。

没有这个锚点,就无法把 DPO 解释成 KL 正则奖励优化。

第二,抵消语言建模难度。

某些回答天然更常见,\(\pi_\theta\)\(\pi_{ref}\) 都会给较高概率。

看 log-ratio 可以更关注训练后相对 SFT 的偏移。

第三,控制更新幅度。

如果 policy 开始偏离 reference,log-ratio 会反映这种偏移,loss 会按偏好对选择方向。

常见误用是把 reference 换成一个完全不同分布的 base model。

这样推导仍能写,但隐式奖励的语义变了。

如果 SFT 模型已经注入了对话模板和安全行为,而 reference 是预训练 base,log-ratio 会混入大量“从 base 到 chat”的差异。

另一个误用是训练过程中同步更新 reference。

如果 reference 跟着 policy 走,KL 锚点会漂移,DPO 的原始解释不再成立。

有些算法会故意设计动态 reference,但那已经不是 vanilla DPO。

八、DPO 的离线限制

DPO 依赖 paired preference data。

每条样本至少要有同一个 prompt 下的 winner 和 loser。

如果数据只有“这个回答好”或“这个回答坏”的单点标签,DPO 原式不能直接使用。

这就是 KTO 之类方法出现的动机。

DPO 还依赖离线数据分布。

偏好对通常来自某个旧模型或多个模型的采样。

训练后的 \(\pi_\theta\) 可能逐渐离开这些样本覆盖的区域。

一旦进入数据没有覆盖的回答模式,DPO 没有在线 reward model 去评价新样本。

这就是 off-policy 风险。

PPO-RLHF 至少会用当前 policy 采样,再由 reward model 打分。

DPO 则把“哪些回答值得比较”固定在数据里。

如果 loser 太弱,DPO 很快学会区分,后续梯度变小。

如果 winner 本身质量一般,DPO 会把它推高,而不会知道还有更好的回答。

如果偏好数据混入格式偏见,DPO 会稳定学习这种偏见。

因此 DPO 的数据构造很关键。

好的 DPO 数据通常需要强负例、难负例、多样 prompt、清晰标注准则和长度控制。

九、\(\beta\) 不是随便调的温度

DPO 里的 \(\beta\) 经常被说成 temperature。

这个说法不算错,但容易让人忽略它和 RLHF KL 正则的关系。

在推导中,\(\beta\) 是 KL 惩罚系数。

它越大,最优策略越不愿偏离 reference。

在 DPO loss 里,\(\beta\) 乘在 log-ratio 差上。

它越大,同样的 log-ratio 差会让分类 logit 更极端。

这两个视角看似相反,原因是 DPO 把 reward scale 和 KL scale 绑定在一起。

实践中,\(\beta\) 会影响三个东西。

第一,梯度大小。

第二,模型相对 reference 的偏移速度。

第三,winner / loser 差距被压到多大才算够。

\(\beta\) 太小,logit 接近 0,训练信号弱,模型可能学得慢。

\(\beta\) 太大,少量 log-prob 差就会让 sigmoid 饱和,也可能带来不稳定。

不同代码库对 \(\beta\) 的命名、默认值和 loss 归一化细节可能不同,不能只看数字比较。

更稳妥的做法是同时监控训练 loss、chosen reward、rejected reward、margin、KL-like log-ratio 和下游评测。

十、DPO 与 PPO-RLHF 的对照

维度 PPO-RLHF DPO
数据 在线采样 prompt-response 离线成对偏好
奖励模型 需要显式 RM 不需要显式 RM
Critic 通常需要 不需要
Reference 用于 KL 惩罚 用于隐式奖励 log-ratio
训练形态 rollout + PPO update teacher forcing + classification loss
探索 当前策略可产生新样本 受限于离线数据
工程复杂度
主要风险 reward hacking、KL 失控、critic 不稳 数据偏置、分布漂移、长度偏置

这张表不是说 DPO 永远更好。

它说明两者优化问题的边界不同。

如果已有高质量偏好对,且目标是把 SFT 模型往人类偏好方向推一段,DPO 非常合适。

如果需要在线发现新策略,或者奖励来自可验证环境,PPO/GRPO/RLVR 可能更合适。

如果偏好数据质量不稳定,DPO 的简洁会让问题更隐蔽:loss 会正常下降,但模型可能学到错误偏好。

十一、DPO 与后续变体的接口

DPO 成为一个家族的起点,是因为它把 RLHF 写成了可改造的监督损失。

IPO 修改偏好目标,试图处理确定性偏好下的过拟合。

KTO 放弃成对偏好,改用单条 good/bad 反馈。

ORPO 把 SFT 和 preference penalty 合并,并尝试去掉 reference model。

SimPO 改用长度归一化隐式奖励,并引入目标 margin。

这些方法都在问同一个问题:DPO 的哪些假设可以放松?

是否必须成对?

是否必须 reference?

是否应该按总 log-prob 还是平均 log-prob 比较?

是否要把 SFT 和偏好训练拆成两个阶段?

下一篇会把这些变体放到同一张表里比较。

参考资料

← 上一篇:09|RLHF 全链路 | 下一篇:11|DPO 家族

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-29 · rl-posttraining

强化学习与大模型后训练

从 MDP、策略梯度、PPO 等强化学习最小必要集出发,系统讲清现代大模型后训练:SFT、奖励模型、RLHF,到 DPO/IPO/KTO/ORPO/SimPO 免 RL 对齐、GRPO,再到 RLVR 可验证奖励、推理模型(o1/R1 范式)、过程奖励、奖励黑客、RL 训练基础设施与评测。全 20 篇深度博客。


By .