LLM 后训练实践
第3课:偏好对齐DPO

3.2 DPO 数学推导

从 RLHF 目标到 DPO 损失函数的完整四步推导,包括闭式最优策略、奖励重参数化和 Bradley-Terry 代入

引言:为什么需要推导 DPO

在上一节中,我们明确了偏好优化的必要性。传统的解决方案是 RLHF(Reinforcement Learning from Human Feedback):先训练一个奖励模型,再用 PPO 等强化学习算法优化策略。但这个流程复杂且不稳定。

DPO(Direct Preference Optimization) 的核心贡献是:通过一个精巧的数学推导,证明了可以完全跳过奖励模型和 RL 训练,直接在偏好对数据上用一个简单的监督损失来优化策略。

本节将完整推导这一过程。

推导路线图:RLHF 目标 → 闭式最优策略 → 奖励的策略表达 → 代入 Bradley-Terry 模型 → DPO 损失函数。每一步都建立在前一步的基础上,最终得到一个只依赖策略模型和参考模型的简洁损失函数。

第一步:RLHF 目标函数

基本设定

RLHF 的目标是找到一个策略 πθ\pi_\theta,使得生成的回复获得尽可能高的人类奖励,同时不偏离参考策略 πref\pi_{\text{ref}} 太远。数学上表示为:

maxπθ  ExD,yπθ(x)[r(x,y)]βKL[πθ(yx)πref(yx)]\max_{\pi_\theta} \; \mathbb{E}_{x \sim \mathcal{D}, \, y \sim \pi_\theta(\cdot|x)} \left[ r(x, y) \right] - \beta \, \text{KL}\left[ \pi_\theta(y|x) \| \pi_{\text{ref}}(y|x) \right]

其中:

  • πθ(yx)\pi_\theta(y|x):当前策略模型,即我们要优化的语言模型
  • πref(yx)\pi_{\text{ref}}(y|x):参考策略,通常是 SFT 之后的模型(冻结参数)
  • r(x,y)r(x, y):奖励函数,衡量回复 yy 对于提示 xx 的质量
  • β>0\beta > 0:KL 惩罚系数,控制策略偏离参考模型的程度
  • D\mathcal{D}:提示(prompt)的分布

KL 散度约束的作用

为什么需要 KL 约束? 如果没有 KL 约束,策略模型会无限制地追求高奖励,导致:

  1. 奖励黑客(Reward Hacking):模型学会利用奖励模型的漏洞,生成奖励分数高但实际质量低的回复
  2. 模式坍缩(Mode Collapse):模型只生成少数几种"高分模板",丧失多样性
  3. 语言退化(Language Degradation):模型输出变得不自然,充满不连贯的高分 token 组合

KL 约束确保优化后的策略不会偏离参考模型太远,起到正则化的作用。

展开 KL 散度

将目标函数完整展开:

maxπθ  ExD[Eyπθ(x)[r(x,y)βlogπθ(yx)πref(yx)]]\max_{\pi_\theta} \; \mathbb{E}_{x \sim \mathcal{D}} \left[ \mathbb{E}_{y \sim \pi_\theta(\cdot|x)} \left[ r(x, y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} \right] \right]

等价地,对于固定的 xx,内层优化问题是:

maxπθ(x)  yπθ(yx)[r(x,y)βlogπθ(yx)πref(yx)]\max_{\pi_\theta(\cdot|x)} \; \sum_y \pi_\theta(y|x) \left[ r(x, y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} \right]

第二步:闭式最优策略

拉格朗日对偶求解

这是一个带约束的优化问题(πθ(x)\pi_\theta(\cdot|x) 必须是合法的概率分布,即 yπθ(yx)=1\sum_y \pi_\theta(y|x) = 1πθ(yx)0\pi_\theta(y|x) \geq 0)。

使用拉格朗日乘子法,对 πθ(yx)\pi_\theta(y|x) 求导并令其为零:

