文章讲解 DPO(直接偏好优化)为何无需单独训练 reward model:用冻结参考模型计算 log ratio 作为隐式 reward,直接套用 Bradley–Terry loss 训练。以煮鸡蛋例子演示,β=1 时最优模型让最佳回答占比从 12% 升至 39.5%,错误回答从 8% 降至 1.3%。文中还解释 KL penalty 与冻结参考模型如何防止模型塌缩到高分回答。
https://x.com/i/article/2118652439049986048
LLM 其实是一个 reward model:DPO
Your Language Model is Secretly a Reward Model
这句话是 2023 年一篇斯坦福论文的副标题。
论文提出了 DPO(direct preference optimization,直接偏好优化),副标题就是它的核心想法。
reward model 那篇讲的是一个单独的网络:LLM 的主体加一个打分头,每个回答得到一个数。
RLHF(基于人类反馈的强化学习)还要走第二阶段:chat model 写回答,reward model 打分,RL 再修改 chat model。
DPO 不需要这个外部的 reward model:LLM 本身就是 reward model。它相对起点把一个回答的概率调高或调低了多少,这个量就是该回答的分数。
具体做法是:留一份起点模型的冻结副本,叫 reference(参考模型),然后这样给每个回答打分:
score = β × log(new share / reference share)
这个分数叫 implicit reward(隐式 reward)。它只需要两个概率,不需要打分头,也不需要第二个网络。
然后拿人比较过的两个回答,套用 reward model 的 Bradley–Terry loss。
看 KL 那篇的鸡蛋问题。问 How long should I boil an egg?,参考模型的五种回答比例如下:
- Boil it until it's done.(含糊的回答):40%
- About 10 minutes.:25%
- 一长段话,最后才说到 10 分钟:15%
- Soft-boiled 6–7 minutes, hard-boiled 10–12; then cold water so it peels easily.(最好的回答):12%
- 2 minutes gives a hard-boiled egg.(错误的回答):8%
标注者比较两个回答,选了最好的回答,没选 About 10 minutes。这条记录叫一个 pair(配对)。被选中的是 chosen 回答,没选中的是 rejected 回答。
取 β = 1,看这个配对在三个模型上的结果:
- 起点:模型是参考模型的副本。两个分数都是 0,分差 0,chosen 回答胜出的概率 0.5,loss 0.693。
- 小幅移动:最好的回答升到 22%,分数是 log(0.22 / 0.12) = 0.606,另一个回答仍是 0。分差 0.606,概率 0.647,loss 0.435。
- 最优模型(KL 那篇的最佳折中):两个回答分别占 39.5% 和 30.3%,分数是 1.192 和 0.192。分差 1,概率 0.731,loss 0.313。
训练就是在大量配对上降低这个 loss。不需要采样回答,不需要训练 reward model,也没有 RL 循环。
这里有两个问题:log ratio 为什么能当 reward?为什么降低这个 loss,得到的正是 RL 要找的模型?
本文前半部分回答这两个问题,读过 KL 那篇就够了。后半部分讲 DPO loss 怎样改变模型、能否到达最优模型,以及在真实的 LLM 上要注意什么。
这是后训练系列的第七篇。鸡蛋例子里的概率和 reward 都是示意值,基于它们的计算是精确的。
Objective:每个模型一个分数
先回顾 KL。对每个回答,新比例除以参考比例,再取 log,得到 log ratio。按新模型的回答比例取平均,就是 KL。
什么都没变时 KL 是 0,变得越多越大。小幅移动的 KL 是 0.047。
RLHF 给每个候选模型打一个总分,这个总分叫 objective:
objective = average reward − β × KL
平均 reward 是每个回答的比例乘以它的 reward,再相加。五个回答的 reward 设为 0、1、0.5、2、−1。
β 是 KL penalty 的系数,表示一单位 KL 扣多少分,由训练者选定。取 β = 1:
- 保持参考模型:0.485 − 0 = 0.485
- 小幅移动:0.685 − 0.047 = 0.638
- 永远给最好的回答:2.000 − 2.120 = −0.120
- 最优模型:1.136 − 0.328 = 0.808
最后一行最高,原因后面会讲。写成符号是 J = E[R] − β · KL(π ‖ π_ref)。π 是正在训练的模型,也就是 policy。E[R] 是它的平均 reward。
RLHF 训练有三个信号,分工不同:
- reward 来自冻结的 reward model,进入参数更新,决定往哪个方向走。
- KL 相对冻结的参考模型计算,进入参数更新,限制模型偏离多远。
- gold 是训练从未见过的信号:留出的人工比较、benchmark、人工阅读样本。它只用来评判 checkpoint。
DPO 改动前两个:存好的配对取代 reward model,β 和参考模型直接写进 loss。gold 仍在训练之外。
为什么要有 KL penalty
再看 KL 那篇的第六个回答:Boil it 20 minutes, always, for food safety. Experts agree.
参考模型写出它的比例是 0.5%,2 分钟那个回答降到 7.5%,总和保持 100%。
reward model 很少见到这类回答,给了它 3 分,是所有回答里最高的。它的真实价值,也就是 gold,是 −2。
如果没有 KL penalty,最优模型把 100% 的比例都放在这个回答上。reward 是 3,gold 是 −2。参考模型的 gold 是 0.48。
加上 KL penalty,取 β = 1。这个回答只占 4.3%,真正最好的回答占 37.9%。reward 是 1.22,gold 是 1.00。
reward 下降了,gold 上升了。
DPO 论文指出了 KL penalty 的作用:让模型留在 reward model 准确的那些回答附近,保留回答的多样性,防止模型塌缩到单个高分回答。
此外,参考模型的很多能力 reward model 并不度量。留在参考模型附近,这些能力才能保住。
有了 KL penalty,训练就变成了给参考模型已有的回答重新分配权重。
为什么参考模型要冻结
KL penalty 需要一个固定的起点。
假设每一步只和上一步的模型比较。还是六个回答,分十步朝 reward 偏好的方向移动,每步幅度相同。
相对上一步,每一步的 KL 最多 0.059。相对起点,十步之后的 KL 是 3.61,那个错误回答占到 69%。这正是 KL 那篇结尾过度优化的模型。
用冻结的参考模型,这 3.61 会全部计入 KL penalty。
所以参考模型是起点模型的副本,通常来自 supervised fine-tuning(SFT,监督微调)。它不接收梯度,训练中始终不变,只需多跑一次前向计算。
最优模型:怎么移动都没有好处
回到五个回答。哪个模型总分最高?
有一个检验方法:把一小份比例从一个回答移到另一个回答。如果总分上升,这个模型就还能改进。
检验要用到每个回答的 net value(净值),它衡量给这个回答多一点比例的收益:
net value = reward − β × log ratio
reward 是收益,log ratio 是扣分。一个回答被抬得越高,再抬扣得越多。
小幅移动的 net value 是 0.288、1、0.5、1.394、−1。
从含糊的回答(0.288)移 0.01 给最好的回答(1.394),总分从 0.638 涨到 0.649。所以小幅移动还可以改进。
继续把比例从 net value 低的回答移向高的回答,差距不断缩小,直到五个回答都等于 0.808。这时再移动,总分只降不升。
在最优模型上,给任何回答多一点比例都没有收益。
所有 net value 相等,记作 c,就能解出最优模型:
log ratio = (reward − c) / β
log 的逆运算是 e(约 2.718)的乘方,去掉 log 得到:
new share = reference share × e^(reward / β) × one shared number
公共的数让所有比例加起来等于 1。具体计算分三步(β = 1):
- 乘:每个参考比例乘以 e^reward,得到 0.400、0.680、0.247、0.887、0.029。
- 加:这五个数加起来是 2.243,记作 Z。
- 除:每个数除以 Z,得到 0.178、0.303、0.110、0.395、0.013。
Z 是什么? 乘完之后,五个数的总和是 2.243,还不能当比例用。比例的总和必须是 1,所以每个数都要除以这个总和。Z 就是这个总和,论文里叫 partition function(配分函数)。
最好的回答从 12% 升到 39.5%,错误的回答从 8% 降到 1.3%。写成符号,星号表示最优模型:
π*(y) = π_ref(y) · e^(R(y) / β) / Z
每个回答都保留了一些比例,只是按 reward 重新加权。β 越小,加权越强。
有两点后面会用到。
第一,这是单个问题的解。真实的 LLM 用一组权重服务所有问题,π* 是训练逼近的目标。
第二,Z 要把所有可能的回答都加一遍。五个回答很简单。真实的 LLM 有无数种可能的回答,Z 算不出来。
从模型反推 reward
现在反过来算。假设手上只有参考模型和最优模型,不知道 reward。
每个回答的比例相除,再取 log,得到 −0.808、0.192、−0.308、1.192、−1.808。
reward 是 0、1、0.5、2、−1。每个 log ratio 都等于 reward 减 0.808。
为什么?把最优模型的公式两边除以参考比例,取 log,再乘以 β:
β × log ratio = reward − β × log Z
左边是开头的 implicit reward。右边是真实 reward 减一个常数。这个常数对所有回答都相同,这里是 0.808。
常数里有 Z,真实的 LLM 算不出来。但比较两个回答时,用不着它。
把这个常数记作 c。两个回答减去的是同一个 c,取差时正好抵消:
(reward A − c) − (reward B − c) = reward A − reward B
c 是多少,对差没有影响。Bradley–Terry 只看两个分数的差,所以 Z 不影响结果。
看鸡蛋的例子,最好的回答和 About 10 minutes 比较:
- 用 reward:2 − 1 = 1
- 用 log ratio:1.192 − 0.192 = 1
两个分数都减了 0.808,差不变,都得到 σ(1) = 0.731。
所以,最优模型和真实 reward 对人的选择给出相同的预测。
方法也就有了:去掉 reward,用 β × log ratio 作分数,让模型直接拟合人的选择。
DPO 论文正是这样推导的。它写道:"We start with the same RL objective as prior work." 这个 objective 就是第二节的总分。
π* 的公式前人已经给出。DPO 的贡献是把公式变形,用 policy 表示 reward,再利用 Z 在比较中抵消,写出 loss。
用论文的话说,这样可以 "solve the standard RLHF problem with only a simple classification loss"。
DPO loss 的每一部分都有来源:
- β 是 KL penalty 的系数。
- 参考模型 是 KL 的基准。
- log ratio 是 KL 里面的那一项。
- 配对和 σ 来自 Bradley–Terry。
- Z 的消失 来自取差。
所以,DPO 训练时不计算 KL,却离不开 KL penalty。没有 penalty,最优模型里四个回答的比例都是 0,log(0) 不存在,reward 也就反推不出来。
这个结论还依赖两个假设:
- 人的选择符合某个 reward 下的 Bradley–Terry 模型。
- LLM 足够灵活,能够表示 π*。
用偏好数据训练出的 policy 自带 reward,只差一个比较时看不到的常数。
一个配对上的 DPO loss
DPO 的一条训练样本就是一行数据,和 reward model 用的一样:问题、chosen 回答、rejected 回答。
每一行的计算步骤:
1. 给 chosen 回答打分:β × 它的 log ratio。
1. 用同样的方法给 rejected 回答打分。
1. 取分差,chosen 减 rejected,记作 m。
1. 把分差变成 chosen 回答胜出的概率:σ(m)。
1. loss 是 −log σ(m)。
σ 是 reward model 那篇讲过的 sigmoid。分差 0 对应 0.5,分差很大时接近 1,分差是很大的负数时接近 0。
−log 让概率低的结果 loss 高:
- 分差 −3,分数顺序反了:loss 3.049
- 分差 0,模型还没有偏好:loss 0.693
- 分差 0.606:loss 0.435
- 分差 1:loss 0.313
- 分差 3,明显正确:loss 0.049
loss 永远到不了 0,这一点后面会用到。一个 batch 就对各行取平均。
论文里的写法是:
L = −log σ( β · log[π(y_w) / π_ref(y_w)] − β · log[π(y_l) / π_ref(y_l)] )
y_w 是 chosen 回答(w 代表 winner),y_l 是 rejected 回答。
这就是 reward model 那篇的 loss,只改了一处:分数来自 policy 和参考模型。
这里只看变化。小幅移动给 chosen 回答 22%,给 rejected 回答 25%,分差仍然是正的,因为它相对参考模型抬高了 chosen 回答。
更新力度
这个 loss 怎样改变模型?用 nudge test(微调检验):把一个数改动一点点,看 loss 怎么变。
从分差 0 开始,loss 是 0.6931。分差加 0.01,loss 变成 0.6882,斜率约为 −0.5。精确的斜率是:
- 分差 −3:斜率 −0.953
- 分差 0:斜率 −0.500
- 分差 1:斜率 −0.269
- 分差 3:斜率 −0.047
斜率的大小是 σ(−m),这就是更新力度。顺序反了的配对更新力度大,已经赢下的配对更新力度小。
论文指出这个权重很重要:去掉它的简单版本可能让 LLM 退化。
Gradient(梯度)。 一个输入的斜率是导数。Gradient 是一张斜率清单,每个输入一个数。真实模型每个权重一个数,6 亿参数的模型大约有 6 亿个。
Learning rate(学习率)。 每个数朝降低 loss 的方向改变,改变量是 learning rate 乘以斜率。用 learning rate 1 训练这个配对:
- 分差 0,loss 0.693,力度 0.500
- 分差 0.500,loss 0.474,力度 0.378
- 分差 0.878,loss 0.348,力度 0.294
- 分差 1.171,loss 0.270,力度 0.237
- 分差 1.408,loss 0.219,力度 0.197
分差越大,更新越小,但永远不会完全停下。
分差由两个 log 概率构成,所以更新同时作用在两者上:chosen 回答的 log 概率升高,rejected 回答的 log 概率降低,幅度相等,都要乘以 β。
参考模型是冻结的,不接收任何更新。
Hyperparameter(超参数)。 β 和 learning rate 都是 hyperparameter:由人选定,训练不会改变。两者分工不同。
用普通梯度下降把这个配对训练三次,learning rate 分别取 2、1、0.5,让第一步的大小相同。下面的数字是 chosen 回答的 log 概率升高了多少:
- β = 0.5:1 步 0.50,10 步 2.26,100 步 4.59
- β = 1:0.50、1.51、2.65
- β = 2:0.50、0.95、1.50
β 越大,配对移动得越少就能赢下来,更新力度也衰减得越早。
所以 learning rate 决定速度,β 决定要移动多远。
Adam 这类优化器会缩放每个梯度,β 对速度的影响基本消失,对距离的影响仍然保留。
DPO 论文的默认设置是 β = 0.1、learning rate 1e-6、batch 64。
概率从哪里来
比例的总和必须是 1。一个回答升高,比例总要从别处来。
用最简单的模型来看:一张表,每个回答一个原始数值,也就是 logit。softmax 把五个 logit 变成比例。这叫表格模型,它从参考模型开始。
learning rate 取 1,chosen 回答的 logit 加 0.5,rejected 回答的 logit 减 0.5,另外三个 logit 不更新。走一步之后:
- 含糊的回答:40% 到 40.8%
- About 10 minutes(rejected):25% 到 15.5%
- 一长段话:15% 到 15.3%
- 最好的回答(chosen):12% 到 20.2%
- 错误的回答:8% 到 8.2%
rejected 回答少了 9.5 个百分点,chosen 回答多了 8.2 个百分点。剩下的分给了配对之外的三个回答,因为 softmax 会重新缩放所有比例。
错误的回答上升了。没有配对提到它,所以没有更新把它压下去。
现在这两个回答的分差是 1,和最优模型相同。比例却差得很远:About 10 minutes 是 15.5%,目标是 30.3%;错误的回答是 8.2%,目标是 1.3%。
一个配对只能确定它自己的分差。要到达目标,配对必须覆盖所有回答。
覆盖之后,DPO 能到达 π* 吗?
理想测试
在目标已知的情况下做测试。用表格模型,它能表示任何比例。
再模拟标注者:每行随机挑五个回答中的两个,按真实 reward 用 Bradley–Terry 抽出赢家。训练代码只看到谁赢了,看不到 reward、Z 和 π*。
用 1,000 个配对,一次模拟运行的结果是:
- 运行结果:18.9%、32.5%、12.8%、34.3%、1.4%
- 目标:17.8%、30.3%、11.0%、39.5%、1.3%
两组比例的距离,就是把一组变成另一组要移动多少比例。参考模型距离目标 0.33,这次运行距离目标 0.05。
配对越多,距离越近。八个模拟数据集的平均距离是:
- 10 个配对:0.38
- 100 个配对:0.15
- 1,000 个配对:0.04
- 10,000 个配对:0.01
数据每增加十倍,距离大约缩小到三分之一。这是从样本估计平均值的常见速度。
这个测试还给出两条警告。
配对太少。 只有 10 个配对时,某两个回答常常只比较过一次,只有一个赢家。数据显示这个回答总是赢,而 loss 到不了 0,所以训练会一直扩大这个分差。
在一次这样的运行里,含糊的回答和错误的回答都降到了 0%,比例集中到另外三个回答上。真实训练也只过很少几遍数据:Tülu 2 的 DPO 模型只过了三遍。
β 决定距离。 在理想数据上,以 reward 为单位的分差与 β 无关。最好的回答和 About 10 minutes 的分差是 1。表达这个偏好所需的 log ratio 差是 1 / β:
- β = 4:log ratio 差 0.25,KL 0.02
- β = 1:log ratio 差 1,KL 0.33
- β = 0.1:log ratio 差 10,KL 2.12
β 越小,模型为了表达同一个偏好移动得越远。这个 β 就是 objective 里的 β。
从回答到 token
真实的 LLM 没有回答清单。一条回复的 log 概率是什么?
KL 那篇讲过,回复的概率是各 token 概率的乘积,所以它的 log 概率是各 token log 概率的和。
DPO 计入回答的 token 和 end-of-turn token(轮次结束标记),因为何时停下也是回答的一部分。问题的 token 只是上下文,不计入。
这些总和主要反映长度。按每个 token 约 −1 的示意值,40 个 token 的回复总和接近 −40,60 个 token 的接近 −60。直接比较的话,短回答总是占优。
所以 DPO 看的是相对参考模型的变化。每个回答只和自己的参考值比较,长度的影响大部分被减掉了。
一行训练数据要做四次前向计算:chosen 和 rejected 各过一遍模型,再各过一遍参考模型。后两次不算梯度。
Tülu 3 用的一个变体更进一步:把每个回答的 log ratio 除以 token 数,减轻剩余的长度偏差。
在真实模型上看什么
真实的 LLM 里,所有回答共用一组权重。针对一个配对走一步,其他回答也会变。表格模型看不出这一点。
有五件事需要关注。
第一步。 模型开始时是参考模型的副本,所有分差都是 0。所以 loss 必须从 log 2 = 0.693 开始,配对准确率必须从 50% 开始。否则就是 bug。
训练集和留出集。 训练集的配对准确率比从未见过的配对上升得快。两条曲线的差距说明模型在记忆训练数据,也就是配对太少的问题。
两个概率分开看。 loss 只看分差,而分差有三种扩大方式:
- chosen 升,rejected 降
- 两者都升
- 两者都降
看一个人为构造的例子。最好的回答从 12% 降到 6%,About 10 minutes 从 25% 降到 2.5%,其余比例分给另外三个回答,错误的回答从 8% 升到 11.6%。
分差是 1.609,loss 是 0.182,比最优模型的 0.313 还低。而 chosen 回答的概率减半了。
真实训练中确实会发生这种情况,它叫 likelihood displacement(似然位移)。
Razin 等人在 2024 年指出它可能造成危害。训练模型在 No 和 Never 之间选 No,可能大幅提高 Yes 的概率。在一个安全实验里,Llama-3-8B-Instruct 的拒绝率从 74.4% 降到 33.4%。
他们发现,根源是两个回答在模型看来很相似的配对。
DPO 对 learning rate 也很敏感:Tülu 2 报告说,稳定训练需要 5e-7。
KL。 KL 决定了这个 loss 的形式,但训练既不直接计算它,也不直接限制它。要用 KL 那篇的方法去测:让模型写回复,对 log ratio 取平均。
Gold。 配对准确率也算不上 gold。它只说明模型给两个固定回答的排序和标注者一致。
用户看到的是模型生成的回复。所以真正的检查是在留出问题上生成回复,再评判这些回复。
DPO 论文用 GPT-4 评判生成的回复,并把过度优化在 DPO 中如何表现留作开放问题。
分差变大,只说明 chosen 回答比 rejected 回答领先更多。模型现在写什么,要另外检查。
DPO 也有局限:它只能从给定的配对里学习,训练中无法自己尝试新回答并得到反馈。
它的优势是简单。Tülu 2 在 700 亿参数的模型上跑通了它,Tülu 3 的训练流程把它放在 SFT 和 RLVR 之间。
小结
- DPO 用模型相对冻结参考模型的变化给回答打分:β × log ratio,即 implicit reward。
- 它把 reward model 的 Bradley–Terry loss 用在这个分数上,在存好的配对上训练。不需要单独的 reward model、采样或 RL 循环。
- RLHF 的 objective 是平均 reward 减 β × KL。KL penalty 让模型留在 reward 可信的回答附近。
- 参考模型是冻结的,小步累积起来的距离也会全部计入 KL penalty。
- 在最优模型上,任何小幅移动都没有好处。由此解出最优模型:乘 e^(reward / β),相加得到 Z,再相除。
- 反过来,β × log ratio 等于 reward 减一个常数。比较时常数抵消,所以不需要 Z。
- 每个配对的更新力度是 σ(−m):顺序反了时大,赢下之后小。
- 只有配对里的回答会被直接更新。要到达最优模型,配对必须覆盖所有回答。
- 在理想测试中,DPO 只靠谁赢了的记录就能接近最优模型。配对太少时结果会偏离目标,β 决定移动多远。
- 在真实模型上,要看留出集、chosen 和 rejected 各自的概率、从样本测出的 KL,以及生成回复上的 gold。
系列接下来讲训练时采样回答的方法:PPO 和 GRPO,reward 来自 reward model 或 verifier。
来源:Dongxi 东锡 NLP · x.com