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

重要性采样在RL中的作用
核心作用
- 可实现off-policy,从而
降低RL采样成本,解决采样效率问题,提升训练效率。- on-policy:采样策略和学习策略相同
- 即产出数据的策略和用这批数据做更新的策略是同1个。
- on-policy:采样策略和学习策略相同
更加谨慎地更新模型。
使用方法
- 从
开始,用 和环境交互,得到一批 回合数据。 - 把这批
回合数据重复使用k次去更新模型(off-policy过程)- 第1次,喂给:
- 第2次,喂给:
- ...
- 第k次,喂给:
k次更新后:
- 第1次,喂给:
策略梯度发生变化
- 原始策略梯度
- 引入重要性采样后的梯度:
, 训练数据是从旧策略采样出来的。
重要性权重目标函数
重要性采样策略梯度推导
从定义到期望形式
转换成优势策略梯度
代入重要性采样
- 推导过程
- 推导结果
除以旧策略概率的作用
:为了 加权梯度- 初期:模型不自信,预测概率较小,加权大,
- 模型自信后:就不怎么加权了。
- 如果旧策略和当前策略梯度
冲突较大,会造成过度优化或训不动。 PPO-CLIP信任域 可解。
广义优势估计
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无偏估计,
只依赖环境奖励,价值模型学习变成简单的监督学习,非常稳定的梯度下降过程。
- 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 估计优势 方差偏差问题
TRPO 提出背景
- 解决
步长选择困难症- 通过
引入约束或限制,确保每次策略更新不会太大。 - 避免策略崩溃,且保证策略能持续提升。
- 通过
- 引入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思想,但实现更简单。能学的一样好、甚至更快。
PPO 核心思想
PPO-Clip
Clip 核心思想
引入IS和GAE后的优化目标
背景
为什么需要CLIP?
考虑采样不足的情况下,
和 分布差异不能太大 因此
是 有上限和下限的,需保证在信任域内。不能一味轻信, 来提升或降低。
CLIP 核心思想
- 通过
CLIP裁剪+MIN函数,限制策略更新幅度,来保证训练稳定性。 - 限制
重要性权重在一个信任域内,超出信任域就裁切。- 约束
新旧策略尽可能接近和相似,约束和 的相似性, 限制更新幅度不要太大,保证训练稳定性 - 希望采样策略和学习策略的差距不要太大。
- 约束
CLIP 信任域
优化目标
- 不做KL散度约束,直接把
CLIP 信任域放到目标函数中
Clip 到底做了什么
公式
- 无限制的策略梯度目标:
- 有限制的策略梯度目标:
,重要性权重裁剪到
Case1:对于好动作
目标:提高概率,即增大
当
时:一切正常 当
时:变成 , 没有梯度- 是一个
旧策略计算出的常数,和当前优化参数无关
- 是一个
意味着
IS差距大的token,该token梯度为0,无法进行梯度更新,该token被硬丢弃。
Case2:对于差动作
目标:降低概率,即减小
当
时:变成 同理,
没有梯度, IS差异大的token,无法进行梯度更新,该token被硬丢弃。


