一、第 17 讲留下的问题

第 17 讲的 RLHF 走了三步:收集偏好 → 训练奖励模型 → 强化学习。第三步训练时,内存里要同时放着策略模型、参考模型、奖励模型,PPO 通常还要再加一个。几个大模型互相牵制,训练很容易发散。

那一讲结尾留了一个问题:

能不能跳过"训练奖励模型"和"强化学习"这两步,直接拿偏好数据训练模型?

这个问题听起来有点天真。偏好数据说的是"A 比 B 好",它不是"正确答案",没法像第 16 讲的 SFT 那样直接当成模仿目标。RLHF 之所以要绕一大圈,就是因为需要一个奖励模型,把"比较"翻译成"分数",再用强化学习把"分数"翻译成"参数更新"。

2023 年提出的 DPO(Direct Preference Optimization,直接偏好优化) 给出的答案是:能。而且它不是一个近似的替代品——在一定的假设下,它和 RLHF 追求的是同一个目标,只是找到了一条不用绕路的数学捷径。

二、打个比方:直接看评委的打分记录

接着第 17 讲美食比赛的比方。

RLHF 的做法是:先根据评委过去的比较记录,训练一个"电子评委";然后让厨师不停做新菜,电子评委打分,厨师照着分数调整手艺。

DPO 的做法是:不训练电子评委了。厨师直接翻看评委过去的比较记录——“同一道题,这道菜被选中了,那道菜被淘汰了”——然后直接把被选中那道菜的做法加强一点,把被淘汰那道菜的做法减弱一点,同时注意不要偏离自己原来的风格太远。

听起来像是偷懒。关键在于:数学上可以证明,只要"加强多少、减弱多少"这个度把握得恰好,这样调出来的厨师,和"先训练电子评委、再追着电子评委的分数跑"最终到达的是同一个地方。

三、推出 DPO

这一节是这一讲的核心,一共四步。每一步都只用到前面讲过的东西。

第 1 步:RLHF 的目标,最优解可以直接写出来

回忆第 17 讲第 3 步的优化目标:

优化目标 = 奖励得分 − β × (当前模型和参考模型的 KL 距离)

第 17 讲说这是"朝高分走,但不能离出发点太远"。这个目标有一个很漂亮的性质:它的最优解可以直接写出来,不需要真的去跑强化学习:

π*(回答) = π_ref(回答) × exp(r(回答) / β) / Z

π_ref 是参考模型(通常就是 SFT 模型)给这个回答的概率,r 是奖励,Z 是一个让所有回答的概率加起来等于 1 的归一化常数。

这个式子的严格证明要用到一点变分法,这里不展开,但它的意思可以直接读出来:

⭐ 最优的模型 = 参考模型的概率 × 一个按奖励放大的系数。 奖励高的回答,概率被 exp(r/β) 放大;奖励低的,被缩小。β 越小(绳子越松),放大得越狠。

再看一眼这个式子的形状:exp(某个分数),再除以所有候选项的总和——这就是第 5 讲的 softmax,只不过每个候选项前面多乘了一个"参考模型原本给它的概率"。你可以把它理解成:在参考模型的基础上,按奖励做一次 softmax 式的重新分配。

第 2 步:把式子倒过来,用模型表示奖励

既然最优模型和奖励之间有一个确定的关系,那就可以把它反过来写——用模型的概率去表示奖励。对第 1 步的式子两边取对数,整理一下:

r(回答) = β × log( π*(回答) / π_ref(回答) ) + β × log Z

⭐ 这一步的意义非常大:奖励不再需要一个单独的模型来输出了,它可以由"最优模型和参考模型的概率之比"直接算出来。模型本身,就隐含着一个奖励函数。

第 3 步:代进偏好概率,Z 被消掉了

回忆第 17 讲训练奖励模型时用的偏好概率:

P(好回答胜过坏回答) = σ(r_好 − r_坏)

第 17 讲专门强调过一个性质:只有分数的差值重要,给两个回答同时加 100 分,胜负概率完全不变。

现在把第 2 步的式子代进去。好回答和坏回答是针对同一个问题的,所以它们的 β × log Z 一模一样,相减之后正好抵消:

r_好 − r_坏 = β × log(π*(好)/π_ref(好)) + β log Z
            − β × log(π*(坏)/π_ref(坏)) − β log Z
            = β × [ log(π*(好)/π_ref(好)) − log(π*(坏)/π_ref(坏)) ]

⭐ Z 消失了。 这件事很关键,因为 Z 是"对所有可能的回答求和"——所有可能的回答是一个天文数字,Z 根本算不出来。它被抵消,是整个推导能落地的前提。第 17 讲那句"只有差值重要",在这里变成了决定性的一步。

第 4 步:得到 DPO 的损失

