本文包括:
-
GRPO的训练过程:
- 详细解析ORM(Off-policy Reinforcement with Multiple outputs)如何更新参数。
- 解释如何使用多次采样的Output结果计算baseline,以及Advantage计算方法。
- 具体的梯度更新公式与优化过程。
-
PPO的训练过程:
- 详细拆解PPO如何基于每个token的生成作为action,以及partial sequence作为state。
- 讨论如何计算reward,并在终止()时计算score。
- 提供完整的训练流程和参数更新的数学推导。
-
DPO的解释:
- 介绍DPO的基本思想,包括其如何直接优化偏好模型。
- 解析其数学公式和参数更新过程。
- 提供代码示例以帮助理解。
GRPO
GRPO(Generalized/Group Relative Policy Optimization)的训练过程:GRPO是对传统PPO的改进,它通过一次生成多个输出来估计基准(baseline),从而避免了训练一个价值网络。具体来说,对于每个输入(问题)先用当前旧策略( π θ old \pi_{\theta_{\text{old}}} πθold)采样出一组回答 { o 1 , o 2 , … , o G } \{o_1, o_2, \dots, o_G\} {o1,o2,…,oG},然后利用这些离线生成的样本来更新策略参数 ([2501.12948] DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning)。因为采样来自旧策略再更新新策略,这种方法被称为**“多输出的离策略强化学习”(Off-policy RL with Multiple outputs, ORM)。每个输出 o i o_i oi都会通过预先设定的奖励函数**得到一个得分 r i r_i ri(例如根据答案的正确性、格式、一致性等指标打分) (Why GRPO is Important and How it Works) (Why GRPO is Important and How it Works)。然后计算该组样本的平均奖励 r ˉ \bar{r} rˉ(作为baseline)和标准差 σ r \sigma_r σr,用于归一化每个样本的优势值(Advantage) A i A_i Ai: ()
[A_i ;=; \frac{r_i - \bar{r}}{\sigma_r},]
其中 r ˉ = 1 G ∑ j = 1 G r j \bar{r}=\frac{1}{G}\sum_{j=1}^G r_j rˉ=G1∑j=1Grj。这个优势值反映了样本 i i i的奖励相对于同组其他样本的好坏程度 (Why GRPO is Important and How it Works) ()。若 A i A_i Ai为正,表示该回答优于平均水平,若为负则劣于平均。**梯度更新:**有了 A i A_i Ai,GRPO采用策略梯度方法来更新模型参数 θ \theta θ,其目标是提高高于平均水平回答的概率,降低差回答的概率。例如策略梯度的无截断形式为:
[\nabla_\theta J \approx \mathbb{E}{q,;o_i \sim \pi{\theta_{\text{old}}}} \Big[ A_i \sum_{t=1}^{|o_i|} \nabla_\theta \log \pi_\theta(o_{i,t}\mid q,;o_{i,<t}) \Big],]
其中 π θ ( o i , t ∣ q , o i , < t ) \pi_\theta(o_{i,t}\mid q,o_{i,<t}) πθ(oi,t∣q,oi,<t)是新策略生成输出 i i i第 t t t个token的概率。直观来说,如果某输出的 A i A_i Ai较大,梯度将推动模型增加产生该输出序列各token的概率;反之如果 A i A_i Ai为负,梯度会降低生成该序列的概率。为了增强训练的稳定性,GRPO还加入了KL散度正则项限制新策略 π θ \pi_\theta πθ不要偏离初始参考策略 π ref \pi_{\text{ref}} πref太远 ()。综合以上,GRPO的损失函数包含两部分:一是策略梯度项(如PPO中的剪辑目标),利用组内相对优势 A i A_i Ai来更新策略;二是与参考模型的KL惩罚项。例如,带剪辑的GRPO目标可表示为(与PPO类似):
[L_{\text{GRPO}}(\theta) ;=; -\frac{1}{G}\sum_{i=1}^G \frac{1}{|o_i|}\sum_{t=1}^{|o_i|} \min\Big( r_{i,t}(\theta),A_i,; \text{clip}\big(r_{i,t}(\theta),1-\epsilon,1+\epsilon\big),A_i \Big);+;\beta,\textrm{KL}(\pi_\theta \parallel \pi_{\text{ref}}),]
其中 r i , t ( θ ) = π θ ( o i , t ∣ q , o i , < t ) π θ old ( o i , t ∣ q , o i , < t ) r_{i,t}(\theta)=\frac{\pi_\theta(o_{i,t}\mid q,o_{i,<t})}{\pi_{\theta_{\text{old}}}(o_{i,t}\mid q,o_{i,<t})} ri,t(θ)=πθold(oi,t∣q,oi,<t)πθ(oi,t∣q,oi,<t)是新旧策略的概率比, ϵ \epsilon ϵ是剪辑阈值, β \beta β是KL系数。训练时对上述损失关于 θ \theta θ求导并梯度下降,即完成一次参数更新 () ()。直观理解:GRPO通过一次输入多次输出来“自我对比”。模型在同一问题上想出不同答案并打分,如果某答案比分组平均高,它的每个生成动作都会被鼓励;比分组平均低,则被抑制 (Why GRPO is Important and How it Works)。这样,无需价值网络估计基准,直接利用一组输出的平均得分作为动态baseline,使更新方向更稳定有效。下面是一个简化的PyTorch伪代码示例,演示GRPO的核心更新逻辑:
# 假设 prompt 是输入,model 是策略模型,ref_model 是参考模型,reward_fn 是奖励函数
outputs = [model.generate(prompt) for _ in range(G)] # 生成G个输出
rewards = torch.tensor([reward_fn(prompt, out) for out in outputs], dtype=torch.float)
adv = (rewards - rewards.mean()) / (rewards.std() + 1e-8) # 计算组内标准化优势A_i
loss = 0.0
for i, out in enumerate(outputs):
log_probs = model.log_probs(prompt, out) # 该输出序列中各token的对数概率
loss_i = - adv[i] * log_probs.mean() # 每个token共享同一个Advantage
loss += loss_i
# KL正则项:约束新旧策略分布不偏离
loss_kl = kl_divergence(model, ref_model, prompt, outputs) # 计算KL(π_theta || π_ref)
loss += beta * loss_kl
optimizer.zero_grad()
loss.backward()
optimizer.step()
上述代码中,我们对每个输出序列取其平均对数概率乘以优势值作为损失(相当于将优势分配给序列中的所有动作),并加上KL惩罚共同优化。实际实现中通常会对所有样本向量化计算,并使用多步更新(类似PPO迭代多epochs)提高数据利用率 () ()。
PPO
PPO(Proximal Policy Optimization)的训练过程:在RLHF中,我们将语言模型生成建模为一个MDP:状态
s
s
s为当前对话或已生成的部分序列,动作
a
a
a为下一个生成的token。每当模型在状态
s
t
s_t
st下选择了token
a
t
a_t
at,环境(即对话系统)会转移到新状态
s
t
+
1
s_{t+1}
st+1(即序列附加了
a
t
a_t
at)。这一过程持续到模型输出终止符<EOS>
或达到最大长度,构成一个完整的序列(轨迹)。在传统RLHF设置中,奖励通常在序列结束时给出:当生成了完整回答后,通过奖励模型或人工偏好评分为整段回答给出一个分数
R
R
R (The N Implementation Details of RLHF with PPO | ICLR Blogposts 2024)。也就是说,中间各token步骤不单独赋予奖励,只有最后一个token(或终止状态)得到汇总的回报。例如,在OpenAI的实现中,奖励模型对拼接了问答的完整序列做出评价,只提取最后一个token对应的奖励分数 (The N Implementation Details of RLHF with PPO | ICLR Blogposts 2024)。为了将最终奖励
R
R
R分配到序列中的各个动作,PPO引入了价值函数基线:训练一个价值网络
V
(
s
)
V(s)
V(s)去预测从状态
s
s
s(即部分序列)出发还能获得的期望奖赏。对于最终回答,令
s
0
s_0
s0表示初始状态(prompt),
s
T
s_T
sT表示序列结束状态(收到奖励
R
R
R且之后无奖励)。通常设折扣因子
γ
=
1
\gamma=1
γ=1(因为我们关心完整回答的总评分),则对于任意时刻
t
t
t,该时刻的回报
G
t
G_t
Gt就是最终奖励
R
R
R(假设期间无中间奖励)。优势函数
A
^
t
\hat{A}_t
A^t可以通过**GAE(广义优势估计)**从序列末端往前递推计算,但简化起见可近似为
A
^
t
=
R
−
V
(
s
t
)
\hat{A}_t = R - V(s_t)
A^t=R−V(st) (
Policy Gradient Algorithms | RLHF Book by Nathan Lambert
)。直观来说,如果价值网络估计当前部分回答的未来得分偏低(
V
(
s
t
)
V(s_t)
V(st)小但最终
R
R
R高),则
A
^
t
\hat{A}_t
A^t为正,表示实际表现比预期好,应该提升该状态下采取动作的概率;反之若
A
^
t
\hat{A}_t
A^t为负则应降低该动作概率。
参数更新与数学推导:PPO使用剪辑的策略梯度目标来优化策略网络。首先,我们让策略以当前参数 θ old \theta_{\text{old}} θold与环境交互采样数据(即让模型对一批提示生成回答序列),并记录每个序列的log概率 log π θ old ( a t ∣ s t ) \log\pi_{\theta_{\text{old}}}(a_t|s_t) logπθold(at∣st)和状态价值 V θ old ( s t ) V_{\theta_{\text{old}}}(s_t) Vθold(st)。然后对每个token计算新旧策略的概率比: r t ( θ ) = π θ ( a t ∣ s t ) π θ old ( a t ∣ s t ) r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)} rt(θ)=πθold(at∣st)πθ(at∣st)。PPO的策略损失定义为剪辑形式的**“代理(surrogate)”目标函数** ():
[L_{\text{policy}}(\theta) = -\mathbb{E}_{s_t,a_t}\Big[\min{,r_t(\theta)\hat{A}_t,;\text{clip}(r_t(\theta),,1-\epsilon,,1+\epsilon)\hat{A}_t,}\Big] ,]
其中 ϵ \epsilon ϵ是超参数(如0.2)控制策略更新步幅的大小。这个损失近似了原始策略梯度,但当策略更新幅度过大( r t r_t rt偏离1超过 ϵ \epsilon ϵ)时,会使用截断的 1 ± ϵ 1\pm\epsilon 1±ϵ替代,防止单步更新过猛。除了策略损失外,PPO的总损失还包括价值函数损失和熵正则项:价值损失通常是 1 2 ( V ( s t ) − G t ) 2 \frac{1}{2}(V(s_t) - G_t)^2 21(V(st)−Gt)2的均值,用于更新价值网络使其更好地拟合实际回报;熵项 − H [ π ( ⋅ ∣ s t ) ] -H[\pi(\cdot|s_t)] −H[π(⋅∣st)]鼓励策略保持一定的随机性,避免过早收敛。综合起来,PPO每次迭代通过最小化以下目标来更新参数:
[L_{\text{PPO}}(\theta) = \mathbb{E}_{s_t,a_t}\Big[ -\min{r_t(\theta)\hat{A}t,,\text{clip}(r_t(\theta),1-\epsilon,1+\epsilon)\hat{A}t} + c_1,(V\theta(s_t)-G_t)^2 - c_2,H[\pi\theta(\cdot|s_t)] \Big] ,]
其中 c 1 , c 2 c_1, c_2 c1,c2是权衡价值损失和熵惩罚的系数。对上述损失关于 θ \theta θ求梯度可得到策略和价值网络的更新方向。训练流程总结: (1) 先用一个已微调的策略模型作为 π θ old \pi_{\theta_{\text{old}}} πθold与环境交互(即让模型对训练集中收集的一批提示各生成一个回答),并使用当前的价值网络估计每个生成步骤的状态价值;(2) 利用预训的奖励模型对每个完整回答计算一个奖励分数 R R R,减去预先设定的baseline(例如对照模型的得分或一个常数)得到最终奖励信号;(3) 计算每个序列中各token的优势 A ^ t \hat{A}_t A^t(通过 R − V ( s t ) R - V(s_t) R−V(st)或GAE法获得);(4) 基于采样得来的 ( s t , a t , A ^ t ) (s_t, a_t, \hat{A}_t) (st,at,A^t)数据,构建PPO的损失函数,并对策略模型(含价值头)执行多步梯度更新;(5) 更新完成后,将新模型参数作为 θ old \theta_{\text{old}} θold重复采样和训练过程,迭代进行直至收敛。下面提供一个简化的PyTorch风格代码片段,展示PPO一次更新的主要步骤:
# 假设 model 带有策略和价值头,ref_model 为冻结的参考模型用于计算KL,reward_model 为训练好的奖励模型
logits, values = model(prompt) # 前向计算得到策略输出logits和状态价值估计
response = sample_from_logits(logits) # 按策略采样生成完整回答
with torch.no_grad():
reward = reward_model(prompt, response) # 计算最终奖励R(prompt, response)
# 计算每个token的即时奖励,这里只有最后一个token有奖励R,其余为0
rewards = torch.zeros(response_length); rewards[-1] = reward
old_log_probs = compute_log_probs(logits, response) # 记录旧策略下各token对数概率
# 计算优势(这里用简单法:回报 - 价值预测)
returns = compute_returns(rewards, gamma=1.0)
advantages = returns - values.detach() # 用模型预测的值作为baseline
# 再次计算策略在新参数下的log概率(PPO通常会跑多个epoch,这里假定一次)
new_logits, new_values = model(prompt)
new_log_probs = compute_log_probs(new_logits, response)
# PPO策略损失:剪辑比例 r 和 优势
log_ratio = new_log_probs - old_log_probs
ratio = log_ratio.exp()
pg_loss = -torch.mean(torch.min(ratio * advantages, torch.clamp(ratio, 1-eps, 1+eps) * advantages))
vf_loss = F.mse_loss(new_values, returns) # 值函数损失
entropy = -torch.mean(torch.sum(F.softmax(new_logits, dim=-1) * F.log_softmax(new_logits, dim=-1), dim=-1))
loss = pg_loss + c1 * vf_loss - c2 * entropy # 总损失
optimizer.zero_grad()
loss.backward()
optimizer.step()
以上代码演示了对一个prompt样本进行PPO更新的计算流程。在实际实现中,会对多个样本组成的batch并行计算,并且一般使用多线程并行生成样本、经验回放等提高效率。此外,PPO常与KL惩罚配合使用,即在奖励中减去 β K L ( π θ ∣ ∣ π ref ) \beta \,\mathrm{KL}(\pi_\theta || \pi_{\text{ref}}) βKL(πθ∣∣πref)来约束策略不偏离初始模型分布 (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO)) (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO))。这种等价于在损失中直接加入KL项的方法与GRPO思想类似,都能防止模型为了极端提高得分而产生不合适的输出。
DPO
DPO(Direct Preference Optimization)的解释:DPO是一种直接基于偏好数据优化语言模型的新方法。它跳过了传统RLHF中“训练奖励模型+强化学习调整策略”的复杂过程,转而将对人类偏好的优化转换为一个简单的二分类问题 (What is direct preference optimization (DPO)? | SuperAnnotate)。DPO背后的关键思想是:如果我们有用户偏好比较数据(例如对于同一提示 x x x下的两个模型回答 y win y_{\text{win}} ywin和 y lose y_{\text{lose}} ylose,人类更喜欢 y win y_{\text{win}} ywin),那么我们希望直接调整策略 π θ \pi_\theta πθ,使得在 x x x上 π θ \pi_\theta πθ赋予 y win y_{\text{win}} ywin更高的概率而赋予 y lose y_{\text{lose}} ylose更低概率。DPO假设我们有一个参考策略 π ref \pi_{\text{ref}} πref(通常是监督微调后的基准模型),作为行为的先验分布,然后通过偏好数据来更新策略。数学上,可证明在引入一个温度/系数 β \beta β后,RLHF的优化目标(最大化偏好奖励并约束KL散度)存在解析解,其最优策略形式满足 (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024) (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024):
[\pi^*(y|x) \propto \pi_{\text{ref}}(y|x),\exp{\beta,r(x,y)},]
其中 r ( x , y ) r(x,y) r(x,y)是“隐藏的”真是偏好奖励函数。基于此,DPO选择将奖励函数直接参数化为模型本身的一部分:令$ r(x,y) = \beta^{-1}\big[\log \pi_\theta(y|x) - \log \pi_{\text{ref}}(y|x)\big] 。这个形式意味着模型相对于参考模型提高对答案 。这个形式意味着模型相对于参考模型提高对答案 。这个形式意味着模型相对于参考模型提高对答案y 的概率,相当于赋予其更高的隐含“偏好得分”。有了这种假设后,我们就可以直接根据偏好比较数据构造损失函数,使 的概率,相当于赋予其更高的隐含“偏好得分”。有了这种假设后,我们就可以直接根据偏好比较数据构造损失函数,使 的概率,相当于赋予其更高的隐含“偏好得分”。有了这种假设后,我们就可以直接根据偏好比较数据构造损失函数,使\pi_\theta$朝最优策略的方向更新。 (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024)推导出的DPO目标是:
[ \mathcal{L}{\text{DPO}}(\pi\theta; \pi_{\text{ref}}) = -,\mathbb{E}{(x,,y_w,,y_l)\sim D}\Big[; \log \sigma!\Big(\beta \big[\log \frac{\pi\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \log \frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)}\big]\Big);\Big] ,]
其中 ( y w , y l ) (y_w, y_l) (yw,yl)表示在同一提示 x x x下人类偏好选择的“胜出”回答和“不受偏好”的回答对, σ ( ⋅ ) \sigma(\cdot) σ(⋅)是Sigmoid函数 (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024)。这个损失其实就是一个二元交叉熵损失:我们希望模型在给定 x x x时更倾向于 y w y_w yw而非 y l y_l yl,即 log π θ ( y w ∣ x ) − log π θ ( y l ∣ x ) \log \pi_\theta(y_w|x) - \log \pi_\theta(y_l|x) logπθ(yw∣x)−logπθ(yl∣x)尽可能大。为了防止模型过度偏离原始分布,上式中同时减去了参考策略对应的对数比值 log π ref ( y w ∣ x ) − log π ref ( y l ∣ x ) \log \pi_{\text{ref}}(y_w|x) - \log \pi_{\text{ref}}(y_l|x) logπref(yw∣x)−logπref(yl∣x),相当于做了一个基准校正。如果参考模型本来就偏好 y w y_w yw多一些,那么新模型不需要改动太大;反之如果参考模型倾向错误选项,新模型需要显著提高 y w y_w yw概率。**参数更新过程:**DPO训练时不需要环境采样和复杂的RL优化,而是直接利用偏好数据最小化上述损失。对于每个偏好样本 ( x , y w , y l ) (x, y_w, y_l) (x,yw,yl),梯度计算非常直接:就是对 log σ ( β ( Δ log π θ − Δ log π ref ) ) \log\sigma(\beta(\Delta \log \pi_\theta - \Delta \log \pi_{\text{ref}})) logσ(β(Δlogπθ−Δlogπref))求导。其效果是提高 π θ \pi_\theta πθ在 x x x上产生 y w y_w yw的概率、降低产生 y l y_l yl的概率。由于损失仅依赖于策略本身的对数几率差,训练过程稳定且高效 (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO)) (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO))。**直观理解:**可以将DPO看作是在做一个“偏好分类”任务:给定prompt和两个回答,让模型判别哪个是人类偏好的。如果模型倾向错了,就调整参数使偏好答案的概率上升。这等价于用人工偏好数据直接微调模型的输出分布,而不显式训练一个奖励模型再通过RL优化。DPO的优势在于避免了RL的不稳定性和高成本,据报道在许多实验中性能能与甚至优于PPO方式,同时显著简化了实现 (What is direct preference optimization (DPO)? | SuperAnnotate) (What is direct preference optimization (DPO)? | SuperAnnotate)。
为了加深理解,下面给出DPO损失计算的简要代码示例。假设我们有大量偏好对数据,每条包含(prompt, 优选回答, 次选回答),以及一个预训练的参考模型ref_model
:
import torch
from torch.nn import functional as F
beta = 0.7 # 超参数,可调整
# 假设 batch_prompts, batch_win, batch_lose 是当前batch的提示和对应偏好胜出/失败回答文本
# 首先计算参考模型和当前策略模型对两个回答的log概率
with torch.no_grad():
logp_ref_win = ref_model.log_prob(batch_prompts, batch_win)
logp_ref_lose = ref_model.log_prob(batch_prompts, batch_lose)
logp_new_win = policy_model.log_prob(batch_prompts, batch_win)
logp_new_lose = policy_model.log_prob(batch_prompts, batch_lose)
# 计算对数几率差
logit_diff = (logp_new_win - logp_new_lose) - (logp_ref_win - logp_ref_lose)
loss = - torch.log(torch.sigmoid(beta * logit_diff)).mean() # DPO二分类损失
optimizer.zero_grad()
loss.backward()
optimizer.step()
在上述代码中,log_prob
函数计算模型生成指定回答的对数概率。logit_diff
对应上面公式中的方括号内部分:如果胜出回答在新模型中概率本来就高于失败回答,那么logit_diff
为正,
σ
\sigma
σ输出接近1,loss小;反之若新模型还倾向错误答案,loss会大,梯度将推动提高logp_new_win
、降低logp_new_lose
。如此直接利用偏好比较数据进行训练,使模型逐渐内化人类偏好。在DPO框架下,模型本身“暗含”了奖励模型的作用:
log
π
θ
(
y
∣
x
)
−
log
π
ref
(
y
∣
x
)
\log \pi_\theta(y|x) - \log \pi_{\text{ref}}(y|x)
logπθ(y∣x)−logπref(y∣x)即为偏好打分函数的一部分 (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024)。因此训练完成后,我们既得到了优化后的策略模型,也可以用它来评估任意输出的偏好分(相当于提取出一个隐式的奖励模型) (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024) (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024)。总之,DPO通过将RLHF转化为有监督的偏好分类问题,大大简化了对齐训练流程,其核心数学推导如上所述,对于实现人机偏好对齐提供了一种稳定高效的新范式 (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO)) (Simplifying Alignment: From RLHF to Direct Preference Optimization (DPO))。
**参考文献:**DeepSeek团队在论文中首次提出GRPO算法 ([2501.12948] DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning)并用于提升数学推理能力 (Why GRPO is Important and How it Works);Schulman等人提出的PPO算法提供了稳定的策略优化手段,其剪辑目标函数已成为强化学习领域的经典 ();Rafailov等人提出的DPO方法将偏好优化转化为等价的监督学习问题,极大地降低了实现难度 (RLHF without RL - Direct Preference Optimization | ICLR Blogposts 2024)。上述方法各有侧重:GRPO通过组内比较简化了价值估计,PPO通过价值网络和剪辑保证了训练稳定性,DPO则通过闭式解直接跳过了价值建模和环境采样。这些算法共同体现了在大模型对齐领域对高效、稳定训练的追求。