必备知识
重要性采样
基本概念
问题定义
- 函数
,需从分布 中采样,来 计算期望值 - 但现在很难从
中采样
方法
- 从另一个分布
中采样( 容易),间接达到从中采样的效果( 困难)
- 总结
重要性权重
: 用来修正采样的偏差,即两个分布之间的差异
IS是特殊MC采样
- 重要性采样也是一种
特殊的MC采样 - 允许
从简单分布采样,避免直接从困难分布采样的问题。
重要性采样的缺点
方差大
和 差异大时,方差很大,尽管期望相同。越接近 ,方差越小; 必须尽可能接近 - 为什么分布接近方差小?见降低方差方法的公式推导 👍
依赖足够多的采样
当q和p差异大时,需通过足够多的采样,抵消差异对期望的影响- 如果
采样次数不够多,期望会有很大差异。和 会 有很大差异
- 比如下图
本身是负的;- 但由于
q和p差异大,大部分q都只能采样到正的,导致期望不对
需足够多的采样,才能采到左边点,并给与其大权重,才能保证期望一致。
- 如果
采样具有随机性
- 采样具有随机性,如果
突然采样到方差大的样本,可能朝着错误方向更新。

核心思想
- 增加
约束信任条件
TRPO KL约束
KL约束(TRPO):把和 的 相似性作为的 约束条件,信任区域。
PPO CLIP
CLIP(PPO):把相似性约束条件,直接放回到目标函数中。
重要性采样在RL中的作用
核心作用
- 可实现off-policy,从而
降低RL采样成本,解决采样效率问题,提升训练效率。- on-policy:采样策略和学习策略相同
- 即产出数据的策略和用这批数据做更新的策略是同1个。
- on-policy:采样策略和学习策略相同
更加谨慎地更新模型。
使用方法
- 从
开始,用 和环境交互,得到一批 回合数据。 - 把这批
回合数据重复使用k次去更新模型(off-policy过程)- 第1次,喂给:
- 第2次,喂给:
- ...
- 第k次,喂给:
k次更新后:
- 第1次,喂给:
策略梯度发生变化
- 原始策略梯度
- 引入重要性采样后的梯度:
, 训练数据是从旧策略采样出来的。
重要性权重目标函数
重要性采样策略梯度推导
从定义到期望形式
转换成优势策略梯度
代入重要性采样
- 推导过程
- 推导结果
除以旧策略概率的作用
:为了 加权梯度- 初期:模型不自信,预测概率较小,加权大,
- 模型自信后:就不怎么加权了。
- 如果旧策略和当前策略梯度
冲突较大,会造成过度优化或训不动。 PPO-CLIP信任域 可解。
重要性采样和KL散度的区别
KL 散度
- 第1个参数
q:分子,真实分布,参考分布,旧策略,从分子采样 - 第2个参数
p:分母,近似分布,模型分布,新策略,
- 第1个参数
两种情况
旧策略/当前策略,旧策略看作真实分布ref策略/当前策略,ref策略看作真实分布
KL值变大的含义
认为 概率高,但认为 概率低,模型发生巨大变化,看旧数据,令其惊讶。
KL 作用
- 衡量
2个分布之间的差异、衡量距离,判断off-policy 数据是否已到需丢弃的程度。
- 衡量
IS 权重
- 衡量
新旧策略的更新幅度,自然是用当前策略/旧策略,用于修正梯度
广义优势估计
TD(λ) 简介
背景
- MC:无偏估计,
低偏差、高方差。TD:有偏估计,高偏差、低方差。 - A2C引入优势函数来
缓解了方差,但TD存在高偏差。需要平衡方差和偏差。
- 一个n步回报
: 采样n步,再做自举估计。
- 对多个n步回报估计量进行
加权平均,λ, 平衡了TD偏差和MC方差。- λ接近1,接近MC估计,偏差小、方差大。
- λ接近0,接近单步TD,偏差大、方差小。
定义
GAE n步优势估计
1. 朴素 TD Error 定义
- 时刻
、步长为1、步长为2 的 TD Error定义- 注意:t时刻的即时奖励下标为
,这里 和 前面文章 其实一样的
- 注意:t时刻的即时奖励下标为
- 时刻
、步长为 的 TD Error 定义
2. n步优势估计 定义
n步优势估计 定义公式- 步长
- 步长
3. n步优势估计 迭代计算公式
- 推导
n步优势估计 迭代计算公式- 步长2、3、4
- 步长为
4. 总结 n步优势 定义及计算公式
GAE 多个n步优势估计做加权平均
0. 背景
1. GAE 定义公式
- 对多个
步优势估计量,进行 加权平均(步数从1到n到无穷),引入λ做方差、偏差平衡
2. GAE 推导过程
3. GAE 推导结果
4. GAE估计 vs 单个n步估计
n步优势估计:采样n步,估计优势
GAE 优势估计:多个n步优势估计加权求平均
4. GAE 反向递推公式
- 从最后一个时间步开始,
反向遍历,提高GAE计算效率
5. λ=0时,退化单步TD估计
高偏差、低方差
6. λ=1时,退化完全MC采样估计
低偏差、高方差
GAE中的奖励衰减(LLM)
背景
- 在LLM任务中
- 对最后token,仅
- 对前面的token,环境奖励
, 均为0。RM即时奖励
- 对最后token,仅
TD Error
对中间步
对于最后一步
GAE 优势估计
- 推导过程
- 推导结果
- 当
时,退回MC估计
奖励衰减
- 从公式可看出,
真实外部奖励信号传播回第t个token时,会乘以权重、 - 当λ<1 且 T-t 很大时
前面token收不到任何有效奖励信号。价值模型就无法学习到它们真正的贡献。
λ=1 vs λ<1
- λ<1
- 在
传统RL任务,每一步都有奖励,方差很大, 使用λ<1来降低方差,很有效 - 在
LLM任务,奖励稀疏,依赖自己自举- 如果一开始估计不准,就会导致
错上加错,训练不稳定。 - 带来的
偏差危害(奖励信号衰减)远远大于在降方差方面的好处。
- 如果一开始估计不准,就会导致
- 在
- λ=1:
MC无偏估计,只 依赖环境奖励- 价值模型学习变成
简单的监督学习,非常稳定的梯度下降过程。
GAE 方差公式
基础方差公式
GAE 方差推导
- 方差:由每一项
自身方差和项与项之间的协方差共同决定。 减小λ会给这些项,更小的权重(尤其是后面的项),从而降低总方差。
GAE 总结
1. 时刻TD Error 定义
2. n步优势估计定义
3. GAE定义
对多个n步优势加权平均
4. GAE 计算推导结果
5. GAE 反向递推公式 (实际代码计算用此公式)
6. λ=0/1
- λ=0时,GAE退化为
单步TD估计
- λ=1时,GAE退化
完全MC采样
- TD(λ)/TD(0)/TD(1)
- λ越小,
偏差越大、方差越小(TD) - λ越大,
偏差越小、方差越大(MC)
- λ越小,
GAE 作用
GAE 实现代码
@register_adv_est(AdvantageEstimator.GAE)
def compute_gae_advantage_return(
token_level_rewards: torch.Tensor,
values: torch.Tensor,
response_mask: torch.Tensor,
gamma: torch.Tensor,
lam: torch.Tensor,
):
"""Adapted from https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py
Args:
token_level_rewards: `(torch.Tensor)`
shape is (bs, response_length)
values: `(torch.Tensor)`
shape is (bs, response_length)
response_mask: `(torch.Tensor)`
shape is (bs, response_length). [EOS] mask. The token after [EOS] have mask zero.
gamma is `(float)`
discounted factor used in RL
lam: `(float)`
lambda value when computing Generalized Advantage Estimation (https://arxiv.org/abs/1506.02438)
Returns:
advantages: `(torch.Tensor)`
shape: (bs, response_length)
Returns: `(torch.Tensor)`
shape: (bs, response_length)
"""
with torch.no_grad():
nextvalues = 0
lastgaelam = 0
advantages_reversed = []
gen_len = token_level_rewards.shape[-1]
for t in reversed(range(gen_len)):
delta = token_level_rewards[:, t] + gamma * nextvalues - values[:, t]
lastgaelam_ = delta + gamma * lam * lastgaelam
# skip values and TD-error on observation tokens
nextvalues = values[:, t] * response_mask[:, t] + (1 - response_mask[:, t]) * nextvalues
lastgaelam = lastgaelam_ * response_mask[:, t] + (1 - response_mask[:, t]) * lastgaelam
advantages_reversed.append(lastgaelam)
advantages = torch.stack(advantages_reversed[::-1], dim=1)
returns = advantages + values
advantages = verl_F.masked_whiten(advantages, response_mask)
return advantages, returnsTRPO
Trust region policy optimization
ActorCritic 缺点
存在步长选择困难症
- 学习率太大:导致策略
更新幅度太大,可能使策略性能下降,甚至崩溃。 - 学习率太小:导致策略
更新速度太慢,训练效率低下。 - 虽然简单直观,但
训练不稳定 - 解法:
KL 约束
每次梯度更新都需对
采样效率低,训练过程比较慢- 采样具有随机性,可能偶然
采样到方差大的样本;如果直接信任,可能朝着错误方向更新 - 解法:
重要性采样- 降低采样成本,提升训练效率
- 同时更加谨慎的更新模型
- 重要性采样也
需要两个分布差异不能太大和 分布差异较大 且 采样轨迹数量不够大时,对 的估计不准 - 解法:
KL约束
TD Error 估计优势函数是有偏的
- 具体详细见 TD Error 估计优势 方差偏差问题
- 解决
步长选择困难症- 通过
引入约束或限制,确保每次策略更新不会太大。 - 避免策略崩溃,且保证策略能持续提升。
- 通过
- 引入
GAE平衡偏差和方差 - 使用
重要性采样解决错误方向问题
信任区域
信任区域作用理解
在策略空间中,策略的
近似线性模型能够比较准确预测策略性能。- 在
信任区域,可以信任策略梯度,进行策略更新。 - 离开信任区域,需重新评估策略性能,并
调整更新方向。
- 在
解决重要性采样需要两个分布接近的缺点
和 分布差异较大且采样轨迹数量不够大时,对的 估计不准。- 使用
信任区域做限制。
信任区域是
悟空给唐僧画的安全区- 在圈内,活动是绝对安全的。
- 若要移动,需重新画圈圈,
确保每一步走的安全、稳健。
信任区域定义 (KL约束条件)
其实是定义了一个KL约束,策略空间中的一个KL球,
保证新策略不会偏离旧策略太远,从而保证策略的单调提升
目标函数理解
- 通过调整策略参数
使目标最大化 :正在优化的新策略,是需要寻找的参数 :旧策略、已知的策略参数,第k次迭代
L 目标函数,代理优势函数,衡量了新策略比旧策略 有多好 - L 通过重要性采样计算,利用
旧策略采样的数据,来评估 新策略的表现。 - L > 0:说明
新策略比旧策略好
- L 通过重要性采样计算,利用
约束条件理解
- KL 散度 :衡量
两个概率分布的差异:两个策略在状态s下 完全一样越大,说明新策略比旧策略变化越大。
- 所有状态
上的平均KL散度 需 , 平均差异不能太大,限制在半径为的小范围/ 信任区域内如0.01,信赖域大小
:状态访问分布,访问各状态的概率是多少。 - 根据旧策略访问这些状态的频率分布
来加权,关注 重要状态的策略变化
- 根据旧策略访问这些状态的频率分布
策略目标
核心目标
期望借助当前
找到一个更优 ,使得 : 旧策略、新策略。: 旧策略、新策略。两种符号表示。
只要找到一个新策略,使
,就能 保证策略性能单调递增,推导过程见下文
难点
- 直接求解该式非常困难
, 是 需要求解的新策略- 既用新策略收集样本数据,把所有可能的新策略都拿来收集数据
- 然后判断哪个新策略符合上述条件,
显然是不现实的。
- 解法:直接使用旧策略
的 状态分布- 新旧策略接近时,
状态访问分布变化小,近似是合理的
- 新旧策略接近时,
目标优化
- 直接采用旧策略
的状态分布,忽略两个策略的状态访问分布
动作仍用新策略采样得到,用重要性采样做处理。- 这样就能基于旧策略
采样出的数据,来估计并优化新策略
- 这样就能基于旧策略
KL 约束 (上文信任域空间)
- 增加
KL约束,保证新旧策略足够近
信任区域:不等式约束定义了策略空间中的一个KL球。- 在信任区域中
- 学习策略和环境交互的状态分布,与上一轮策略最后采样的状态分布一致
- 可以基于一步行动的重要性采样使当前学习策略稳定提升
信任区域示意图:左侧无信任区域,梯度更新可能导致性能骤降;右侧有信任区域,每次梯度更新都能带来稳定提升。