把上面的差值塞回 −log σ(...) 里,把 π* 换成我们正在训练的模型 π,就得到了 DPO 的损失函数:

损失 = −log σ( β × [ log(π(好)/π_ref(好)) − log(π(坏)/π_ref(坏)) ] )

看看这个式子里有什么:

  • 正在训练的模型 π
  • 参考模型 π_ref(参数冻结不动,只用来提供对照)
  • 偏好数据里的"好回答"和"坏回答"

没有奖励模型,没有强化学习,没有抽样。算 log π(回答) 就是第 13 讲算交叉熵时本来就在算的东西——把回答里每个 token 的对数概率加起来。整个训练就是一个普通的梯度下降,和第 16 讲的 SFT 一样简单。

DPO(直接偏好优化):利用"带 KL 约束的奖励最大化问题有闭式最优解"这一性质,把奖励用模型与参考模型的对数概率比来表示,从而直接在偏好数据上用一个分类式的损失训练模型,跳过奖励模型训练和强化学习。

β × log(π(回答)/π_ref(回答)) 这个量有个名字,叫隐式奖励(implicit reward):它就是第 2 步里"模型本身隐含的那个奖励"。DPO 训练的效果,就是让好回答的隐式奖励高过坏回答。

手算一遍

取 β = 0.5。某条偏好数据里,参考模型给好回答和坏回答的对数概率都是 −10(参考模型觉得两个差不多)。

训练开始时,正在训练的模型就是参考模型的一份拷贝,所以:

log(π(好)/π_ref(好)) = −10 − (−10) = 0
log(π(坏)/π_ref(坏)) = −10 − (−10) = 0

β × (0 − 0) = 0
σ(0) = 0.5
损失 = −ln(0.5) ≈ 0.693

模型对"哪个更好"毫无倾向,胜负概率五五开。

训练一段时间后,模型给好回答的对数概率涨到了 −8,给坏回答的降到了 −12:

log(π(好)/π_ref(好)) = −8 − (−10)  = +2    ← 好回答比参考模型"更被看好"了
log(π(坏)/π_ref(坏)) = −12 − (−10) = −2    ← 坏回答比参考模型"更不被看好"了

β × (2 − (−2)) = 0.5 × 4 = 2
σ(2) = 1 / (1 + e^(−2)) ≈ 0.881
损失 = −ln(0.881) ≈ 0.127

⭐ 注意模型被推动的方向:不是把好回答的概率推到最大,而是相对于参考模型,把好回答往上提、把坏回答往下压。度量的起点始终是参考模型——这就是第 17 讲那根"KL 绳子"在 DPO 里的样子,它没有消失,而是被直接写进了损失函数的形状里。

再看梯度。对括号里的差值求导,得到的推力大小是 1 − σ(差值):训练开始时是 1 − 0.5 = 0.5,训练后是 1 − 0.881 ≈ 0.12。这和第 17 讲奖励模型的梯度是同一个形状:排序还没拉开的数据用力推,已经拉开的轻轻推。这并不奇怪——DPO 本来就是把"训练奖励模型"这一步,直接做在了语言模型身上。

四、省掉的两步,丢掉了什么

RLHF(PPO) DPO
训练阶段 训练奖励模型 → 强化学习 一步
训练时内存里的大模型 策略、参考、奖励,通常还有一个辅助模型 策略、参考
训练时要不要让模型现场生成回答 要,边生成边打分 不要,只用现成的偏好数据
稳定性 容易发散,调参难 接近普通的监督训练

表格最后两行,是 DPO 最大的优点,也是它最大的代价的来源。

⭐⭐ DPO 是离线的:它只从一份固定的偏好数据里学,从不看自己新生成的回答长什么样。

RLHF 的第 3 步是在线的:模型不停生成新回答,奖励模型对这些新回答打分。随着模型进步,它会写出偏好数据里从未出现过的回答,而这些回答也会得到评价——模型能在自己真正会走到的地方得到反馈。

DPO 没有这个环节。偏好数据里的回答,是某个更早的模型生成的;训练中的模型越走越远,它真正会生成的回答,和偏好数据里那些回答的差别也越来越大——它在一片越来越陌生的地方,拿着一张越来越旧的地图。强化学习里有个说法叫"探索":自己去试,自己得到反馈。DPO 放弃了探索。这个代价在"风格、语气、格式"这类对齐任务上不太明显,但在需要反复尝试才能找到正确路径的任务上(比如多步推理)会变得很大——这正是第 19 讲的推理模型又回到强化学习的原因之一。

⚠️ 只看差值,会带来一个反直觉的现象。DPO 的损失只关心"好回答的隐式奖励比坏回答高多少",不关心各自的绝对值。于是可能出现:好回答和坏回答的概率同时下降,只是坏回答降得更多——差值拉开了,损失降下来了,但模型给"好回答"的概率反而比训练前低了。被挤走的概率去了哪里?去了偏好数据里根本没出现过的回答上。这不一定是坏事,但它说明 DPO 学到的是"相对顺序",不保证"好回答本身更可能被说出来"。

