用 GMPO 训练更稳定的 GRPO:trl 中几何均值策略优化的原理、配置与源码解析
2026/9/13 14:53:12 网站建设 项目流程

用 GMPO 训练更稳定的 GRPO:trl 中几何均值策略优化的原理、配置与源码解析

【免费下载链接】trlTrain transformer language models with reinforcement learning.项目地址: https://gitcode.com/GitHub_Trending/tr/trl

GMPO(Geometric-Mean Policy Optimization)是 trl 在trl.experimental.gmpo模块中提供的一种 GRPO 变体:它用 token 级重要性比率的几何均值取代 GRPO 的算术均值,从而对离群比率不敏感、策略更新更稳定,并允许使用远比 GRPO/DAPO 更宽的裁剪范围。本文基于 docs/source/gmpo.md 展开,结合 GMPOTrainer 实现 与 GMPOConfig 配置 及对应的 单元测试,讲清楚 GMPO 的目标函数、两个核心超参数(epsilon/epsilon_high)在 log 空间中的真实含义、完整的训练代码示例,以及源码中裁剪与几何均值归一化的具体实现。读完你可以直接在 trl 中配置并跑通一次 GMPO 训练,也能理解其与 GRPO 的精确差异。

GMPO 的核心思想:从算术均值到几何均值

在论文Geometric-Mean Policy Optimization(论文编号 2507.20673)中,作者提出的核心改动是:GRPO 在聚合 token 级重要性比率时计算的是算术均值,而 GMPO 计算的是几何均值

为什么这个改动有意义?算术均值对极端值(离群比率)非常敏感——一个 token 出现极大的 importance ratio 就会把整条序列的目标拉偏,迫使策略更新过度激进。而几何均值对离群值天然不敏感,它本质上是"对数空间中的平均后再指数化",个别极端 token 的影响被对数运算平滑掉。因此:

  • 策略更新更加稳定;
  • 可以容忍更宽的裁剪范围而不至于训练崩溃;
  • 裁剪按 token 进行、在log 空间执行,且按 advantage 的符号做单侧裁剪(即 PPO 标准 trust region 的"min"技巧),关键的是:裁剪发生在几何均值聚合之前

在 trl 中,这一思想落地为trl.experimental.gmpo下的两个公开类:GMPOTrainerGMPOConfig(见 gmpo/init.py)。

快速上手:一次完整的 GMPO 训练

官方文档给出的用法非常简洁,核心代码如下:

