系列文章:
1、强化学习算法-1:GRPO、DPO与PPO解析
2、强化学习算法-2:熵坍缩以及奖励坍缩问题机制分析及解决措施
3、强化学习算法-3:主流算法的改进与演进
GSPO
处理长序列优化问题,将token级别处理为sequence级别
Qwen团队论文1里面首先分析在GRPO中存在如下几点问题:1、奖励函数一般是sequence级别的(对整个回答进行评分)但是却对每个token去计算重要性比率;2、不同专家被不同token激活,导致路由(routing)在rollout和training阶段不一致,GRPO的token级噪声会直接把某些专家“训崩”。针对上述两点问题在GSPO中损失函数为:

区别与GRPO中改进就在于:1、去掉了对于token的平均(在GRPO中对于模型输出会计算token平均:$\frac{1}{\vert o_i \vert}\sum_{t=1}^{\vert o_i \vert}$);2、计算sequence重要性:将GRPO中计算方式由 $r_{i,t}(\theta)=\frac{\pi_{\theta}(o_{i,t} \vert q,o_{i<t})}{\pi_{\theta_{old}}(o_{i,t} \vert q,o_{i<t})}$改为 $s_i(\theta)=(\frac{\pi_{\theta}(o_i \vert q)}{\pi_{\theta}(o_i \vert q)})^{\frac{1}{\vert o_i \vert}}$。通过改进GSPO区别GRPO表现:

两部分算法在代码差异点如下(Github-GRPOTrainer):
log_ratio = per_token_logps - old_per_token_logps # shape: [batch*G, seq_len]
if self.importance_sampling_level == "token":
log_importance_weights = log_ratio # 每个token都一个独立权重
elif self.importance_sampling_level == "sequence":
log_importance_weights = (log_ratio * mask).sum(-1) / mask.sum(-1).clamp(min=1.0) # 所有token加权求和得到 sequence
log_importance_weights = log_importance_weights.unsqueeze(-1) # # shape: [batch*G, 1] 得到sequence级别
coef_1 = torch.exp(log_importance_weights)
在trl中要实现GSPO直接使用可以直接使用参数:GRPOConfig(importance_sampling_level="sequence",) 就可以切换到GSPO优化了,按照论文里面参数配置
training_args = GRPOConfig(
importance_sampling_level="sequence",
beta=0.0,# 不加KL散度
epsilon=3e-4,# clipping 下界
epsilon_high=4e-4,# clipping 上界(
)
SAPO
Qwen团队论文2核心目标是解决“硬clipping的脆性问题”。它在保持group-based RL(去Critic、组内相对优势)的基础上,把clipping机制从硬裁剪升级为温度控制的软控制,从而实现sequence-coherent(序列一致性) + token-adaptive(token自适应)的双重优势,其损失函数为:

整个损失函数还是基于GRPO进行出发,将内部的 $\min(r, clip(r,1-\epsilon, 1+\epsilon))$ 替换为 $f$其中其中 $\sigma$ 是sigmoid函数,$x = r_{i,t}$ 重要性,$\tau$ 是温度参数。靠近on-policy(r ≈ 1)时,门接近1,梯度几乎不受影响(充分学习)。偏离越大时,门值平滑衰减(attenuate),而不是直接截断到clip边界。不对称温度:正优势(好token)用 $ \tau_{pos} $,负优势(坏token)用 $ \tau_{neg} > \tau_{pos} $,让负面更新衰减更快,提高稳定性。
只是将最后的clip改为最终模型表现

https://zhuanlan.zhihu.com/p/1978208354783486737