1. 从RLHF到DPO:为什么我们需要绕开强化学习?
如果你玩过大语言模型,肯定听说过RLHF(基于人类反馈的强化学习)这个词。它就像给模型请了个私教,通过人类的“点赞”和“踩”来教模型说人话。但说实话,RLHF这套流程用起来挺折腾的:你得先训练一个奖励模型来模仿人类的打分,再用强化学习算法(比如PPO)去优化模型,整个过程又慢又不稳定,超参数多得能让人调到头秃。
我自己在项目里踩过不少坑。比如奖励模型训偏了,导致强化学习阶段模型直接“摆烂”,生成的内容越来越奇怪;又或者PPO训练不稳定,loss曲线像过山车一样,根本没法收敛。这些问题让我一直在想:有没有更直接、更稳当的办法?
直到DPO(直接偏好优化)出现,我才发现原来路可以这么走。DPO的核心洞察特别巧妙:语言模型本身就可以看作一个隐式的奖励函数。它通过一系列数学变换,把原来“奖励建模+强化学习”的两步走,直接合并成了“一步到位”的策略优化。这就好比你想学做菜,RLHF是让你先背下所有菜谱(奖励模型),再照着菜谱练习(强化学习);而DPO是直接让你在厨房里,看着老师做一遍(偏好数据),然后自己动手调整,整个过程更直观、更高效。
那么,DPO到底是怎么做到的呢?它其实建立在一个关键的数学关系上。在传统的RLHF优化目标里,我们想最大化奖励,同时不让模型偏离原始版本太远(用KL散度约束)。通过一些推导(这里先不展开公式),我们可以发现,最优的策略模型和最优的奖励模型之间,存在一个简洁的解析关系。DPO正是利用了这个关系,把对奖励模型的学习,直接“重参数化”成了对策略模型的学习。这样一来,我们就不再需要显式地训练一个独立的奖励模型,也不用和复杂的强化学习算法打交道了。
2. 拆解DPO损失函数:从直觉到公式
理解了DPO的动机,我们再来看看它的核心——损失函数。别看公式有点长,拆开来看其实非常直观。我们先从最基础的偏好数据说起。
假设我们有一条用户提问(prompt)x,比如“解释一下什么是人工智能”。模型生成了两个回答:y+(正样本,人类觉得好的回答)和y-(负样本,人类觉得不好的回答)。DPO的目标很明确:让模型更喜欢生成y+,而不是y-。
怎么量化这个“更喜欢”呢?DPO引入了一个巧妙的比较:它不看模型输出的绝对概率,而是看当前策略模型和一个固定的参考模型之间的相对概率变化。参考模型通常就是经过基础指令微调(SFT)后的模型,可以把它理解为“原始版本”。
DPO损失函数的标准形式长这样:
L_DPO(θ) = - E [ log σ( β * ( log[π_θ(y+|x)/π_ref(y+|x)] - log[π_θ(y-|x)/π_ref(y-|x)] ) ) ]
别慌,我们一步步拆解:
- 核心比较项:
log[π_θ(y|x) / π_ref(y|x)]。这个比值衡量了当前模型相对于参考模型,对某个回答的“偏好程度”。如果这个值变大,说明当前模型比参考模型更倾向于生成这个回答。我们可以把它看作一个隐式的奖励信号。 - 计算偏好差异:用正样本的隐式奖励减去负样本的隐式奖励,即
(奖励_y+) - (奖励_y-)。我们希望这个差值越大越好,这意味着模型能清晰地区分好坏回答。 - Sigmoid转换:通过
σ函数(即1/(1+e^{-z}))将差值映射到0到1之间,解释为“正样本优于负样本的概率”。然后取对数log σ(...),这就是经典的二元分类交叉熵损失的形式。 - 加上负号:因为我们要最小化损失,所以前面加个负号,等价于最大化
log σ(...)内部的那个差值。 - 温度系数 β:这是一个超参数,它像一个“调节旋钮”,控制着偏好信号的强度。β 越大,模型对偏好数据的反应就越“激进”,会更努力地拉开好坏回答的差距;β 越小,模型就越“保守”,会更倾向于保持和参考模型类似的行为。我们后面会专门讲怎么调它。
我举个生活化的例子。假设参考模型是个中庸的厨师,做菜口味打7分。当前模型(我们正在训练的)尝试创新。对于一道成功的菜(正样本),它做出了8分的味道;对于一道失败的菜(负样本),只做出了5分的味道。那么隐式奖励的差值就是 (8-7) - (5-7) = 1 - (-2) = 3。这个正差值说明当前模型的创新是成功的,它能做出更棒的菜,同时也能避免做出更差的菜。DPO损失函数就是在鼓励这种“扩大优势、避免劣势”的行为。
3. 梯度推导:看损失函数如何“指导”模型更新
光有损失函数还不够,我们得知道模型参数应该朝哪个方向调整,这就是梯度计算。理解梯度有助于我们看清DPO是如何“发力”的。我们来动手推一下(放心,只用到链式法则和一点Sigmoid函数的性质)。


1004

被折叠的 条评论
为什么被折叠?