πθ(yx)[πθ(yx)(r(x,y)βlogπθ(yx)πref(yx))+λ(1yπθ(yx))]=0\frac{\partial}{\partial \pi_\theta(y|x)} \left[ \pi_\theta(y|x) \left( r(x,y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} \right) + \lambda \left(1 - \sum_{y'} \pi_\theta(y'|x)\right) \right] = 0

求导得到:

r(x,y)βlogπθ(yx)πref(yx)βλ=0r(x, y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} - \beta - \lambda = 0

整理后:

logπθ(yx)πref(yx)=1β(r(x,y)λβ)\log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} = \frac{1}{\beta}\left(r(x, y) - \lambda - \beta\right)

最优策略的闭式解

从上式可得最优策略:

π(yx)=πref(yx)exp(r(x,y)β)1Z(x)\pi^*(y|x) = \pi_{\text{ref}}(y|x) \cdot \exp\left(\frac{r(x, y)}{\beta}\right) \cdot \frac{1}{Z(x)}

其中配分函数 Z(x)Z(x) 确保概率归一化:

Z(x)=yπref(yx)exp(r(x,y)β)Z(x) = \sum_y \pi_{\text{ref}}(y|x) \cdot \exp\left(\frac{r(x, y)}{\beta}\right)

直觉理解:最优策略是参考策略的一个**能量模型(Energy-Based Model)**修正版本。奖励高的回复 yy 会被"上调"概率(exp(r/β)\exp(r/\beta) 大),奖励低的回复会被"下调"概率。β\beta 控制调整的幅度——β\beta 越小,高奖励回复被放大得越多,策略偏离参考模型越远。

关键性质

这个闭式解告诉我们:

  • β\beta \to \infty 时,ππref\pi^* \to \pi_{\text{ref}}:KL 惩罚极强,策略完全不动
  • β0\beta \to 0 时,π\pi^* 趋向于只给最高奖励的 yy 赋予概率:完全贪婪
  • Z(x)Z(x) 只依赖于 xx,不依赖于具体的 yy:这在后续推导中非常关键

第三步:将奖励表示为策略的函数

核心变换:从策略反推奖励

从第二步的最优策略表达式出发,两边取对数:

logπ(yx)=logπref(yx)+r(x,y)βlogZ(x)\log \pi^*(y|x) = \log \pi_{\text{ref}}(y|x) + \frac{r(x, y)}{\beta} - \log Z(x)

移项得到奖励的策略表达式

r(x,y)=βlogπ(yx)πref(yx)+βlogZ(x)r(x, y) = \beta \log \frac{\pi^*(y|x)}{\pi_{\text{ref}}(y|x)} + \beta \log Z(x)

这一步是 DPO 的核心洞察! 传统 RLHF 需要一个显式的奖励模型 r(x,y)r(x,y)。但这个公式告诉我们:奖励函数可以完全用最优策略和参考策略的对数概率比来表示。换言之,最优策略本身就隐式地"编码"了奖励信息。

重参数化技巧

这个变换被称为重参数化技巧(Reparameterization Trick):我们不再需要显式地学习奖励函数 r(x,y)r(x,y),而是直接学习策略 πθ\pi_\theta,然后通过上述公式隐式地得到奖励。

注意,在实践中我们用参数化策略 πθ\pi_\theta 来近似最优策略 π\pi^*

r(x,y)=βlogπθ(yx)πref(yx)+βlogZ(x)r(x, y) = \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} + \beta \log Z(x)

第四步:代入 Bradley-Terry 模型

回顾 Bradley-Terry 模型

在3.1节中我们介绍了 Bradley-Terry 偏好模型。给定偏好对 (yw,yl)(y_w, y_l)ywy_w 被偏好),人类偏好的概率为:

P(ywylx)=σ(r(x,yw)r(x,yl))P(y_w \succ y_l | x) = \sigma\left(r(x, y_w) - r(x, y_l)\right)

其中 σ(z)=11+ez\sigma(z) = \frac{1}{1+e^{-z}} 是 sigmoid 函数。

代入奖励的策略表达

将第三步得到的奖励表达式代入 Bradley-Terry 模型:

r(x,yw)r(x,yl)=βlogπθ(ywx)πref(ywx)+βlogZ(x)βlogπθ(ylx)πref(ylx)βlogZ(x)r(x, y_w) - r(x, y_l) = \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} + \cancel{\beta \log Z(x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)} - \cancel{\beta \log Z(x)}

关键的一步βlogZ(x)\beta \log Z(x) 项只依赖于提示 xx,在 ywy_wyly_l 之间做差时完全消去

因此:

r(x,yw)r(x,yl)=βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx)r(x, y_w) - r(x, y_l) = \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)}

DPO 损失函数

最终,DPO 通过最大化偏好数据的对数似然来训练策略,即最小化负对数似然:

LDPO(πθ;πref)=E(x,yw,yl)D[logσ(βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx))]\boxed{ \mathcal{L}_{\text{DPO}}(\pi_\theta; \pi_{\text{ref}}) = -\mathbb{E}_{(x, y_w, y_l) \sim \mathcal{D}} \left[ \log \sigma \left( \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)} \right) \right] }

这就是 DPO 的全部! 一个看似复杂的 RLHF 问题,通过四步推导,变成了一个简洁的监督学习损失。不需要训练奖励模型,不需要 PPO,不需要价值网络——只需要在偏好对上最小化这个损失。

理解 DPO 损失函数

损失函数的结构

让我们定义隐式奖励边际(Implicit Reward Margin)

r^θ(x,y)=βlogπθ(yx)πref(yx)\hat{r}_\theta(x, y) = \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)}

那么 DPO 损失可以简写为:

LDPO=E[logσ(r^θ(x,yw)r^θ(x,yl))]\mathcal{L}_{\text{DPO}} = -\mathbb{E}\left[\log \sigma\left(\hat{r}_\theta(x, y_w) - \hat{r}_\theta(x, y_l)\right)\right]

直觉:DPO 本质上是在训练一个隐式的奖励模型,奖励定义为策略与参考策略的对数概率比。训练目标是让 chosen 回复的隐式奖励高于 rejected 回复的隐式奖励。

损失值分析

当优化进展顺利时:

  • r^θ(x,yw)>r^θ(x,yl)\hat{r}_\theta(x, y_w) > \hat{r}_\theta(x, y_l):模型正确地给 chosen 更高的隐式奖励
  • σ()\sigma(\cdot) 的输入为正值,σ>0.5\sigma > 0.5
  • logσ>log0.50.693\log \sigma > \log 0.5 \approx -0.693
  • 损失值较小

当优化不佳时:

  • r^θ(x,yw)<r^θ(x,yl)\hat{r}_\theta(x, y_w) < \hat{r}_\theta(x, y_l):模型错误地给 rejected 更高的奖励
  • σ()\sigma(\cdot) 的输入为负值,σ<0.5\sigma < 0.5
  • logσ<0.693\log \sigma < -0.693
  • 损失值较大,梯度推动模型修正

DPO 梯度分析

梯度公式

对 DPO 损失求关于参数 θ\theta 的梯度:

θLDPO=βE[σ(r^θ(x,yl)r^θ(x,yw))权重项(θlogπθ(ywx)提升 chosenθlogπθ(ylx)抑制 rejected)]\nabla_\theta \mathcal{L}_{\text{DPO}} = -\beta \, \mathbb{E} \left[ \underbrace{\sigma\left(\hat{r}_\theta(x, y_l) - \hat{r}_\theta(x, y_w)\right)}_{\text{权重项}} \left( \underbrace{\nabla_\theta \log \pi_\theta(y_w|x)}_{\text{提升 chosen}} - \underbrace{\nabla_\theta \log \pi_\theta(y_l|x)}_{\text{抑制 rejected}} \right) \right]

梯度的三个组成部分

权重项:σ(r^θ(x,yl)r^θ(x,yw))\sigma(\hat{r}_\theta(x, y_l) - \hat{r}_\theta(x, y_w))