广义优势估计
- 对不同TD步数的优势估计进行指数加权平均,平衡方差和偏差
def compute_advantage(gamma, lmbda, td_delta):
td_delta = td_delta.detach().numpy()
advantage_list = []
advantage = 0.0
for delta in td_delta[::-1]:
advantage = gamma * lmbda * advantage + delta
advantage_list.append(advantage)
advantage_list.reverse()
return torch.tensor(advantage_list, dtype=torch.float)PPO
核心思想
背景
- TRPO计算复杂, 每步更新
运算量非常大。 - PPO基于TRPO思想,但
实现更简单。能学的一样好、甚至更快。
1.引入GAE
- 解决
单步优势的方差-偏差平衡问题。
2.引入重要性采样
- 使用
重要性权重修正分布差异 - 达成
可使用off-Policy,提高采样效率,解决效率问题。
3.引入Clip或Penalty
- 解决
采样方差大& 重要性采样分布差异大+采样数量不足面临的问题 - 使用
Clip或Penalty增强训练稳定性 - 把
和 的 相似性作为的 约束条件。- TRPO:用
KL约束做一个信任区域 - PPO:把
约束条件放到中做优化,CLIP 或 Penalty。
- TRPO:用
PPO-Clip
Clip 核心思想
引入IS和GAE后的优化目标
为什么需要CLIP
考虑
采样不足的情况下,和 分布差异不能太大因此
是 有上限和下限的,需保证在信任域内。不能一味轻信, 来提升或降低。
CLIP 核心思想
- 通过
CLIP裁剪+MIN函数,限制策略更新幅度,来保证训练稳定性。 - 限制
重要性权重在一个信任域内,超出信任域就裁切。- 约束
新旧策略和 尽可能接近相似,限制更新幅度不要太大,保证训练稳定性 - 希望
采样策略和学习策略的差距不要太大。
- 约束
CLIP 信任域
优化目标
- 不做KL散度约束,直接把
CLIP 信任域放到目标函数中
Clip 到底做了什么
有无CLIP公式对比
无限制的策略梯度目标:有限制的策略梯度目标:,IS权重 裁剪到
- 比例
一旦 超出范围,变量就变为一个常数,对常数求导为0,导致梯度为0。
对于好动作
目标:
提高概率,即增大当
时:一切正常 当
时:变成 , 没有梯度- 旧策略计算出的
常数,和当前优化参数无关 - 意味着
IS差距大的token梯度为0,无法进行梯度更新,该token被硬丢弃。
- 旧策略计算出的
对于差动作
目标:
降低概率,即减小当
时:变成 同理,
没有梯度IS差异大的token,无法进行梯度更新,该token被硬丢弃。
默认无clip
- 策略梯度
- 推导梯度项
- 项1:
正向推力,提高的 logit分数 - 项2:
反向抑制,按概率加权降低其他动作的logit分数
带clip的策略梯度
比例
一旦 超出范围,变量就变为一个常数,对常数求导为0,导致梯度为0。在clip区域之外的所有梯度均为0,在clip区域 范围外,不会做提升,在clip区域 范围外,不会做抑制
PPO-CLIP 梯度简洁写法