Clip 改进工作
PPO-Penalty
背景
- 直接把限制条件加入优化目标中,解决TRPO优化复杂的问题。
- 限制条件被称为
KL penalty
KL Penalty
- KL散度, TRPO 信任区域 KL散度球
- 约束
行为上的距离,而不是参数上的距离,也因此无法使用L1L2范数等距离方法。
- 约束
- 对
KL散度设置阈值 - 超参
的调整策略:自动调节、自适应KL散度 新策略偏离旧策略太远,应该增大, 把分布拉回来
- 当前策略可能找到一条接近,只优化KL散度。
- 让自己和旧策略相近,而
不去优化优势相关的项 - 应该减小
, 降低KL散度对目标的影响。
优化目标
- 原始优化目标
引入KL Penalty后的优化目标
Actor
策略目标
1. 普通优势策略目标
2. TRPO策略目标
3. PPO-CLIP 策略目标 ‼️
期望写法,Seq-Level-Loss
期望序列内平均写法,Seq-Level-Loss
- 另有
Token-Level Loss变体,2级平均,token-mean这是目前的主流。
4. PPO-KLPenalty 策略目标
PPO Loss
Actor在PPO epoch中,使用同一批数据做迭代更新的。
重要性采样/比率
- 为了稳定性,会对重要性采样做一个截断
- negative_approx_kl =
log_prob - old_log_prob - negative_approx_kl = torch.clamp(negative_approx_kl, min=-20.0, maxs=20.0)
PPO Loss
Dual-Clip Loss
- 在优势
时,额外增加一个裁剪
熵奖励
背景
- 熵:信息量的期望,衡量不确定性的程度,熵越大,不确定性越大。
- RL容易陷入局部最优,停止探索。
- 为了鼓励策略探索,增加熵奖励。
计算方法
- 熵系数:
entropy_coeff - 熵loss:
entropy_loss,response每个llm生成token熵的平均值。- entropy_loss = agg_loss(loss_mat=entropy, loss_mask=response_mask, loss_agg_mode=loss_agg_mode)
- 熵奖励:
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_lossKL 惩罚
背景
- RLHF中通常有一个SFT后的
模型,具有一定能力。 - Reward Hacking问题:如果不对
进行约束,可能会走捷径骗过RM,来获取高奖励。 - KL loss正则化手段,给策略上缰绳,允许追求高奖励、同时又防止跑偏太远。
计算公式
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_coefPolicy总Loss
总loss
Policy loss = PPO损失 - 熵奖励 + KL 惩罚
policy_loss = pg_loss - entropy_coeff * entropy_loss + kl_loss_coef * kl_loss
Policy Loss 代码
朴素PG loss
@register_policy_loss("vanilla")
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_log_probs: torch.Tensor | None = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
"""
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
# Clamp negative_approx_kl for stability
negative_approx_kl = torch.clamp(negative_approx_kl, min=-20.0, max=20.0)
ratio = torch.exp(negative_approx_kl)
# 近似KL散度,作为监控指标
ppo_kl = verl_F.masked_mean(-negative_approx_kl, response_mask)
pg_losses1 = -advantages * ratio
if cliprange_low is None:
cliprange_low = cliprange
if cliprange_high is None:
cliprange_high = cliprange
pg_losses2 = -advantages * torch.clamp(
ratio, 1 - cliprange_low, 1 + cliprange_high
) # - clip(ratio, 1-cliprange, 1+cliprange) * A
clip_pg_losses1 = torch.maximum(
pg_losses1, pg_losses2
) # max(-ratio * A, -clip(ratio, 1-cliprange, 1+cliprange) * A)
# 被clip的比例
pg_clipfrac = verl_F.masked_mean(torch.gt(pg_losses2, pg_losses1).float(), response_mask)
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
pg_losses = torch.where(advantages < 0, clip_pg_losses2, clip_pg_losses1)
if config.tis_imp_ratio_cap > 0 and rollout_log_probs is not None:
# Apply truncated importance sampling -> https://fengyao.notion.site/off-policy-rl
tis_imp_ratio = torch.exp(old_log_prob - rollout_log_probs)
tis_imp_ratio = torch.clamp(tis_imp_ratio, max=config.tis_imp_ratio_cap)
pg_losses = pg_losses * tis_imp_ratio
pg_loss = agg_loss(loss_mat=pg_losses, loss_mask=response_mask, loss_agg_mode=loss_agg_mode)
return pg_loss, pg_clipfrac, ppo_kl, pg_clipfrac_lowerPolicy 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_coefReward
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。
- 内存、计算资源有限。极致性价比。
- 快速迭代。
- 多样性任务。
- 高效稳定。