这个 sigmoid 项决定了梯度的强度

  • 当模型已经正确排序(chosen 的隐式奖励 >> rejected),权重项接近 0,梯度很小——"已经学好了,不用再调"
  • 当模型排序错误(rejected 的隐式奖励 > chosen),权重项接近 1,梯度很大——"还没学会,需要大幅调整"

这是一种自适应学习机制:模型自动聚焦在还没学好的样本上。

提升 chosen:θlogπθ(ywx)\nabla_\theta \log \pi_\theta(y_w|x)

梯度推动模型增加 chosen 回复 ywy_w 在给定提示 xx 下的生成概率。

抑制 rejected:θlogπθ(ylx)-\nabla_\theta \log \pi_\theta(y_l|x)

梯度推动模型降低 rejected 回复 yly_l 在给定提示 xx 下的生成概率。

与对比学习的联系

DPO 的梯度结构与对比学习(Contrastive Learning)非常相似:

  • 正样本(chosen)被"拉近"——增加其概率
  • 负样本(rejected)被"推远"——降低其概率
  • 学习力度由当前模型的排序能力动态调节

DPO vs RLHF:关键对比

架构对比

方面RLHF (PPO)DPO
需要的模型4个(策略、参考、奖励、价值)2个(策略、参考)
训练阶段3个(SFT → RM → PPO)2个(SFT → DPO)
奖励模型显式训练隐式(策略即奖励模型)
RL 循环需要(PPO)不需要
训练稳定性低(奖励黑客、KL 爆炸)高(简单的监督损失)
内存需求极高(4个模型)中等(2个模型)
实现复杂度
在线探索有(策略生成新回复)无(固定数据集)

DPO 的核心优势

  1. 简洁性:一个公式,一个损失函数,没有 RL 的复杂性
  2. 稳定性:不存在奖励黑客问题(没有显式奖励模型可以被利用)
  3. 高效性:只需加载2个模型,内存需求约为 PPO 的一半
  4. 易于实现:用标准的深度学习框架即可实现,不需要 RL 基础设施

DPO 的潜在局限

  1. 离线数据限制:标准 DPO 使用固定的偏好数据集,无法探索策略空间中的新区域
  2. 分布偏移:随着策略优化,训练数据可能变得"过时"——数据中的 (yw,yl)(y_w, y_l) 可能与当前策略的生成分布相差甚远
  3. 需要参考模型:标准 DPO 需要维护一个冻结的参考模型,增加内存开销

这些局限催生了 DPO 变体:SimPO 解决了参考模型依赖问题,KTO 解决了偏好对数据稀缺问题,在线 DPO 解决了分布偏移问题。我们将在下一节详细介绍。

完整推导总结

将四步推导串联起来:

RLHF 目标

maxπθ  Ex,yπθ[r(x,y)]βKL[πθπref]\max_{\pi_\theta} \; \mathbb{E}_{x, y \sim \pi_\theta}\left[r(x,y)\right] - \beta \, \text{KL}\left[\pi_\theta \| \pi_{\text{ref}}\right]

含义:最大化奖励,同时约束不偏离参考模型太远。

闭式最优策略

π(yx)=1Z(x)πref(yx)exp(r(x,y)β)\pi^*(y|x) = \frac{1}{Z(x)} \pi_{\text{ref}}(y|x) \cdot \exp\left(\frac{r(x,y)}{\beta}\right)

含义:最优策略是参考策略的指数加权版本。

奖励的策略表达(重参数化)

r(x,y)=βlogπθ(yx)πref(yx)+βlogZ(x)r(x,y) = \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} + \beta \log Z(x)

含义:奖励可以用策略比值来表示,不需要显式奖励模型。

代入 Bradley-Terry,Z(x) 消去

LDPO=E[logσ(βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx))]\mathcal{L}_{\text{DPO}} = -\mathbb{E}\left[\log\sigma\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)}\right)\right]

含义:纯监督损失,直接优化偏好排序,无需 RL。

实现 DPO 损失的伪代码

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行核心代码就实现了完整的偏好优化。