Clip 改进工作
PPO-Penalty
KL 惩罚约束行为距离
- 使用
KL散度约束行为上的距离,而非参数上的距离,因此无法用L12范数等距离法。
- 对
KL散度设置阈值
自适应KL惩罚beta参数
- 超参
的调整策略:自动调节 自适应KL散度 新策略偏离旧策略太远,应该增大, 把分布拉回来
新旧策略相近,可能只优化KL散度,不去优化优势相关的项。- 应该减小
, 降低KL散度对目标的影响。
优化目标
- 原始优化目标
- 引入KL 惩罚后的优化目标
Actor
策略目标
普通优势策略目标
TRPO策略目标
PPO-Clip Seq-Level 策略目标
PPO-Clip Seq-level Loss
相关笔记
Token-Level Loss变体,2级平均,token-mean是目前主流。
PPO-Clip Token-level 策略目标
PPO-Clip Token-level Loss
直接对所有Token做平均,每个token权重相同,不论来自长或短序列。
PPO Loss
Actor在PPO epoch中,使用同一批数据做迭代更新的。
重要性权重/比率做Clip
- 为了稳定性,会对
重要性权重做CLIP截断
negative_approx_kl=log_prob-old_log_probnegative_approx_kl= torch.clamp(negative_approx_kl,min=-20.0,max=20.0)
PPO Loss
PPO Dual-Clip Loss
负优势IS大权重时CLIP失效
当
且 时 MIN机制
选择更小的负数,Loss变成绝对值巨大的负数,产生巨大梯度,导致训练不稳定负优势+IS权重大时CLIP机制失效,惩罚太大梯度无限制。如
Dual-Clip Loss
- 在优势
时, 额外增加一个裁剪 负优势+IS权重偏差很大,限制惩罚力度- 这个
token的loss,最大不能超过优势绝对值*clip_ratio_c=3
熵奖励
相关笔记
背景
熵是信息量的期望,衡量不确定性的程度。熵越大,不确定性越大。- RL容易
陷入局部最优,停止探索。为了鼓励探索,增加熵奖励。
计算方法
- 熵系数
entropy_coef+ 熵lossentropy_loss,response每个生成token熵的平均值 - agg_loss(loss_mat=
entropy, loss_mask=response_mask, loss_agg_mode=x) - 熵奖励:
entropy_coeff*entropy_loss
if calculate_entropy:
entropy = output["entropy"][:, -response_length - 1 : -1].contiguous()
entropy_loss = agg_loss(loss_mat=entropy, loss_mask=response_mask, ...)
entropy_coeff = meta_info["entropy_coeff"]
# 核心:从PPO损失中减去熵损失(乘以一个系数)
policy_loss = pg_loss - entropy_coeff * entropy_loss KL 惩罚
背景
- RLHF中通常有一个SFT或基座的
模型, 有一定能力。 Reward Hacking:如果不约束,模型可能会 走捷径骗过RM,来获取高奖励。
KL Loss 正则化手段
- 给模型上
缰绳,允许追求高奖励、同时又防止跑偏太远。 - GRPO用KL3 散度:无偏且低方差,DeepSeek-V3.2
乘以IS权重做优化,无偏估计。 KL距离vsIS权重区别见上文。
if self.config.use_kl_loss:
ref_log_prob = data["ref_log_prob"]
# compute kl loss
kld = kl_penalty(logprob=log_prob, ref_logprob=ref_log_prob, kl_penalty=self.config.kl_loss_type)
kl_loss = agg_loss(loss_mat=kld, loss_mask=response_mask, loss_agg_mode=self.config.loss_agg_mode)
# 核心:将KL损失(乘以一个系数)加到总损失上
policy_loss = policy_loss + kl_loss * self.config.kl_loss_coef def kl_penalty(logprob: torch.FloatTensor, ref_logprob: torch.FloatTensor, kl_penalty) -> torch.FloatTensor:
"""Compute KL divergence given logprob and ref_logprob. Optionally using straight through to bind k2 on other
kl penalty compute method for unbiased KL gradient estimation.
See more description in http://joschu.net/blog/kl-approx.html
Args:
logprob:
ref_logprob:
Returns:
kl_estimate
"""
forward_score = kl_penalty_forward(logprob, ref_logprob, kl_penalty)
if not kl_penalty.endswith("+") or kl_penalty in ("mse", "k2"):
return forward_score
"""
The expectation of k1 and k3 estimator is the expected value of KL, but the expected gradient of k1 and k3
estimator is not the expected gradient of KL. On the other hand k2 estimator gives right gradient estimator,
so we use a straight through trick here if the kl_penalty method ends with '+', e.g., k3+.
"""
backward_score = 0.5 * (logprob - ref_logprob).square()
return backward_score - backward_score.detach() + forward_score.detach()def kl_penalty_forward(logprob: torch.FloatTensor, ref_logprob: torch.FloatTensor, kl_penalty) -> torch.FloatTensor:
"""Compute KL divergence given logprob and ref_logprob.
Copied from https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py#L1104
See more description in http://joschu.net/blog/kl-approx.html
Args:
logprob:
ref_logprob:
Returns:
kl_estimate
"""
if kl_penalty in ("kl", "k1"):
return logprob - ref_logprob
if kl_penalty == "abs":
return (logprob - ref_logprob).abs()
if kl_penalty in ("mse", "k2"):
return 0.5 * (logprob - ref_logprob).square()
# J. Schulman. Approximating kl divergence, 2020.
# # URL http://joschu.net/blog/kl-approx.html.
if kl_penalty in ("low_var_kl", "k3"):
kl = ref_logprob - logprob
# For numerical stability
kl = torch.clamp(kl, min=-20, max=20)
ratio = torch.exp(kl)
kld = (ratio - kl - 1).contiguous()
return torch.clamp(kld, min=-10, max=10)
if kl_penalty == "full":
# so, here logprob and ref_logprob should contain the logits for every token in vocabulary
raise NotImplementedError
raise NotImplementedErrorPG Loss 代码及实现过程
核心思想
优势*重要性权重,PPO-Clip,PPO-Dual-Clip- Loss 聚合类型:
token-mean、seq-mean-token-mean等。 - 入参:
old_log_prob、log_prob、advantages、response_mask、loss_agg_mode等
相关笔记
1. 重要性权重
IS ratio=torch.exp(log_prob-old_log_prob)
2. 新旧策略PPO_KL监控指标
-(
log_prob-old_log_prob),近似KL,作为观测指标数据采样策略:; 当前学习策略:。Response做Mask,求mean
3. 朴素无clip的 PG Loss
pg_losses1= -advantages*ratio
4. PPO-CLIP PG Loss 计算
根据
clip_range(low和high),对IS权重做clip,再乘以优势,计算pg_losses2pg_losses2= -advantages *torch.clamp(ratio, 1 - cliprange_low, 1 + cliprange_high)
pg_losses1和pg_losses2 选大的,
loss已有负号,应选大的clip_pg_losses1= torch.maximum(pg_losses1, pg_losses2)
计算
pg_clipfrac比例,监控指标,有多少比例的token被clip掉pg_clipfrac= verl_F.masked_mean(torch.gt(pg_losses2, pg_losses1).float(), response_mask)
5. PPO-Dual CLIP Loss 计算
clip_pg_losses2:针对负优势,使用clip_ratio_c=3.0做clip。- 具体原理见 dual-clip-loss
pg_losses3= -advantages * clip_ratio_cclip_pg_losses2= torch.min(pg_losses3,clip_pg_losses1)
6. 最终clip_pg_losses
- 在
优势小于0的token,选择clip_pg_losses2;其余仍选择clip_pg_losses1pg_losses= torch.where(advantages < 0, clip_pg_losses2, clip_pg_losses1)
- 根据
loss_agg_mode做loss聚合
@register_policy_loss("vanilla") # type: ignore[arg-type]
def compute_policy_loss_vanilla(
old_log_prob: torch.Tensor,
log_prob: torch.Tensor,
advantages: torch.Tensor,
response_mask: torch.Tensor,
loss_agg_mode: str = "token-mean",
config: Optional[DictConfig | AlgoConfig] = None,
rollout_is_weights: torch.Tensor | None = None,
) -> tuple[torch.Tensor, dict[str, Any]]:
"""
Compute the clipped policy objective and related metrics for PPO.
Adapted from
https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py#L1122
Args:
old_log_prob (torch.Tensor):
Log-probabilities of actions under the old policy, shape (batch_size, response_length).
log_prob (torch.Tensor):
Log-probabilities of actions under the current policy, shape (batch_size, response_length).
advantages (torch.Tensor):
Advantage estimates for each action, shape (batch_size, response_length).
response_mask (torch.Tensor):
Mask indicating which tokens to include in the loss, shape (batch_size, response_length).
loss_agg_mode (str, optional):
Aggregation mode for `agg_loss`. Defaults to "token-mean".
config: `(verl.trainer.config.ActorConfig)`:
config for the actor.
rollout_log_probs: `(torch.Tensor)`:
log probabilities of actions under the rollout policy, shape (batch_size, response_length).
"""
assert config is not None
assert not isinstance(config, AlgoConfig)
clip_ratio = config.clip_ratio # Clipping parameter ε for standard PPO. See https://arxiv.org/abs/1707.06347.
clip_ratio_low = config.clip_ratio_low if config.clip_ratio_low is not None else clip_ratio
clip_ratio_high = config.clip_ratio_high if config.clip_ratio_high is not None else clip_ratio
clip_ratio_c = config.get( # Lower bound of the ratio for dual-clip PPO. See https://arxiv.org/pdf/1912.09729.
"clip_ratio_c", 3.0
)
cliprange = clip_ratio
cliprange_low = clip_ratio_low
cliprange_high = clip_ratio_high
assert clip_ratio_c > 1.0, (
"The lower bound of the clip_ratio_c for dual-clip PPO should be greater than 1.0,"
+ f" but get the value: {clip_ratio_c}."
)
negative_approx_kl = log_prob - old_log_prob
# KL做CLIP
negative_approx_kl = torch.clamp(negative_approx_kl, min=-20.0, max=20.0)
# IS 重要性权重
ratio = torch.exp(negative_approx_kl)
# old_logprob-logprob,old-采样,logprob-学习,PPO_KL近似KL散度,监控指标
ppo_kl = verl_F.masked_mean(-negative_approx_kl, response_mask)
# 朴素无clip的pg_loss,-优势*重要性权重
pg_losses1 = -advantages * ratio
if cliprange_low is None:
cliprange_low = cliprange
if cliprange_high is None:
cliprange_high = cliprange
# ppo-clip 第二项,对ratio做clip,乘以advantages
pg_losses2 = -advantages * torch.clamp(ratio, 1 - cliprange_low, 1 + cliprange_high) # - clip(ratio, 1-cliprange, 1+cliprange) * A #
# max(-ratio * A, -clip(ratio, 1-cliprange, 1+cliprange) * A)
# ppo clip loss
clip_pg_losses1 = torch.maximum(pg_losses1, pg_losses2)
# ppo clip 比例,有多少loss2 > loss1的
pg_clipfrac = verl_F.masked_mean(torch.gt(pg_losses2, pg_losses1).float(), response_mask)
# dual ppo clip,在优势小于0时,额外增加clip
pg_losses3 = -advantages * clip_ratio_c
clip_pg_losses2 = torch.min(pg_losses3, clip_pg_losses1)
# dual ppo clip 比例
pg_clipfrac_lower = verl_F.masked_mean(
torch.gt(clip_pg_losses1, pg_losses3) * (advantages < 0).float(), response_mask
)
# dual ppo clip,在优势小于0时,额外增加一个裁剪
pg_losses = torch.where(advantages < 0, clip_pg_losses2, clip_pg_losses1)
# Apply rollout correction weights if provided
if rollout_is_weights is not None:
pg_losses = pg_losses * rollout_is_weights
pg_loss = agg_loss(loss_mat=pg_losses, loss_mask=response_mask, loss_agg_mode=loss_agg_mode)
pg_metrics = {
"actor/pg_clipfrac": pg_clipfrac.detach().item(),
"actor/ppo_kl": ppo_kl.detach().item(),
"actor/pg_clipfrac_lower": pg_clipfrac_lower.detach().item(),
}
return pg_loss, pg_metrics总Policy Loss 及代码
相关笔记
- Verl Policy Loss 计算代码
- 朴素PG loss:见上文
核心思想
Policy loss =
PPO损失-熵奖励+KL 惩罚policy_loss =
pg_loss-entropy_coeff * entropy_loss+kl_loss_coef * kl_loss
Policy Loss 增加 Entropy和KL loss
policy_loss = pg_loss
if calculate_entropy:
entropy = output["entropy"][:, -response_length - 1 : -1].contiguous()
if not forward_only:
entropy_loss = agg_loss(loss_mat=entropy, loss_mask=response_mask, loss_agg_mode=loss_agg_mode)
entropy_coeff = meta_info["entropy_coeff"]
policy_loss = pg_loss - entropy_coeff * entropy_loss
else:
ret_entropy = entropy
if forward_only:
policy_loss = torch.tensor(1.0, device=device)
else:
if self.config.use_kl_loss:
ref_log_prob = data["ref_log_prob"]
# compute kl loss
kld = kl_penalty(logprob=log_prob, ref_logprob=ref_log_prob, kl_penalty=self.config.kl_loss_type)
kl_loss = agg_loss(loss_mat=kld, loss_mask=response_mask, loss_agg_mode=self.config.loss_agg_mode)
policy_loss = policy_loss + kl_loss * self.config.kl_loss_coef
metrics["actor/kl_loss"] = kl_loss.detach().item()
metrics["actor/kl_coef"] = self.config.kl_loss_coefVerl 训练观测指标
pg_loss
优势*权重+PPO-Clip+PPO-Dual-Clip后的最终pg_loss。
ppo_kl
采样策略和 学习策略之间的 KL距离。
pg_clipfrac
IS权重被PPO-Clip区间`裁剪的比例
pg_clipfrac_lower
PPO-Clip后,被PPO-Dual-Clip针对负优势,裁剪的比例。
Reward
Reward Model 训练
目标
- 给
(Prompt, Response)打分,输出1个标量。
偏好数据收集
- 1个Prompt,输出多个Response,人类排序
- 偏好数据:
(prompt, chosen_response, rejected_response)
训练目标
好回复的分数比差回复的分数高
Pairwise Loss
:原始分数差;目标: 最大化原始分数差- Sigmoid:模型认为
Chosen比Reject分数好的概率;目标:把概率推向1 :交叉熵loss,对错误概率进行惩罚;目标: 最小化惩罚
Reward Model 即时奖励
RM 打分
在NLP中,RM仅对整个Response打1个分,仅
最后一个token才有奖励,其余设为0。 - 下文Critic目标之一:使
最后一个token的回报接近RM给的奖励
- 下文Critic目标之一:使
打分模型:训练过的
Reward Model或者Rule-Based Func或LLM as Judge等。充当环境的作用,给每一步
即时奖励。
环境奖励信号
环境奖励
最终奖励
- 最终每一步的奖励 =
环境奖励-KL约束,KL 奖励约束见下文
- 由于KL约束非负,除
,其余token的奖励 要么是0、要么是负数。
奖励加入KL散度项
目的
- 确保 PolicyModel
不会偏离 ReferenceModel 太远。 - 如果偏离越大, 负的KL散度奖励,
对策略的抑制也越大。
核心思想
- 对Policy和Reference模型的token预测分布,加入KL项。
KL 负奖励
最终奖励
- 最终奖励 =
环境奖励-KL约束
- 由于KL约束非负,除
,其余token的奖励 要么是0、要么是负数。
Critic
Critic 目标
Critic 核心目标
评估策略效果,Actor更新后,需新的Critic来衡量新策略的价值。
优化价值函数
, 学习真实目标值- 让
预测 尽可能更接近 真实的未来总回报。类比TD Error 定义预测当前策略,从状态出发, 未来总回报的期望值。- 是状态
的价值,不是即时奖励 。
- 让
但我们并不知上帝视角的
真实目标值只能通过MC采样轨迹来估计,也就是Target Value,。
使
最后一个token的回报接近RM给的奖励
Critic 核心作用
- 通过不断“
预测-验证-修正”的过程,Critic 的价值评估能力越来越强。 - 从而能为 Actor 提供
更准确、更稳定的优势信号,最终引导 Actor 学会更好的策略
稀疏的监督信号
- 在LLM RL中,仅
最后一个token有RM给的奖励。 其他token奖励都为0,其他token缺乏合适的奖励信号。- 导致
Critic Model非常难以训练‼️。
Critic 学习过程
标准的监督学习
- 输入:状态
、 - 预测:
、 、 、 - Critic网络 在时间步
对状态 的 价值预测。 是Critic 网络参数
- Critic网络 在时间步
- 目标:
、 、 - 在时间步
,根据实际获得奖励、对真实回报的 估计值。 - 这是
最核心内容,在下文详细介绍计算。
- 在时间步
- Loss:
预测值和目标值之间的差距,MSE loss。
算法流程
采样数据
Actor和环境交互,收集1个batch的轨迹数据
计算旧价值预测
- 使用
当前Critic对每一个状态预测价值,得到,后面作为 固定值
- 使用
计算 TD Error
- 对每个时间步t,计算
TD Error
是环境给的 即时奖励,可通过Reward Model 或 Reward Func给出
- 对每个时间步t,计算
计算 GAE 优势估计
GAE 公式
从最后一个时间步开始,
反向遍历,提高GAE计算效率
计算 Critic 目标值:利用
GAE优势+旧价值预测
计算 Critic Loss (见下文详细说明)
在PPO多个优化子周期(epoch)里,对batch中每个数据点
把
输入到 正在更新的Critic网络,得到新预测值利用
Critic 目标值和Critic 最新预测值,计算MSE Loss根据Critic Loss调整Critic网络,
争取下次预测的更准。
Critic Loss
Loss函数
- 实际训练中,从收集到的数据,取batch,计算batch上所有时间步的平均loss
Critic目标值/真实回报目标值计算
最核心部分,
计算方法直接 影响Critic的学习效率和稳定性优势函数计算
朴素优势函数:优势函数趋于0的理解
- 要估计Q和V2个网络,
复杂。
- 要估计Q和V2个网络,
- 仅V一个网络,但偏差大,TD Error 估计优势 方差偏差问题`
- 综合多个n步优势估计
- 综合多个n步优势估计
计算 ‼️ 目标回报Q值= 优势值 + V值Critic 学习目标是
真实回报,可以看作是的一个估计,得到 请注意
:用当时旧的Critic网络预测并记录下来 旧的、固定的值,在GAE之前- 当做常数,不参与梯度计算。
: 值计算出来的。
理解 基于旧价值函数的估计+这个估计的修正量(优势值)= 得到更精确的回报估计。
Critic Loss 深入理解
TD Error
Critic Loss
TD Error 类比
GAE 优势 推导
- 反向递推公式
- 推导结果
目标回报值 推导
- R = A + V
- 推导结果
- 其实在朴素单步TD目标值基础上加了一个
GAE估计。
- 其实在朴素单步TD目标值基础上加了一个
代入计算Loss
- 和 A2C 中优势趋于0的理解是
完全一致的。
Critic Value Clip
背景
- 稳定训练技巧,
防止Critic网络更新过大,对新价值预测做裁剪。
价值更新裁剪
是超参 例如(0.2),和Actor Loss 裁剪范围通常相同。
计算未裁剪和裁剪后的2个loss
未裁剪
裁剪后
最终Critic Loss 取较大者
具体稳定训练过程思考
建立信任区域
围绕旧值
建立信任区域,相信 旧价值预测大体上是正确的。确保
新价值预测不会离 旧价值预测太远。预测价值本该朝向目标回报靠近,但若预测价值超出信任区域,则应该Clip。
防止因目标值不准而过度更新
是由 GAE计算出来的,是估计值,存在方差。
保持 Actor和Critic 更新步调一致
- PPO核心是限制策略更新幅度,为Actor提供指导信号的Critic也应该限制更新幅度。
- 防止Critic剧烈变化导致下一轮优势估计出现波动,导致Actor训练不稳定。
重要性采样
策略梯度
- 交互策略
:与环境交互,采集大量数据来训练 - 学习策略
:要训练学习的网络 更新多次后,再去更新
优势策略梯度
- 优势作权重
- 引入重要性采样
- 优势应是
演员和环境交互计算出来的
目标函数
优点
- 可通过重要性采样把同策略换成异策略
GAE
- 对不同步数的TD优势估计进行指数加权平均,平衡方差和偏差
算法流程
PPO算法流程
- 初始策略参数
- 每次迭代
- 用旧策略
和环境交互,采样大量 对 - 根据
交互结果,估计 - 采样到这组数据后,最大化目标函数
- 可以让
更新很多次
- 用旧策略

