ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AReaL 的 PPO 家族强化学习算法实战:从 GRPO、GSPO、DAPO 配置到损失计算与调试

AReaL 的 PPO 家族强化学习算法实战:从 GRPO、GSPO、DAPO 配置到损失计算与调试 AReaL 的 PPO 家族强化学习算法实战从 GRPO、GSPO、DAPO 配置到损失计算与调试【免费下载链接】AReaLThe RL Bridge for LLM-based Agent Applications. Made Simple Flexible.项目地址: https://gitcode.com/GitHub_Trending/are/AReaL本文聚焦 AReaL 中 RL 算法专家视角的核心内容PPO 家族算法PPO、GRPO、Dr.GRPO、GSPO、DAPO、RLOO、SAPO 等的选型与配置差异、PPOActorConfig/NormConfig关键参数、RLVRWorkflow等工作流实现模式、奖励函数签名以及 PPO clip 损失的计算与调试方法。读完本文你可以独立完成算法切换配置、理解 advantage 归一化与重要性采样的底层实现并掌握一套系统的 RL 训练问题排查手段。一、RL 算法家族总览AReaL 支持多种 PPO-like 算法它们共享同一套基础目标函数差异集中在归一化策略、裁剪机制、重要性采样层级三个维度。AReaL 通过调整少量配置参数即可在算法之间切换算法专家文档给出的核心对照表如下算法关键特性配置覆盖方式PPO基于 CriticGAE 优势估计kl_ctl0GRPO无 Critic组内归一化默认配置Dr.GRPO仅做均值归一化adv_norm.std_levelnullGSPO序列级重要性采样importance_sampling_levelsequenceDAPO动态 batch sizedapo_dynamic_bs.yamlRLOO留一法Leave-one-out基线rloo.yamlSAPO非对称软门控损失use_sapo_losstrue结合 算法官方文档完整的算法配置矩阵即各算法对应的adv_norm与采样层级组合如下算法adv_norm.mean_leveladv_norm.std_leveladv_norm.mean_leave1outimportance_sampling_level特殊项PPObatchbatchfalsetoken需要 critic 模型GRPObatchbatchfalsetoken-Dr.GRPOgroupnullfalsetoken-LitePPOgroupbatchfalsetoken-RLOOgroupnulltruetoken-GSPObatchbatchfalsesequence-DAPObatchbatchfalsetoken非对称裁剪、动态采样SAPObatchbatchfalsetokenuse_sapo_losstrueIcePopbatchbatchfalsetokenrejection_sampling.metricratioKPopbatchbatchfalsetokenrejection_sampling.metricbinary_kl所有算法使用相同的执行模式推荐直接修改配置 YAML 来切换。仓库为每个算法提供了现成示例入口统一为 examples/math/gsm8k_rl.py后端命令localpython3 examples/math/gsm8k_rl.py --config examples/math/gsm8k_algo.yaml scheduler.typelocalraypython3 examples/math/gsm8k_rl.py --config examples/math/gsm8k_algo.yaml scheduler.typerayslurmpython3 examples/math/gsm8k_rl.py --config examples/math/gsm8k_rl.py --config examples/math/gsm8k_algo.yaml scheduler.typeslurm其中algo可取ppo、grpo、drgrpo、liteppo、rloo、gspo、dapo_dynamic_bs、sapo、icepop、kpop对应仓库中 gsm8k_ppo.yaml、gsm8k_grpo.yaml、gsm8k_rloo.yaml、gsm8k_gspo.yaml、gsm8k_dapo_dynamic_bs.yaml、gsm8k_sapo.yaml、gsm8k_icepop.yaml、gsm8k_kpop.yaml、gsm8k_liteppo.yaml 等配置文件。通过 CLI 覆盖项切换算法不新建 YAML 也可以直接切算法只需在启动命令上追加 OmegaConf 覆盖参数注意新增原 YAML 中不存在的 key 时要加前缀# 从 GRPO 配置切换为 Dr.GRPO python3 examples/math/gsm8k_rl.py \ --config examples/math/gsm8k_grpo.yaml \ scheduler.typelocal \ actor.adv_norm.mean_levelgroup \ actor.adv_norm.std_levelnull # 从 GRPO 配置切换为 GSPO序列级重要性采样 python3 examples/math/gsm8k_rl.py \ --config examples/math/gsm8k_grpo.yaml \ scheduler.typelocal \ actor.importance_sampling_levelsequence # 从 GRPO 配置切换为 SAPO python3 examples/math/gsm8k_rl.py \ --config examples/math/gsm8k_grpo.yaml \ scheduler.typelocal \ actor.use_sapo_losstrue \ actor.sapo_tau_pos1.0 \ actor.sapo_tau_neg1.05 \ actor.use_decoupled_lossfalse二、核心配置参数PPOActorConfig 与 NormConfig2.1 PPOActorConfigPPO/GRPO 核心参数算法专家文档指明核心配置位于 areal/api/cli_args.py 中的PPOActorConfig继承自TrainEngineConfig。文档中最常被引用的四个参数在源码中的实际定义与默认值如下# PPOActorConfig节选自 areal/api/cli_args.py eps_clip: float 0.2 # 策略比率裁剪系数PPO clipping parameter kl_ctl: float 0.1 # KL 散度系数无 critic 算法可设为 0 discount: float 1.0 # 未来奖励折扣 gamma gae_lambda: float | str 1.0 # GAE lambda也可为点分路径指向逐样本 lambda 函数在此之外PPOActorConfig还承载了与算法切换强相关的一组参数默认值均以源码为准参数类型默认值说明ppo_n_minibatchesint4每次 PPO 更新划分的 mini-batch 数eps_clipfloat0.2策略比率裁剪系数eps_clip_higherfloat | NoneNone上界裁剪系数设置后eps_clip作为下界DAPO 非对称裁剪c_clipfloat | NoneNone双重裁剪dual clipping系数必须大于 1.0reward_normNormConfig | NoneNone奖励归一化配置reward_scaling/reward_bias/reward_clipfloat1.0/0.0/20.0奖励缩放、偏置、最大绝对值裁剪overlong_reward_penaltyboolfalse超长回复惩罚DAPO 使用overlong_tokens/overlong_penalty_factorint / float | NoneNone尾部惩罚 token 数与惩罚因子kl_estimatorstrk1KL 估计器可选k1/k2/k3use_sapo_lossboolfalse启用 SAPO 损失与 PPO 裁剪互斥sapo_tau_pos/sapo_tau_negfloat1.0/1.05SAPO 正/负优势温度importance_sampling_levelstrtoken重要性比率层级token标准 PPO或sequenceGSPOuse_decoupled_lossboolfalse解耦损失开启时隐式启用recompute_logprobrejection_samplingConfig | NoneNone过滤陈旧样本的拒采配置IcePop/KPop 依赖它其中importance_sampling_level的定义可以直接印证 GSPO 的开关方式areal/api/cli_args.pyimportance_sampling_level: str field( defaulttoken, metadata{ help: Level at which to compute importance sampling ratios. token: per-token ratios (standard PPO). sequence: sequence-level geometric mean of per-token ratios (GSPO)., choices: [token, sequence], }, )2.2 NormConfig奖励与优势归一化的深度解析reward_norm和adv_norm共用同一个NormConfig数据类areal/api/cli_args.py。算法专家文档只列出了mean_level与std_level两项源码中还包含若干决定行为细节的字段# NormConfig节选自 areal/api/cli_args.py mean_level: str | None batch # batch / group / None mean_leave1out: bool False # 是否使用留一法均值RLOO 的关键开关 std_level: str | None batch # batch / group / None std_unbiased: bool True # 无偏标准差默认值从 v0.3.4 起由 False 改为 True eps: float 1e-5 # 除以标准差时的数值保护常量 group_size: int 1 # group 归一化的组大小归一化层级语义batch在整个 batch 上计算均值/标准差group在每个 prompt 组同一 prompt 采样的多条轨迹内部计算——这是 GRPO 类组归一化的来源None跳过对应的均值中心化或标准差缩放整个字段在 YAML 中省略或置为null如adv_norm: null时完全不执行归一化。源码中的__post_init__会做合法性校验mean_level/std_level只能取batch、group、None三种取值任一取值为group时要求group_size为正整数。结合算法文档可以进一步确认AReaL 中 group 边界实际来自 rollout 批次元数据TrajBatchMeta.traj_group_sizes而非group_size本身——因此当部分样本被过滤导致组内数量不等时仍按 prompt 逐组归一化group_size仅在该元数据不可用时作为固定步长的兜底。AReaL 的默认实践默认配置对优势使用std_level: batch归一化。Dr.GRPO 建议std_level: null以获得潜在更好的性能但 AReaL 为向后兼容保留了 batch 级标准差想获得 Dr.GRPO 行为时显式设置actor.adv_norm.std_levelnull即可。一个典型的组归一化写法actor: adv_norm: null reward_norm: mean_level: group std_level: group group_size: ${gconfig.n_samples}三、损失计算Clip 损失与变体的源码级实现3.1 PPO Clip 损失算法专家文档给出的基础损失形式为L -min(r(theta) * A, clip(r(theta), 1-epsilon, 1epsilon) * A) 其中 - r(theta) pi_new / pi_old重要性比率 - A advantage按配置归一化后的优势 - epsilon eps_clip实现位于 areal/trainer/ppo/actor.py。从源码结构看compute_loss调用链将eps_clip、eps_clip_higher、c_clip、use_sapo_loss等参数一并传入损失函数见 areal/trainer/ppo/actor.py并在损失内部对use_sapo_loss与use_cispo_loss做了互斥校验二者只能设置其一。损失函数还会统计clip_mask、dual_clip_mask等裁剪率指标areal/trainer/ppo/actor.py这些指标正是后文调试截断与裁剪问题时使用的观测点。奖励侧在送入 GAE 前也会先做绝对值裁剪torch.clip(reward_score, -reward_clip, reward_clip)areal/trainer/ppo/actor.py对应默认reward_clip20.0用于防止异常奖励值破坏优势估计。3.2 非对称裁剪与双重裁剪DAPO 相关裁剪策略由eps_clip与eps_clip_higher两个参数共同控制areal/api/cli_args.pyeps_clip_higher为None时对称裁剪$\text{clip}(r, 1-\epsilon, 1\epsilon)$eps_clip_higher被设置时DAPO 风格非对称裁剪$\text{clip}(r, 1-\epsilon_{\text{low}}, 1\epsilon_{\text{high}})$另外c_clip必须大于 1.0提供 PPO 论文中的 dual clipping用于限制负优势方向下比率过小时的损失放大。DAPO 的动态采样则通过PPOTrainer.train()的dynamic_filter_fn实现——过滤掉组内回复全对或全错的样本无学习信号trainer.train( workflow..., dynamic_filter_fnlambda x: 0 x[rewards].mean() 1 )DAPO 的超长惩罚对应三个参数overlong_reward_penalty开关、overlong_tokens视为超长的尾部 token 数、overlong_penalty_factor惩罚因子。3.3 SAPO 软门控损失SAPO 用软 sigmoid 门取代 PPO 的硬裁剪提供平滑梯度与非对称控制。定义上正优势门$g_t^ \frac{4}{\tau_{\text{pos}}} \sigma(\tau_{\text{pos}} (r_t - 1))$负优势门$g_t^- \frac{4}{\tau_{\text{neg}}} \sigma(\tau_{\text{neg}} (r_t - 1))$损失$L^{\text{SAPO}} -\mathbb{E}_t[g_t A_t]$其中 $g_t$ 按 $A_t$ 的正负选择 $g_t^$ 或 $g_t^-$actor: use_sapo_loss: true sapo_tau_pos: 1.0 sapo_tau_neg: 1.05 use_decoupled_loss: false # SAPO 要求 use_decoupled_lossfalse3.4 GSPO 序列级重要性采样GSPO 把重要性比率从 token 级提升到序列级取逐 token 比率的几何均值$$ r_i(\theta) \exp\left(\frac{1}{|o_i|}\sum_{t1}^{|o_i|} \log\frac{\pi_\theta(o_{i,t} \mid q, o_{i,t})}{\pi_{\theta_{\text{old}}}(o_{i,t} \mid q, o_{i,t})}\right) $$配置上仅需actor.importance_sampling_levelsequence与上文源码help描述一致sequence-level geometric mean of per-token ratios。3.5 IcePop 与 KPop可组合的 token 掩码IcePop/KPop 是可叠加到任意上述算法之上的 token 掩码策略均通过rejection_sampling配置实现且都要求use_decoupled_losstrue否则该配置不生效# IcePop掩码重要性比率落在 [lower, upper] 之外的 token actor: use_decoupled_loss: true rejection_sampling: level: token action: mask metric: ratio lower: 0.5 upper: 5.0# KPop掩码双向二元 KL 散度超过阈值的 token仅支持 actionmasklower 不生效 actor: use_decoupled_loss: true rejection_sampling: level: token action: mask metric: binary_kl upper: 2.0四、工作流Workflowepisode 的实现模式算法专家文档把工作流列为核心专长之一位置在areal/workflow/工作流用途关键方法RLVRWorkflow单轮 RLarun_episodeMultiTurnWorkflow多轮对话arun_episodeVisionRLVRWorkflow视觉-语言 RLarun_episode三者均已实现并可确认RLVRWorkflow 继承RolloutWorkflow并定义arun_episodeareal/workflow/rlvr.pyMultiTurnWorkflow 同样实现arun_episodeareal/workflow/multi_turn.pyVisionRLVRWorkflow 继承自RLVRWorkflow并覆写arun_episodeareal/workflow/vision_rlvr.py。自定义工作流遵循统一的模式——arun_episode内完成四步class MyWorkflow(RolloutWorkflow): async def arun_episode(self, engine: InferenceEngine, data: dict[str, Any]): # 1. 准备输入tokenize # 2. 生成回复engine.generate # 3. 计算奖励async_reward_fn # 4. 返回拼接后的结果若后续需要启用 turn 级 GAE自定义工作流还需返回与input_ids/loss_mask同形状[B, S]、整数 dtype 的turn_ids张量同一 assistant 回合的所有活跃生成 token 使用同一个[0, S)内的 IDprompt/用户/工具/padding 位置填-1。文档给出的构建范式turn_ids [-1] * input_len [turn_idx] * resp.output_len result[turn_ids] torch.tensor(turn_ids, dtypetorch.int32).unsqueeze(0)五、奖励函数签名约定与内置实现奖励函数位于 areal/reward/统一的函数签名为def reward_fn( prompt, completions, prompt_ids, completion_ids, answer, **kwargs ) - float: ...即接收 prompt 文本、completion 文本、prompt/completion 的 token id 序列以及参考答案answer返回一个标量奖励。内置的关键实现包括areal/reward/gsm8k.py —— 数学题答案校验对应示例examples/math/gsm8k_rl.py相关测试见 tests/test_math_verify_reward.pyareal/reward/clevr_count_70k.py —— CLEVR 计数任务校验areal/reward/geometry3k.py —— 几何题校验另有 areal/reward/if_gap.py 与areal/reward/prm/过程奖励等扩展。AReaL 采用结果型outcome-based奖励约定每条轨迹可以是多轮 LLM 输入输出拼接在序列级别被赋予一个标量奖励而非 token 级。训练侧再把它当作最后一个 token 的奖励前面 token 奖励为 0通过 GAE 的反向递推把终端奖励传播到每个生成 token当discount1、gae_lambda1、critic 值为零且关闭 KL 正则时终端结果奖励会被有效广播到每个生成 token。GAE 与时间步单位优势估计由discountgamma、gae_lambda与gae_timestep_unit共同控制gae_timestep_unit: token默认标准 token 级 GAE$\delta_t r_t \gamma V_{t1} - V_t$$A_t \delta_t \gamma\lambda A_{t1}$EOS 结尾轨迹使用零终端 bootstrap无 EOS 的被截断轨迹从最终值估计 bootstrapgae_timestep_unit: turn把每个非空生成回合视为一个宏时间步回合级任务优势广播到该回合所有活跃 tokentoken 级 KL 惩罚刻意不参与回合递推与 critic 目标避免先对回合内 KL 求和再广播回每个 token的偏差。prompt、工具、padding 等被 mask 的位置永远不会消耗 GAE 步。gae_lambda还支持传点分路径调用逐轨迹动态计算 lambda 的函数函数接收effective_token_lengths、turn_counts、timestep_lengths三个[B]张量并返回每个轨迹一个有限浮点 lambda内置两个长度感知实现函数路径Kwargs定义areal.trainer.ppo.lambda_fn.vapo_length_adaptive_gaealpha 0$L0$ 时 $\lambda\max(0, 1-1/(\alpha L))$$L0$ 取 0areal.trainer.ppo.lambda_fn.relative_position_gae_lambda0 q 1$L\ge2$ 时 $\lambdaq^{1/(L-1)}$$L1$ 取 1、$L0$ 取 0actor: gae_timestep_unit: turn gae_lambda: areal.trainer.ppo.lambda_fn.relative_position_gae_lambda gae_lambda_kwargs: q: 0.5实现可参考 areal/trainer/ppo/gae.py 与 areal/trainer/ppo/lambda_fn.py。AReaL 与原始 GRPO 论文的两点实现差异结合算法文档说明AReaL 的 GRPO 相对原始 DeepSeekMath 论文有两处关键差异长度归一化AReaL 移除了 GRPO 目标函数中的逐 token 长度归一化项与 Dr.GRPO 的建议一致消除优势估计偏差KL 正则方式AReaL 不把 KL 项直接加进目标函数而是按 PPO 风格把 KL 惩罚融入 actor 优势由actor.kl_ctl控制。token 模式下KLEstimator惩罚在 GAE 之前加到逐 token 奖励上turn 模式下它保持为 token 局部的 actor 惩罚不进入回合递推与 critic 目标。六、常见问题与调试手段算法专家文档沉淀了一份高频问题对照表结合仓库实现可直接落地排查问题解决方案奖励恒为 0/1检查奖励函数的答案抽取逻辑如 areal/reward/gsm8k.py 的解析部分KL 散度爆炸调小eps_clip、调大kl_ctl没有学习信号检查adv_norm配置确认组内/批内存在方差异步奖励超时增大超时或优化奖励函数组大小不匹配确保group_size与 rollout 配置一致配套的调试代码片段打印优势/奖励统计、重要性比率与裁剪率正好对应actor.py中记录的clip_mask统计指标# 检查优势统计 print(fAdvantages: mean{adv.mean():.4f}, std{adv.std():.4f}) print(fRewards: mean{rewards.mean():.4f}, std{rewards.std():.4f}) # 检查重要性比率 ratio (new_logp - old_logp).exp() print(fImportance ratio: mean{ratio.mean():.4f}, max{ratio.max():.4f}) # 检查裁剪频率 clipped (ratio 1-eps) | (ratio 1eps) print(fClipping rate: {clipped.float().mean():.2%})验证相关的测试用例可以作为断言基准例如 tests/test_cispo_loss.py、tests/test_adv_norm_config.py、tests/test_ppo_actor_truncation.py、tests/test_token_rewards_advantage.py。七、关键文件索引文件用途areal/api/cli_args.pyPPOActorConfig、NormConfig等算法配置定义areal/trainer/ppo/actor.pyPPO/SAPO 损失计算与裁剪统计areal/trainer/ppo/gae.pyGAE 优势估计token/turn 时间步areal/workflow/rlvr.py单轮 RL 工作流areal/workflow/multi_turn.py多轮工作流areal/reward/init.py奖励函数入口docs/en/algorithms/grpo_series.md算法族完整文档公式、配置矩阵、GAE 细节examples/math/gsm8k_grpo.yaml 等各算法的完整示例配置从这份索引出发可以沿着配置cli_args→ 损失trainer/ppo/actor→ 工作流workflow→ 奖励reward的主线完整理解 AReaL 中一个 RL 训练步从 rollout 到参数更新的全部算法细节。【免费下载链接】AReaLThe RL Bridge for LLM-based Agent Applications. Made Simple Flexible.项目地址: https://gitcode.com/GitHub_Trending/are/AReaL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表