verl调参指南
GRPO 训练与调参梳理
前言
不久前尝试复现了一个 GRPO 训练 Qwen2.5-VL-7B 的工作,当时面对 verl 繁多的参数,看个文档也是一知半解,简单粗暴地改小了 train_batch_size 试图增加 logging 频率,结果没练几步就爆了。


这次重回 verl 进行训练,决定先把这些参数背后的逻辑彻底理顺。
概念梳理
在聊流程之前,我们得先搞清楚 verl 里这几个容易打架的 Batch Size 概念。这几个参数如果不区分清楚,后面的逻辑很难盘得通:
首先是 train_batch_size,这是宏观层面的一次“采样大部队”。它决定了在一次采样阶段(Rollout),模型总共要处理多少个不同的 Prompt。
其次是 rollout.n,也就是 Group Size。GRPO 的特点就是对同一个 Prompt 生成多个回复(Group),然后组内比较优势。所以,实际上模型在采样阶段产生的数据总量是 train_batch_size * rollout.n。
有了数据就要训练,这就轮到 ppo_mini_batch_size 了。这才是优化器(Optimizer)真正关心的参数——每次更新权重时“吃”多少数据。
至于 micro_batch_size,它纯粹是为了照顾显存的。如果显卡塞不下 mini batch,就切得更碎一点用梯度累加(Gradient Accumulation)来凑,它不影响训练逻辑。
GRPO 的两阶段循环
GRPO 的训练本质上就是两个阶段的无限循环:造数据(Rollout) 和 吃数据(Update)。
第一阶段:造数据 (Rollout)
这个时候模型是冻结的(eval 模式),它的任务就是根据当前的策略去“见世面”。
系统会从数据集中捞出 train_batch_size 个 Prompt,然后让模型对着每个 Prompt 生成 rollout.n 个回答。
生成完之后,最关键的一步来了:模型会立刻计算这些回答的 old_log_prob。你可以把这个值看作是一个 “锚点”。在接下来的训练中,无论模型参数怎么变,这个锚点数值是绝对不会变的。它就像是一个参照系,用来时刻提醒模型:“你现在的策略和刚开始采样时的策略差了多远”。
第二阶段:吃数据 (PPO Update)
数据造好了,Reward Model 也打完分了,现在模型切换到训练模式(train),开始参数更新。
通常我们会把这批造好的数据重复利用几次(ppo_epochs),在每一个 Epoch 里,数据被切分成小块(ppo_mini_batch_size)喂给优化器。
这里有个非常重要的细节:
我们在 PPO Update 中会进行多次 optimizer.step()。虽然每一次更新后,模型的参数都变了,新计算出的概率(log_prob)也变了,但我们在第一阶段算好的那个“锚点”(old_log_prob)是定死的。
这意味着,随着更新步数越来越多,现在的模型策略会逐渐偏离采样时的策略。
为什么会练崩?调参背后的逻辑
理解了上面的流程,之前的“崩盘”原因就呼之欲出了。调参的核心,其实就是在平衡**“外循环的广度”和“内循环的深度”**。
1. 外循环:为什么 train_batch_size 越大越稳?
train_batch_size 决定了模型在改变策略之前,到底看了多少“案例”。
- 如果 Batch 很小(比如 256): 这就好比一个学生,做了一道题就急着对答案、改思路。这道题可能比较偏,学生改完思路后,再做下一道题发现又不对,于是又改。模型就会陷入这种“做一题改一次”的震荡中,非常容易过拟合当前的局部数据,导致策略剧烈抖动。
- 如果 Batch 很大(比如 10240): 这就像学生做完了一整套模拟卷(100题),综合了所有题目的得失,才总结出一套改进方案。这种基于大样本量的梯度方向是非常稳健的,因为它看到了数据的“全貌”。
所以结论很简单:只要显存和时间允许,train_batch_size 越大越好。
2. 内循环:ppo_mini_batch_size 的黄金比例
确定了要采多少数据(Train Batch),接下来就是决定“怎么吃掉这批数据”。这时候 ppo_mini_batch_size 就很关键了。
- 吃得太慢(Mini Batch 太小):
这意味着你需要更新很多次参数才能吃完这批数据。就像上面说的,更新次数越多,模型策略偏离“锚点”就越远。
这就导致到了后面几步,模型现在的想法和采样时的想法已经天差地别了。此时计算出的 Ratio (
log_prob / old_log_prob) 会变得极不稳定,PPO 的裁剪机制(Clip)会强制把梯度切零。结果就是:你后面算的这些步数,基本都是无效计算,甚至是有害的。 - 吃得太快(Mini Batch 太大):
假如你直接一口吞(Mini Batch = Train Batch),那这一轮 Rollout 辛辛苦苦生成的几万条数据,只换来了一次
optimizer.step()。这就太奢侈了,数据利用率极低,训练效率慢得令人发指。
所以,这里需要一个**“黄金比例”**。经验法则通常是:调节 Mini Batch 的大小,让每一轮 Rollout 的总更新步数保持在 4-8 步左右。 既保证了数据被重复利用,又不会让策略偏离太远。
3. 实战避坑指南
最后总结一下,我们在看 Log 的时候,主要盯着 Clip Ratio 和 KL Divergence 这两个指标看就行:
- 如果你发现
Clip Ratio特别低 (< 1%),而且 Loss 下降得很慢。那说明你太保守了,数据还没被榨干。 👉 尝试:减小ppo_mini_batch_size(多更几步),或者干脆多跑一个 Epoch。 - 如果你发现
Clip Ratio飙升 (> 15%),或者 KL 散度突然爆炸。那说明你太激进,模型已经“学歪了”。 👉 尝试:增大ppo_mini_batch_size(少更几步),让模型“少吃多餐”变为“多吃少餐”,稳住心态。