ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ms-swift 中 RLOO 算法实战:留一法优势估计、KL 并入奖励与源码级配置详解

ms-swift 中 RLOO 算法实战:留一法优势估计、KL 并入奖励与源码级配置详解 ms-swift 中 RLOO 算法实战留一法优势估计、KL 并入奖励与源码级配置详解【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600 LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300 MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swiftRLOOREINFORCE Leave-One-Out是基于经典 REINFORCE 策略梯度的强化学习算法通过留一法Leave-One-Out, LOO构造无偏的优势基线避免引入价值模型critic的高显存开销。在 ms-swift 的 GRPO 训练中RLOO 与 GRPO 共享同一套 rollout、奖励函数与训练管线仅通过--advantage_estimator rloo与--kl_in_reward true两个参数即可切换。读完本文你将理解 RLOO 与 GRPO 在优势基线构造和 KL 正则化方式上的本质差异掌握 ms-swift 中 RLOO 的完整配置方法并能对照源码确认每个参数在compute_advantages、GRPOTrainer中的真实落地逻辑。算法原理RLOO 与 GRPO 的两个核心差异RLOO 与 GRPO 都通过组内比较intra-group comparison来估计优势advantage从而避免全局基线带来的高方差。两者的核心差异集中在两点优势基线如何构造、KL 正则化如何施加。差异一优势基线的构造方式GRPOGroup Relative Policy Optimization对每个 prompt 生成 $G$ 个响应样本并用组内均值与标准差对奖励做标准化$$ \hat{A}{i} \frac{R_i - \text{mean}({R_j}{j1}^G)}{\text{std}({R_j}_{j1}^G)} $$其中$R_i$ 为第 $i$ 个样本的奖励$\text{mean}({R_j}{j1}^G) \frac{1}{G}\sum{j1}^G R_j$ 为组内均值$\text{std}({R_j}_{j1}^G)$ 为组内标准差。RLOOREINFORCE Leave-One-Out对每个 prompt 生成 $K$ 个响应样本对第 $i$ 个样本基线取其余 $K-1$ 个样本的均值$$ \hat{A}{i} R_i - \frac{1}{K-1}\sum{j \neq i} R_j $$该式可等价改写为$$ \hat{A}_{i} \frac{K}{K-1} \left(R_i - \bar{R}\right) $$其中 $\bar{R} \frac{1}{K}\sum_{j1}^K R_j$ 为组内平均奖励。说明这里用 $K$ 是为了与 RLOO 论文符号保持一致其含义与 GRPO 中的 $G$ 相同对应 ms-swift 的配置参数num_generations。为什么要用留一法关键在于无偏性。对第 $i$ 个样本而言其奖励 $R_i$ 与基线 $\frac{1}{K-1}\sum_{j \neq i} R_j$ 相互独立因此优势估计是无偏的反之若基线包含自身均值则会引入偏差。差异二KL 正则化的施加位置为防止策略偏离参考策略过远两种算法都引入 KL 散度正则但施加方式不同GRPO把 KL 散度作为独立正则项加入 损失函数$$ \mathcal{L}(\theta) -\mathbb{E}\left[\hat{A}i \log \pi\theta(a_i|s_i)\right] \beta \cdot \text{KL}(\pi_\theta \Vert \pi_{\text{ref}}) $$RLOO直接把 KL 散度并入奖励构造修正奖励$$ Ri R_i - \beta \cdot \text{KL}(\pi\theta \Vert \pi_{\text{ref}}) $$其中 $\beta$ 为 KL 系数参数beta$\pi_{\text{ref}}$ 为参考策略通常是 SFT 模型或初始策略。源码级实现RLOO 在 ms-swift 中的落地路径参数定义与默认值联动RLOO 由GRPOTrainer支持入口参数定义在 RLHF 参数混入类 中# RLOO, REINFORCE advantage_estimator: Literal[grpo, rloo, reinforce_plus_plus] grpo # If false, add KL into loss, otherwise add into reward kl_in_reward: Optional[bool] None # rloo/reinforce_plus_plus: true, grpo: false (default)kl_in_reward默认为None其真实取值在 参数校验逻辑 中按advantage_estimator自动联动if self.kl_in_reward is None: if self.advantage_estimator grpo: self.kl_in_reward False elif self.advantage_estimator in [rloo, reinforce_plus_plus]: self.kl_in_reward True也就是说只要设置--advantage_estimator rlooKL 并入奖励就是 RLOO 的默认行为与文档中--kl_in_reward true # Integrate KL divergence into the reward (default for RLOO)的注释一致显式指定该参数只是把默认行为写明白便于脚本可读性。同样的联动逻辑还决定了scale_rewards奖励缩放策略的默认值见 rlhf_args.pyadvantage_estimatorkl_in_reward 默认值scale_rewards 默认值grpoFalsegroup按组内标准差缩放rlooTruenone不做额外缩放reinforce_plus_plusTruebatch按整批标准差缩放这一设计在源码注释中有明确说明scale_rewards的默认值“tied toadvantage_estimatorgroup for grpo、none for rloo、batch for reinforce_plus_plus”见 args_mixin.py。RLOO 默认none的含义是优势仅做留一法基线减法和 $K/(K-1)$ 的等价缩放不再除以组内标准差——这正是 RLOO 与 GRPO 在公式上的区别之一。优势计算的核心实现所有后端HF、Megatron、Ray共用的纯张量优势计算函数是 compute_advantagesRLOO 分支只有寥寥几行但完整对应了上文公式rewards (rewards_per_func * reward_weights.unsqueeze(0)).nansum(dim1) if kl_in_reward and beta ! 0.0 and kl_values is not None: rewards rewards - beta * kl_values # R_i R_i - beta * KL K num_generations grouped rewards.view(-1, K) group_mean grouped.mean(dim1).repeat_interleave(K) if advantage_estimator rloo and K 1: advantages rewards * K / (K - 1) - group_mean * K / (K - 1) else: advantages rewards - group_mean # GRPO 分支R_i - mean三个实现细节值得注意KL 在优势归一化之前从奖励中扣除rewards - beta * kl_values。这与文档公式 $R_i R_i - \beta \cdot \text{KL}$ 一致且函数 docstring 明确说明“Ref model KL (kl_in_reward) is subtracted from rewardsbeforeadvantage normalization”。$K/(K-1)$ 等价式源码没有直接实现 $\frac{1}{K-1}\sum_{j\neq i} R_j$而是利用代数恒等式改写为rewards * K/(K-1) - group_mean * K/(K-1)即 $\hat{A}_i \frac{K}{K-1}(R_i - \bar{R})$与文档给出的等价形式完全对应且只需一次组均值计算更高效。K 1的保护条件当num_generations为 1 时退化为rewards - group_mean即恒为 0避免除以 0实践中 RLOO 必须保证num_generations 2才有意义。随后进入scale_rewards分支当 RLOO 使用默认的none时std为None优势不再除以标准差若用户显式指定--scale_rewards group则会按组内标准差缩放退化为类似 GRPO 的行为。KL 值如何计算何时进入损失函数在 GRPOTrainer._compute_advantages 中kl_in_rewardTrue且beta ! 0.0时逐样本 KL 的求法是对每个 completion token 累加新旧策略对数概率之差if self.kl_in_reward and self.beta ! 0.0: kl_list [] for batch_encoded in batch_encoded_inputs: grpo_batch batch_encoded[grpo_batch] per_token_kl grpo_batch.old_per_token_logps - grpo_batch.ref_per_token_logps kl (per_token_kl * grpo_batch.completion_mask).sum(-1) kl_list.append(kl) kl_values torch.cat(kl_list, dim0) kl_values gather(kl_values) rewards (rewards_per_func * self.reward_weights.unsqueeze(0)).nansum(dim1) if self.kl_in_reward and self.beta ! 0.0: rewards rewards - self.beta * kl_values随后kl_values作为实参传入compute_advantages。注意这里的 KL 是old policy 与 ref policy 在采样 token 上的逐 token logp 差之和单样本 KL 估计并跨进程gather后统一计算保证组内统计的正确性。与之相对当kl_in_rewardFalseGRPO 风格时KL 以独立正则项的形式在损失中处理——训练器中对应逻辑为if self.beta ! 0.0 and not self.kl_in_reward:时计算损失内 KL 项见 grpo_trainer.py。两种风格互斥且由参数联动自动切换无需手动保证一致性。多轮/动态样本数场景下的 RLOO在多轮multi-turn训练中每个 prompt 的有效响应数可能不一致。ms-swift 提供了请求感知的动态版本 compute_advantages_dynamic先按request_id去重再按prompt_id分组组内样本数为该组的局部 $K$RLOO 分支为if advantage_estimator rloo: request_advantages torch.zeros_like(unique_rewards) for pid, idxs in prompt_to_indices.items(): K len(idxs) r_group unique_rewards[idx_t] if K 1: request_advantages[idx_t] r_group * K / (K - 1) - r_group.mean() * K / (K - 1) else: request_advantages[idx_t] r_group - r_group.mean()可以看到动态路径同样实现了 $\frac{K}{K-1}(R_i - \bar{R})$ 的留一法等价式只是 $K$ 变为每组实际的样本数。训练器根据dynamic_num_samples决定走compute_advantages默认分组模式还是compute_advantages_dynamic请求感知模式RLOO 在两条路径上均可用。一个限制GDPO 与 kl_in_reward 不兼容若同时使用 GDPO--scale_rewards gdpo对每个奖励函数分别归一化后加权聚合与 RLOO训练器会强制关闭 KL 并入奖励见 grpo_trainer.pyself.kl_in_reward args.kl_in_reward if self.scale_rewards gdpo and self.kl_in_reward: logger.warning(GDPO mode does not support kl_in_rewardTrue. Setting kl_in_rewardFalse.) self.kl_in_reward False这是因为 GDPO 的逐奖励函数归一化与“KL 先并入奖励再归一化”的语义冲突。从源码结构看此时 RLOO 的留一法基线仍然生效但 KL 会回退到损失独立项的形式或当beta0时完全无 KL 正则。参数配置RLOO 训练基于GRPOTrainer启用核心两个开关# Basic RLOO configuration --advantage_estimator rloo # Use RLOOs leave-one-out advantage estimator --kl_in_reward true # Integrate KL divergence into the reward (default for RLOO)关键参数说明--advantage_estimator选择优势估计器grpo默认使用组内均值与标准差做标准化rloo使用留一法构造基线此外还支持reinforce_plus_plusREINFORCE本文不展开。定义见 args_mixin.py。--kl_in_reward控制 KL 项的施加位置falseKL 作为损失函数中的独立正则项GRPO 风格true直接从奖励中扣除 KL 形成修正奖励RLOO 风格默认值与advantage_estimator联动grpo→Falserloo/reinforce_plus_plus→True见 rlhf_args.py。--num_generations每个 prompt 的采样数即公式中的 $K$必须大于 1K 越大留一基线越稳定但 rollout 成本越高。--betaKL 正则系数 $\beta$控制策略更新的保守程度。GRPO 场景下若未显式设置beta默认回退为0.04见 rlhf_args.py 的默认逻辑。RLOO 中它直接参与修正奖励 $R_i R_i - \beta \cdot \text{KL}$取值越大越贴近参考策略。--scale_rewards可选默认随advantage_estimator联动为none也可显式指定group/batch/gdpo改变缩放策略其中gdpo与kl_in_rewardtrue不兼容见上文。其余参数与 GRPO 命令行参数 完全一致例如--epsilon/--epsilon_highPPO 式裁剪上下界、--loss_type、--reward_funcs等。训练脚本实战仓库提供了一个开箱即用的 RLOO 训练示例 examples/train/grpo/internal/rloo.sh基于 8 卡环境对 Qwen2.5-VL-3B-Instruct 做视觉定位grounding任务的 RLOO LoRA 训练CUDA_VISIBLE_DEVICES0,1,2,3,4,5,6,7 \ NPROC_PER_NODE8 \ swift rlhf \ --rlhf_type grpo \ --advantage_estimator rloo \ --kl_in_reward true \ --model Qwen/Qwen2.5-VL-3B-Instruct \ --external_plugins examples/train/grpo/plugin/plugin.py \ --reward_funcs external_r1v_acc format \ --use_vllm true \ --vllm_mode colocate \ --vllm_gpu_memory_utilization 0.4 \ --vllm_tensor_parallel_size 1 \ --vllm_max_model_len 16384 \ --tuner_type lora \ --torch_dtype bfloat16 \ --dataset AI-ModelScope/clevr_cogen_a_train \ --overlong_filter false \ --epsilon 3e-4 \ --epsilon_high 4e-4 \ --max_completion_length 1024 \ --num_train_epochs 1 \ --per_device_train_batch_size 2 \ --learning_rate 1e-6 \ --gradient_accumulation_steps 4 \ --eval_steps 1000 \ --save_steps 1000 \ --save_total_limit 10 \ --sleep_level 1 \ --offload_model true \ --offload_optimizer true \ --logging_steps 1 \ --dataloader_num_workers 4 \ --num_generations 16 \ --temperature 1.0 \ --system examples/train/grpo/prompt.txt \ --deepspeed zero2 \ --log_completions true \ --report_to tensorboard swanlab \ --num_iterations 1 \ --async_generate false \ --beta 0.001 \ --attn_impl flash_attention_2 \ --padding_free true \ --loss_type grpo脚本要点解读--rlhf_type grpo--advantage_estimator rlooRLOO 复用 GRPO 训练入口仅通过优势估计器参数切换算法这正是 ms-swift “一套管线多算法” 的设计体现--num_generations 16$K16$留一基线取其余 15 个样本的均值估计较稳定但 rollout 开销为普通 SFT 的 16 倍同 prompt 采样 16 次需注意显存与吞吐预算--beta 0.001配合--kl_in_reward true每个样本的修正奖励为 $R_i - 0.001 \cdot \text{KL}$KL 以较小权重约束策略漂移--epsilon 3e-4/--epsilon_high 4e-4非对称重要性采样裁剪DAPO 风格配合--loss_type grpo使用--reward_funcs external_r1v_acc format与--external_plugins自定义奖励函数外部定位准确率 格式奖励奖励函数写法可参考 奖励函数开发指南--use_vllm true --vllm_mode colocate与训练进程共卡部署 vLLM 加速 rollout--sleep_level 1、--offload_model/offload_optimizer true用于训练/推理交替时的显存调度。将上述脚本作为模板替换模型、数据集与奖励函数后即可运行 RLOO 训练切换到标准 GRPO 只需把--advantage_estimator改为grpo并显式设--kl_in_reward false其余管线不变。小结RLOO 的无偏性来自留一法基线第 $i$ 个样本的基线不包含自身等价于 $\hat{A}_i \frac{K}{K-1}(R_i - \bar{R})$与 GRPO 相比RLOO 在 ms-swift 中有两处实现差异优势不做组内标准差归一化scale_rewards默认noneKL 在归一化前直接并入奖励kl_in_reward默认True实现集中于 compute_advantagesHF/Megatron/Ray 三后端共用与 GRPOTrainerKL 计算与两路分发参数联动逻辑在 rlhf_args.py使用 RLOO 时注意num_generations必须大于 1gdpo缩放模式与kl_in_rewardtrue不兼容其余参数与 GRPO 完全通用。【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600 LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300 MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表