PPO 调参踩坑经验
主要坑点
- Critic初始化
- 要用预训练权重, 随机初始化基本gg
- KL散度监控
- 超过0.02就要降学习率,不然策略会崩
- 内存管理
- 内存需求爆炸,双网络+梯度存储
- 超参数敏感
- 学习率、裁切范围,都很敏感
部分参数
- learning_rate:3e-4直接爆炸,降到1.5e-5才稳定
- batch_size:小于128,训练震荡严重
- clip_range:跳到0.4后,策略变化太激进
# 稳定的PPO配置(13B模型)
ppo_config = {
"learning_rate": 1.5e-5, # 别用太大,容易崩
"clip_range": 0.2, # 经典值,基本不用改
"batch_size": 256, # 越大越稳定
"gae_lambda": 0.95, # GAE参数
"value_loss_coef": 0.5, # 价值损失权重
"entropy_coef": 0.01, # 探索系数
"max_grad_norm": 1.0, # 梯度剪切
"n_epochs": 4, # 数据重用次数
}缺点不足
GAE带来的计算开销大、训练不稳定
- GAE 主要依赖于单步时序误差
- 计算TDError之前,需为每个token计算
奖励和价值- 每个token的价值:
需由独立的Critic模型计算得到 - Critic通常和策略模型同架构和大小,Critic
计算开销非常大,且训练不稳定导致无法提供准确的价值信号
- 每个token的价值:
DPO
标准RLHF目标
标准RLHF目标-tradeoff
- 最大化奖励:
生成的回答 , 从奖励模型尽可能获得高分 - 不要偏离太远:约束策略
和参考策略 保持一定相似性。
- 奖励函数
标准RLHF训练流程
先训rewad model
再通过PPO训Actor Model
PPO缺点 & DPO动机
PPO 缺点
- 计算复杂、成本高
- Actor、
CriticModel(估计价值,降低梯度估计中的方差)、RewardModel(奖励信号)、SFTModel (KL散度)
- Actor、
- 训练不稳定
奖励稀疏、梯度更新不稳定、收敛困难、参数敏感等
- Reward Hacking
- RM从有限的人类偏好数据中学习的,不可避免存在
缺陷和偏差。 - 策略在优化过程中,发现并利用RM的漏洞,获得高分
但实际不符合人类预期的输出。 - 把复杂抽象的人类价值观,压缩成简单的标量信号,是
很困难的。
- RM从有限的人类偏好数据中学习的,不可避免存在
DPO 动机
- 把带有KL约束最大化奖励目标,等价替换成简单的
直接在偏好数据上进行优化的分类问题。 - 把对齐问题重定义为最大似然估计问题,
简单二元交叉熵loss,直接对偏好Pair数据优化。 - 完全绕过
显示奖励模型训练和复杂RL训练。这两个恰好是RLHF中最贵和不稳定的环节。 - 并非性能上超越RLHF,而是
工程上的成功。更稳定、更轻量、更容易实现。
理论基础
显示最优解
PPO式子理论存在显示最优解
- 理论最优解:通过完美奖励函数
计算出完美策略模型,不需要迭代式的强化学习。 最优策略、参考策略、奖励函数之间的确定性关系。
:归一化因子、分配函数,确保给定x, 所有y概率加起来等于1
显示最优解推导过程
显示最优解推导过程
- 推导1
归一化分母,构建
,以及新的概率分布 代入目标式子,得到KL散度
- KL散度在2个分布相等时取最小值,因此RLHF训练希望得到的最优概率分布就是
反解奖励函数
反解奖励函数
- 直接转换
定义,反解出隐式奖励函数
DPO和RM目标loss一致
奖励函数带入奖励loss
- RewardModel 训练目标 和 DPO 训练目标一致
DPO目标和Reward Model一致
- DPO对标的是RewardModel
训练数据一致、loss函数一致,局限性也一致。
DPO和RM不同点
- 架构不同
- RM:
有单独的Value Head,输出分值 - DPO:无Value Head,直接优化token概率
- RM:
- 优化手段/目标不同
- RM:优化
偏序打分目标 - DPO:优化
生成目标。
- RM:优化
DPO和RM 联系
- RM可以给DPO扩充数据
- 理论上,RM也可以做生成,DPO也可以做打分,只是没这么试过。
DPO 核心思想
通过
- 逆向运用理论最优解关系。
- 不再采用老策略:先学习奖励函数、再利用奖励函数优化策略。
- 假设LLM隐式定义一个奖励函数,从策略
和参考策略 中 反解出隐式奖励函数
偏好建模
winner > loser,chosen > reject- 人类偏好
而不是 的概率
DPO 目标函数
最小化目标函数
:交叉熵loss,对错误概率进行惩罚;目标: 最小化惩罚
最大化以下目标
- 生成正样本的概率
比参考模型高,生成负样本的概率比参考模型低。
- 生成正样本的概率
从loss理解其弊端
- Loss转换过程
Loss转换结果
- 生成正负样本的比例,要
目标策略的比例比参考策略的比例高,loss就可以下降。
比如参考策略:
,目标策略 , - 虽然
loss下降、负样本概率下降,但是正样本概率也下降了。 正负样本概率都下降,自然一些奇奇怪怪的输出概率就提高了。
- 虽然
- 生成正负样本的比例,要
梯度更新
算法机制
- 数据:
离线静态的偏好数据 - 参考模型作用:
和 不要偏离太远 - 超参数
:控制2部分权重 - 一是:
最大化chosen和reject之间的概率差 - 二是:
保持与参考模型的相似性
- 一是:

DPO 缺点
简洁性是其最大优点,但也是其最大缺点。
1. 离线模式缺乏在线采样数据
策略模型在进化,但
静态偏好数据一成不变数据集无法代表
新策略潜在的失败模式,导致模型无法从新的错误中学习。DPO离线特性
限制了模型的探索能力。- 只有evaluate,没有generate
PPO/GRPO 会一直和环境交互采样数据,
用当前策略采样新数据来学习提升。- generate + evaluate + generate + evaluate + ...
2. DPO Loss 导致优化过程不稳定
- loss 见上文 DPO 核心思想
正样本概率、负样本概率都可能会下降。 回答抑制模式,正负似然都下降。奇怪输出概率会上升,特别在遇见未见内容时。负样本概率下降比正样本概率提升
快得多。- 大力
惩罚已知坏样本,擅长学习不做什么,而非做什么。 不是探索奖励好样本。
- 大力
过拟合/RewardHacking
Loss对所有偏好对一视同仁,不会做权重区分,强行拉开他们的概率差距缺乏鲁棒性:可能拟合数据噪声,而非真实人类偏好。
3. 依赖SFT模型和数据质量
- 对SFT模型质量很敏感
- 最终性能取决于
初始化SFT模型。 - 起点差了,就很难摆脱。而在线学习能通过采样自我学习迭代来摆脱。
- 最终性能取决于
- 数据质量敏感
- 需要
高质量偏好数据 - 可能学习多数群体的偏好、而忽略少数群体的观点,引入偏见。
- 需要
GRPO
PPO缺点&GRPO动机
PPO 核心思想
- Actor Model
- Critic Model
- Reward Model (不参与训练,或 Rule Based Reward)
PPO 缺点
资源开销大- 需要训Critic Model(通常和Actor同尺寸),增加了
额外的内存和计算开销。 - 每个Token都需要由Critic
去估计价值,依赖Critic。
- 需要训Critic Model(通常和Actor同尺寸),增加了
训练复杂/不好训- LLM通常只有最后一个Token才有奖励信号
- 导致Critic Model 难以估计每个Token的价值,
不好训练。
GRPO 动机
- 解决PPO
Critic资源开销大、训练复杂的问题。
GRPO核心思想
核心思想
抛弃Critic Model,降低资源开销和 训练复杂度。
分组采样:每个Prompt采样
1组答案(G=64)。组内计算优势
- 好的答案,加大权重;差的答案,降低权重。
- 使用
组内平均分作为基线 - 每个答案,
得分减去平均分,作为自身优势,作为策略梯度优化信号。- 更多信号见:策略梯度权重设计
自适应加权的对比学习。
MC采样思想
- 和REINOFRCE 算法挺像,主要依赖
MC采样,不用TD估计优势。 - 但MC采样方差大,没有TD去平衡方差,怎么解呢?
- 使用组内标准化奖励,一定程度降低了策略梯度估计方差。
组内相对优势
分组采样
- 对每个query,
采样1组输出,RewardModel 为每个输出打分,给出奖励。
- 组内基线计算:组内
平均奖励/奖励标准差
相对组优势计算
- 为每个输出
,计算 组内的相对得分,作为组内的相对优势
组内相对优势 - 不同于PPO仅最后时刻token有奖励信号。
- 所有时刻的token
,都使用 同一个组内相对得分,作为t时刻优势信号
GRPO策略目标
优化目标-PPO核心差异
- 使用
组内优势来替代GAE优势。 - 把
和 的 KL约束放入目标函数。- PPO是放在
每个Token的即时奖励信号里的
- PPO是放在
- 同PPO一样,使用
CLIP信任域来保证新旧策略分布差异不太大。
GRPO 优化目标公式
- GRPO梯度, 省去了clip,DAPO token-level loss, VAPO 解决长度不一问题
GRPO ref KL 约束
- K3 KL,
无偏且低方差
GRPO调参踩坑经验
主要坑点
- 采样基础设施:需高效的推理系统,SGLANG/VLLM
- Group大小:
太小(<32)统计不稳定,太大计算贵 - Beta调参:
非常关键,需要仔细调 - 奖励设计:需要奖励信号
有足够的区分度
Beta 参数
- 0.05:
学习太慢、收敛慢 - 0.1:
大多数任务的甜点 - 0.2:有时候会
过拟合 - 0.3+:基本上
会发散
Group_size
- 16:统计不稳定、方差大
- 32:勉强能用
- 64:比较稳定的选择
- 128:更稳定、但计算成本高
GRPO 标准配置
# 我的GRPO标准配置
grpo_config = {
"learning_rate": 8e-7, # 比PPO小很多
"beta": 0.1, # KL系数,最关键
"group_size": 64, # 群体大小
"temperature": 0.7, # 生成多样性
"top_p": 0.9, # 核采样
"max_length": 2048, # 最大长度
}PPO vs GRPO