⚠️ 偏好数据的所有老问题,DPO 一个都没解决。第 17 讲第四节讲的那些隐患——偏好有噪声、有立场,“人更喜欢"不等于"更正确”——全部原样继承,因为 DPO 用的还是同一份偏好数据。古德哈特定律也还在:奖励模型被换成了"隐式奖励",但优化的依然是一个近似的代理指标。DPO 省掉的是工程上的麻烦,不是对齐本身的难题。

五、这一类方法还在往哪些方向演进

⚠️ 关于时效性:DPO 之后出现了大量变体,名字和细节更新得非常快,这里不列具体方法,只讲它们在调整哪几个设计维度——这些维度比具体方法的名字更不容易过时:

  • 数据形式:有的方法不需要"成对"的比较,只需要单个回答被标成"好"或"坏",数据收集更便宜。
  • 要不要参考模型:有的方法把参考模型也省掉,进一步降低内存,代价是少了那根"绳子"的直接约束。
  • 离线还是在线:针对第四节那个"旧地图"问题,有的做法让模型定期生成一批新回答,再给这批新回答收集偏好,一轮一轮迭代——介于纯离线的 DPO 和完全在线的 RLHF 之间。
  • 偏好由谁来给:人工标注又贵又慢,一个重要趋势是让另一个模型按照一份写明的原则去做比较判断,代替或补充人工,这类思路常被称为 RLAIF(基于 AI 反馈的强化学习)。它能大幅扩大偏好数据的规模,但也把问题转移到了"那个做判断的模型,和那份原则,本身是否可靠"上。

六、和后面课程的关系

  • 第 19 讲(推理模型与 RLVR) 会重新回到在线的强化学习,把第四节 DPO 放弃的"探索"拿回来,同时把奖励换成可以客观验证的对错,绕开第 17 讲的奖励作弊问题。
  • 第 20 讲 会把 SFT、RLHF、DPO 放在一起看:这些方法到底改变了模型的什么,又没有改变什么。
  • 第 29 讲(幻觉):第四节说 DPO 原样继承了"人更喜欢不等于更正确"这个问题,那一讲会讲这件事对"模型说错话"意味着什么。

七、本讲小结

  • DPO 回答了第 17 讲的问题:可以跳过奖励模型和强化学习,直接用偏好数据训练模型,而且追求的和 RLHF 是同一个目标。
  • ⭐ 推导四步:带 KL 绳子的奖励最大化问题有闭式最优解(参考模型 × exp(r/β),形状就是 softmax)→ 倒过来,奖励可以用模型与参考模型的对数概率比表示 → 代进偏好概率,归一化常数 Z 因为"只有差值重要"而抵消 → 得到只含当前模型和参考模型的损失。
  • 隐式奖励 β × log(π/π_ref):模型本身就是一个奖励模型。手算显示,训练把好回答相对参考模型往上提、把坏回答往下压,KL 绳子被写进了损失函数的形状里;梯度的形状和第 17 讲奖励模型的完全一样。
  • ⭐⭐ 最大的代价是离线:DPO 只从一份固定的偏好数据里学,从不评价自己新生成的回答,放弃了探索——这是第 19 讲回到强化学习的原因之一。
  • ⚠️ 只看差值,可能出现好坏两个回答的概率同时下降;偏好数据的老问题一个都没解决。DPO 省掉的是工程麻烦,不是对齐本身的难题。

思考题

  1. 在第三节的手算里,如果训练后模型给好回答的对数概率是 −9、坏回答是 −11(β 仍为 0.5),损失是多少?和例子里的 0.127 相比是大是小?为什么?
  2. 第三节第 3 步说 Z 能被抵消,是因为好回答和坏回答针对的是同一个问题。如果一条"偏好数据"比较的是两个不同问题的回答,Z 还能抵消吗?这对偏好数据的收集方式提出了什么要求?
  3. 第四节说可能出现"好回答和坏回答的概率同时下降,只是坏回答降得更多"。请构造一组具体数字(参考模型两者都是 −10),让损失比训练前更低,但好回答的对数概率也比 −10 更低。
  4. 用"越来越旧的地图"这个比方解释:为什么离线训练在"让回答语气更礼貌"这类任务上问题不大,但在"学会解一道需要十步推理的数学题"这类任务上问题会变大?
  5. RLAIF 用另一个模型代替人来做偏好判断。结合第 17 讲的古德哈特定律,如果做判断的那个模型有某种系统性的偏好(比如偏爱更长的回答),被训练的模型会学到什么?这和人工标注时的问题相比,是更容易发现还是更难发现?