from trl.experimental.gmpo import GMPOConfig, GMPOTrainer training_args = GMPOConfig( epsilon=0.4, # log 空间裁剪范围 -> 比率被裁剪到 (exp(-0.4), exp(0.4));论文 Sec. 4 推荐值 beta=0.0, ) trainer = GMPOTrainer( model="Qwen/Qwen3-0.6B", reward_funcs=..., train_dataset=..., args=training_args, ) trainer.train()

其中:

  • GMPOConfigGRPOConfig的构造签名基本一致,modelreward_funcstrain_datasetargs等均沿用 GRPO 的约定;
  • reward_funcs可以传入内置奖励函数或自定义奖励函数;
  • trainer.train()触发完整训练循环(采样、奖励计算、优势估计、策略更新)。

对照仓库中的 测试用例 tests/experimental/test_gmpo_trainer.py,一个可以直接运行的配置示例是:

training_args = GMPOConfig( output_dir=tmp_dir, learning_rate=0.1, # 测试注释:梯度偏小,默认学习率可能停滞,故调高 per_device_train_batch_size=3, # 减小 batch 以降低显存占用 num_generations=3, # 每个 prompt 采样的生成数,默认 8 max_completion_length=8, # 生成的最大长度 num_iterations=2, # 每批迭代次数,大于 1 时重要性采样权重非零 report_to="none", ) trainer = GMPOTrainer( model="trl-internal-testing/tiny-Qwen2ForCausalLM-2.5", reward_funcs="trl-internal-testing/tiny-Qwen2ForSequenceClassification-2.5", args=training_args, train_dataset=dataset, ) trainer.train()

测试中还覆盖了多种eval_dataset传入形态(单数据集、DatasetDict、字典),以及多轮对话数据集(conversational_prompt_only)的训练,说明 GMPO 的数据流与 GRPO 完全兼容。

GMPOConfig:继承 GRPOConfig,只改裁剪语义

GMPOConfig定义在 trl/experimental/gmpo/gmpo_config.py,它的类文档写得很明确:

继承GRPOConfig的全部参数,只改变裁剪范围的语义与默认值

epsilon 与 epsilon_high:log 空间中的裁剪边界

这是 GMPO 与 GRPO 最本质的差异所在:

参数GMPO 默认值GRPO 默认值含义
epsilon0.40.2下界裁剪值,以 log 空间表达:token 重要性比率的下界为exp(-epsilon)
epsilon_highNone(回退为epsilon的值)None上界裁剪值,以 log 空间表达:上界为exp(epsilon_high)

也就是说,在 GRPO 中epsilon=0.2直接作为比率空间(线性空间)的裁剪边界;而在 GMPO 中,由于裁剪发生在 log 空间,实际的比率裁剪区间是:

(exp(-epsilon), exp(epsilon_high))

epsilon_high保持None时上下界对称,即(exp(-0.4), exp(0.4))。测试test_default_epsilon_is_log_space正是验证这一点:

def test_default_epsilon_is_log_space(self): # GMPO expresses the clip range in log space; default is the paper's (exp(-0.4), exp(0.4)). args = GMPOConfig("dummy") assert args.epsilon == 0.4 # epsilon_high is inherited from GRPOConfig and defaults to None, so the range is symmetric. assert args.epsilon_high is None

注意exp(0.4) ≈ 1.49,而上界exp(0.2) ≈ 1.22exp(0.28) ≈ 1.32(DAPO 推荐值),可见 GMPO 允许的比率上界明显更宽——论文推荐这个更宽的范围正是为了鼓励探索,而几何均值的稳定性保证了宽范围不会导致训练发散。

继承自 GRPOConfig 的其他重要参数

由于GMPOConfig全量继承GRPOConfig(见 trl/trainer/grpo_config.py),以下参数同样生效:

  • beta:KL 系数,默认0.0。为0时不加载参考模型,省显存、提速;DeepSeek-R1 论文使用0.001。GMPO 中若beta != 0,KL 项按序列平均(见下文源码解析);
  • num_iterations:每个 batch 的迭代次数(算法中的 μ),默认1
  • num_generations:每个 prompt 的采样数,默认8,要求有效 batch size 能被其整除;
  • max_completion_length:生成最大长度,默认512
  • temperature/top_p/top_k/min_p:采样参数;
  • use_vllm/vllm_mode"server""colocate"):是否用 vLLM 加速生成;
  • reward_weights/multi_objective_aggregation:多奖励聚合配置;
  • remove_unused_columns:默认False,自定义奖励函数需要额外列时保持False

beta=0.0epsilon=0.4即官方文档示例中的两个显式参数——前者关闭 KL 正则、后者设定 log 空间裁剪下界。

源码级解析:GMPOTrainer._compute_loss 的五个步骤

GMPOTrainer定义在 trl/experimental/gmpo/gmpo_trainer.py,其类文档明确说明:

相对GRPOTrainer的唯一改动是_compute_loss,其余部分(生成、奖励计算、权重同步、指标日志)原样继承。

因此理解 GMPO 的关键就是逐行读懂_compute_loss(见 gmpo_trainer.py#L43-L155)。

第 1 步:计算 per-token log 概率与熵

拼接 prompt 与 completion,仅保留 completion 段的 logits(logits_to_keep),调用_get_per_token_logps_and_entropies得到每个位置的对数概率per_token_logps与熵entropies。注意该方法支持多模态输入(pixel_valuesimage_grid_thwimage_sizes等参数均有透传),说明 GMPO 沿用了 GRPO 的视觉语言模型支持。若top_entropy_quantile < 1.0,还会构造高熵 token 掩码(entropy_mask),把低熵 token 从目标中剔除,只让高熵 token 参与梯度。

num_iterations == 1steps_per_generation <= gradient_accumulation_steps时,新旧策略的 logps 相同,实现上直接用per_token_logps.detach()跳过前向计算以省算力。

第 2 步:log 空间中的逐 token 双向裁剪

log_ratio = per_token_logps - old_per_token_logps # per-token log 重要性比率 clamped_log_ratio = torch.clamp(log_ratio, min=-self.epsilon_low, max=self.epsilon_high)

裁剪直接作用于对数比率(log 空间),对应比率空间的(exp(-epsilon), exp(epsilon_high))区间,数值上比在比率空间裁剪更稳定。

第 3 步:按 advantage 符号做单侧裁剪(PPO trust region)

clipped_log_ratio = torch.where( advantages_col > 0, torch.minimum(log_ratio, clamped_log_ratio), torch.maximum(log_ratio, clamped_log_ratio), )

这是 PPO 经典 "min" 技巧的 log 空间写法:advantage 为正的 token 只限制上界(防止过度上调该 token 的概率),advantage 为负的 token 只限制下界(防止过度下调)。单侧裁剪在几何均值之前逐 token 完成——这正是文档强调的 "one-sided per the advantage sign, before the geometric mean is taken"。

第 4 步:几何均值聚合与逐序列损失

log_importance_weights = (clipped_log_ratio * seq_mask).sum(-1) / seq_mask.sum(-1).clamp(min=1.0) coef = torch.exp(log_importance_weights) # 序列级几何均值重要性权重 per_sequence_loss = -coef * advantages
  • 先对有效 token 的裁剪后 log 比率求平均(对数空间平均),再指数化得到几何均值coef
  • 代码注释特别指出:1/|o_i|指数正是几何均值的归一化因子,论文的消融实验表明这一归一化是必需的
  • 逐序列损失为-coef * advantages,对序列做普通平均得到 batch 损失(token 归一化已蕴含在几何均值内部),并按梯度累积步数归一化。

第 5 步:可选的 KL 正则与裁剪指标

beta != 0.0时,向参考模型方向施加 KL 正则,且与 GMPO 的序列级目标对齐,KL 同样按序列平均(测试test_train_with_kl专门覆盖beta=0.1路径):

per_token_kl = torch.exp(ref_per_token_logps - per_token_logps) - (ref_per_token_logps - per_token_logps) - 1 seq_kl = (per_token_kl * mask).sum(-1) / mask.sum(-1).clamp(min=1.0) per_sequence_loss = per_sequence_loss + self.beta * seq_kl

此外,训练日志中会记录以下裁剪相关指标,用于监控有多少 token 被推进裁剪区:

  • klbeta != 0时)、entropy
  • clip_ratio/low_meanlog_ratio < -epsilon_lowadvantage < 0的 token 占比;
  • clip_ratio/high_meanlog_ratio > epsilon_highadvantage > 0的 token 占比;
  • clip_ratio/region_mean:两侧裁剪区合并占比;
  • clip_ratio/low_min/clip_ratio/high_max:跨进程 gather 后的序列级极值。

GMPOTrainer_tag_names = ["trl", "gmpo"],训练完成后会自动打上这两类模型标签;trainsave_modelpush_to_hub等方法均从GRPOTrainer继承,用法与 GRPO 完全一致。

训练实践建议与注意事项

结合 测试用例 与源码,给出几点实操要点:

  1. 学习率:GMPO 的梯度通常偏小,测试中特意将learning_rate提到0.1以避免更新停滞;实际训练时如发现 loss 不下降,可优先排查学习率量级。
  2. num_iterations > 1时的重要性采样:测试注释指出num_iterations=2时重要性采样权重非零,说明多迭代下old_per_token_logps才真正来自旧策略,这是 GRPO 家族通用的机制。
  3. 默认beta=0.0:不加载参考模型,内存占用更小、速度更快;需要约束与参考模型的偏离时再开启,DeepSeek-R1 经验值0.001可作起点。
  4. epsilon/epsilon_high的非对称用法epsilon_high独立于epsilon设置时即可实现非对称裁剪(如epsilon=0.4, epsilon_high=0.28),满足对上下界不同容忍度的场景。
  5. 限制:测试注释明确"Streaming datasets are not yet supported in GMPO"(流式数据集暂不支持);eval_dataset支持单数据集、DatasetDict、字典三种形态。
  6. 作为实验性功能GMPOTrainer位于trl.experimental.gmpo命名空间下,API 属于实验性模块,升级 trl 时需留意接口变更(MIGRATION.md 中会有相关迁移说明)。

小结

GMPO 与 GRPO 的差异可以浓缩为一句话:GRPO 在比率空间用算术均值,GMPO 在 log 空间裁剪后取几何均值。在 trl 中,这只意味着换一个 Trainer 类、改一个epsilon默认值——生成、奖励、权重同步全部复用 GRPO 的成熟实现,而目标函数的稳定性收益则由 gmpo_trainer.py 中几十行_compute_loss精妙地承载。如果你想在 GRPO 基础上获得更稳的策略更新并让探索更充分,GMPO 是一个低接入成本、高理论清晰度的选择。

【免费下载链接】trlTrain transformer language models with reinforcement learning.项目地址: https://gitcode.com/GitHub_Trending/tr/trl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询