核心目标思想差异
PPO
- 找到一个最大化奖励的最优策略。
- 解决问题:
策略更新的稳定性。
GRPO
- 找到一组高质量且多样化的策略。
- 解决问题:
策略发现的多样性。
PPO
- 拥有
历史数据库的教练,追求绝对最优,学习绝对期望值。 - 过程
- 策略模型(
1个运动员)完成1次表现,奖励模型给出最终成绩。 - 价值模型基于历史数据,在运动员跑到中间点时,
预测最终成绩;
- 策略模型(
- 优势:
最终成绩-历史预测成绩。超预期,就获得正向奖励。- 参照物:过去的自己,
。超越昨天的自己。
- 学习信号/优势信号
Token-Level,Critic提供更细粒度的学习信号。- 通过Critic,每个token有不同的价值。而不是整个轨迹级别的。
GRPO
- 组织
小组赛的教练,追求相对领先,直接使用相对的、动态的平均值。 - 过程
- 策略模型(
1组运动员)同时完成表现,生成G个回答。奖励模型为每位运动员给出最终成绩。 - 没有历史数据,直接算出
这组运动员的平均成绩。
- 策略模型(
- 优势:
组内相对优势,个人成绩-小组平均成绩。超平均水平,就获得正向奖励。- 参照物:团队平均策略,
。超越团队平均。
- 学习信号/优势信号
Response-Level,Trajectory-Level轨迹级优势直接应用到序列的每个token,作为token-level优势。
技术实现差异
核心目标
- PPO:找到一个最大化累积奖励的单一最优策略。解决策略更新的稳定性问题。
- GRPO:找到一组高质量且具备多样性的策略。解决策略发现的多样性和效率问题。
优化参照物
- PPO:过去的自己
。通过和上一轮策略比较,在信任域内小步快跑,争取超过昨天的自己。 - GRPO:小组的平均策略
。超过平均水平,则获得正向激励。
算法架构
- PPO
Actor-Critic架构:Actor+Critic+RewardModel。- Critic 估计状态价值
、用于GAE计算优势。 - MC 采样 + TD估计。
- GRPO
纯策略梯度:Actor+RewardModel。- 无Critic,价值基线通过统计得出。
- MC 采样。
优势
- PPO
GAE,依赖价值模型, 基于模型预测、学习的方法。- 对多个n步优势估计,
加权平均,引入λ平衡方差和偏差 - 结合了多步MC回报+Critic价值预测,MC采样+TD估计。
- 依赖准确估计的Critic,这个往往是PPO的难点。
- 对多个n步优势估计,
- 优势获得条件
- 实际得分比历史预测好,才获得正向奖励。
- 基于绝对奖励+价值函数预测
- 优势信号特点
仅最后一个token有环境奖励,其余token为0。- 所有token都有KL惩罚奖励。
- GRPO
组相对优势,不依赖价值模型,基于群体投票、统计的方法。- 优势获得条件
- 个人比组平均成绩好,才获得正向奖励。
- 组内相对排名和分数
- 优势信号特点
- 一条轨迹上所有token共享相同的优势值,都为
- 一条轨迹上所有token共享相同的优势值,都为
奖励信号利用
PPO
Token-Level- 间接利用。
- 环境奖励用来训Critic;再由依赖Critic计算的GAE优势,指导Actor更新优化。
- 有奖励KL惩罚。
- 绝对奖励信号。
GRPO
Response-level- 直接利用。
- 奖励信号直接用于计算相对优势,直接用于Actor优化。
- 无奖励KL惩罚。
- 标准化组相对奖励。
资源开销和训练复杂度差异
1. 资源开销
- PPO
- 资源需求高。
Actor和Critic 2个模型。 - 内存需求:基础模型*
3倍Actor *1,Critc *1,梯度+优化器 *1,旧策略缓存:部分参数。- 实际和bs、序列长度有关。
- 资源需求高。
- GRPO
- 资源需求低,
仅Actor模型。 - 内存需求:基础模型*
1.5倍Actor *1,梯度+优化器 *0.5(单网络)。- 实际和bs、序列长度有关。
- 无Critic,与PPO相比,
显存需求降低25%。若使用规则,不用RewardModel,降低50%。
- 资源需求低,
2. 训练复杂性
- PPO
- 复杂性:高。
需同时训Actor和Critic,难度大。超参数敏感。Critic本身难训练,尤其在奖励稀疏的语言模型中,Critic难收敛,导致优势估计不准。
- GRPO:
- 复杂性:低。
- 只需训练Actor,调参更容易。
- 基线是直接
从组内得分统计出来的,而非学习来的。过程更简单、稳定。
3. 训练稳定性
- PPO
- 相对稳定。
- 通过CLIP信任域机制,
限制策略更新幅度,防止“学崩”,保证训练稳定性。 - GAE在Critic训练良好的情况下,能有效
平衡降低方差和偏差。Critic若收敛,训练更稳定。
- GRPO
- 非常稳定。
组内相对优势,天然对奖励绝对值不敏感,只关心排序,有效降低了方差。目标函数通样有KL约束,保证策略更新的稳定性。
优缺点对比
优点
PPO
- 通用性强。
- 当样本更新对噪声容忍度较高。
GRPO
- 高效轻量。无Critic模型,资源消耗低、训练快。
- 稳定易用。训练过程更稳定,参数好调。
- 与偏好奖励模型 (Reward Model) 的相对比较机制完美契合
缺点
PPO
- 计算成本高。
- 训练困难。
- 对奖励缩放敏感。优势估计受奖励绝对值影响。
·GRPO
采样开销可能较高,每次更新需要采样G个输出。G太小,方差大。- 对G值敏感:会
影响性能和开销平衡。 - 依赖组内质量多样性:组内样本高度相似情况下,如
标准差为0,优势估计会失效,导致梯度为0,更新失效。
为什么GRPO在LLM下可能更优/能work
- Critic 在LLM 稀疏奖励情况下(仅最后token有奖励信号),
非常难以训练。 - GRPO 完美规避了Critic训练难题。
- GRPO和RewardModel很搭配。
- RewardModel通过
比较谁更好来训练,最擅长做出相对判断; - GRPO通过
组内选出更好的,而非绝对分数。 - 机制上契合,使得
奖励信号利用更加高效。
- RewardModel通过
- 隐式课程学习
- 同一个问题,组内样本质量有高有低。
- 模型通过比较,可以同时学到好的和差的,学习信号更加丰富。
- 高效且稳定。
适用场景对比
PPO
- 通用RL,机器人控制、游戏AI等。
- 主观评价。
- 内存、计算资源充足。
- 追求极致性能提升
- 支持连续和离散动作空间。
GRPO
- 针对LLM的RLHF:GRPO完美契合人类偏好训练的RewardModel。
- 内存、计算资源有限。极致性价比。
- 快速迭代。
- 多样性任务。
- 高效稳定。