RL 算法性能调优指南
覆盖 PPO / GRPO / DAPO / VERL,聚焦超参数 + 算法特性调优,零废话
一、训练流程与瓶颈定位
1.1 典型 RL 训练循环(以 PPO 为例)
环境交互 → 采样 trajectory → 计算 advantage → 策略更新 → 网络同步
↑ ↓
采样慢 更新震荡 / 崩溃
每个环节都可能成为瓶颈:
| 环节 | 常见问题 | 症状 |
|---|---|---|
| 环境交互 | CPU 单线程,GPU 空闲等数据 | GPU 利用率 < 30% |
| Advantage 估计 | GAE 参数不当,variance 大 | Reward 曲线剧烈抖动 |
| 策略更新 | LR 过大,epoch 过多 | Loss 爆炸或 NaN |
| 价值网络 | 估计偏差大,导致策略误导 | Critic Loss 持续偏高 |
| 梯度更新 | 梯度爆炸/消失 | Loss → NaN 或 Critic Loss → ∞ |
1.2 瓶颈快速定位三问
- Loss 是 NaN? → 梯度爆炸,检查
clip_range、max_grad_norm、reward scaling - Reward 不涨? → 策略没更新,检查
entropy_coef(是否探索不足)或 LR - GPU 闲置? → 环境交互太慢,检查
num_envs(并行环境数)
二、核心超参数详解
2.1 学习率(Learning Rate)
| 值域 | 效果 |
|---|---|
3e-4 ~ 1e-3 |
默认安全区,适合大多数任务 |
1e-3 ~ 3e-3 |
初期快速收敛,但易震荡,中后期需 lr_decay |
< 1e-4 |
稳定但收敛慢,适合复杂任务微调 |
调度策略(关键但常被忽略):
python
# 余弦退火 --- 最通用的选择
lr = config.lr * (1 + cos(π * step / total_steps)) / 2
# 线性预热 + 余弦衰减 --- 防止初期梯度过大
if step < warmup_steps:
lr = config.lr * step / warmup_steps
else:
progress = (step - warmup_steps) / (total_steps - warmup_steps)
lr = config.lr * (1 - progress)
2.2 PPO-Clip 范围(clip_range / epsilon)
作用:限制策略更新步长,防止一次更新过大导致性能崩溃。
旧策略概率比 r(θ) = π_θ(a|s) / π_θ_old(a|s)
PPO 目标:L^CLIP(θ) = E[ min(r(θ)·A, clip(r(θ), 1-ε, 1+ε)·A) ]
clip 效果:当 |A| 大时,允许更大的策略变化
clip_range |
策略稳定性 | 样本效率 | 适用场景 |
|---|---|---|---|
0.1 ~ 0.2(保守) |
低震荡 | 较低 | 训练后期、脆弱环境 |
0.2 ~ 0.3(激进) |
可能震荡 | 高 | 简单任务、离线微调 |
自适应 clip:DAPO 核心改进之一,动态调整 clip 范围(见第五节)。
2.3 GAE(Generalized Advantage Estimation)
A_t = δ_t + (γλ)·δ_{t+1} + (γλ)²·δ_{t+2} + ...
δ_t = r_t + γ·V(s_{t+1}) - V(s_t)
| 参数 | 作用 | 推荐值 |
|---|---|---|
λ(GAE 参数) |
balance variance 与 bias | 0.9 ~ 0.95 |
γ(折扣因子) |
未来 reward 重要性 | 0.99(标准),0.995(长视野) |
λ 越接近 1 :bias 小,variance 大(TD(∞)),适合长序列决策
λ 越接近 0:variance 小,bias 大(TD(0)),适合稀疏奖励
2.4 Epochs 与 Batch Size
| 参数 | 值 | 效果 |
|---|---|---|
ppo_epochs |
4 ~ 10 |
多次对同一批数据更新,提高样本效率但易过拟合 |
batch_size |
256 ~ 512 |
越大梯度越稳定,但显存压力增大 |
num_mini_batch |
4 ~ 8 |
分成更多 mini-batch,减少过拟合 |
常见错误 :ppo_epochs=1,数据只过一遍,样本利用率极低。
2.5 熵系数(Entropy Coefficient)
策略熵 H(π) = -Σ π(a|s) log π(a|s)
熵大 → 探索多,策略更随机
熵小 → exploitation,策略更确定
entropy_coef |
效果 |
|---|---|
0(禁用) |
策略可能早熟,陷入局部最优 |
0.01 ~ 0.1 |
标准推荐值 |
| 随训练衰减 | 前期多探索,后期稳定 exploitation |
| 自动调节(SAC α) | 动态维持目标熵,但需要调参稳定 |
早停信号 :如果 entropy 在前几个 episode 就急剧下降 → 策略已早熟,加大 entropy_coef。
三、价值网络调优
3.1 Value Function 估计偏差
价值网络估计不准是 RL 训练失败最常见的原因之一:
真实 V(s) vs 估计 V_θ(s)
偏差(Bias):高估/低估 reward
方差(Variance):估计波动大
两者都会导致策略学偏
3.2 常用解法
① Value Function 损失加权
python
# 过度信任价值网络会中毒,加权重限制梯度
value_loss = F.mse_loss(v_pred, v_target)
value_loss = min(value_loss, # 标准 loss
F.mse_loss(v_pred.detach(), v_target)) # 限制梯度不反向传播
② 双 Q 网络(Double Q)
python
# 用在线网络选择动作,用目标网络评估,减小高估偏差
next_action = online_network(next_state).argmax(1)
next_q = target_network(next_state, next_action)
③ Value Clipping(PPO)
python
# 限制 value 变化幅度,防止 value 估计剧烈波动
v_clipped = v_old + clamp(v_pred - v_old, -ε, +ε)
value_loss = max(loss(v_pred, v_target), loss(v_clipped, v_target))
3.3 Reward Scaling
Pendulum 类环境原始 reward 范围很大(-1600 ~ 0),直接用会数值不稳定:
python
# 方法1:除以 running reward 标准差
reward = reward / running_reward_std
# 方法2:clamp 到固定范围
reward = reward.clamp(-10, 10)
# 方法3:简单除以常数(Pendulum 常用 /10.0)
reward = reward / 10.0
警告:测试集不用 running stats,只用训练集的统计值。
四、探索策略调优
4.1 连续动作空间的探索
| 方法 | 原理 | 优缺点 |
|---|---|---|
| 随机扰动(DDPG) | 在确定性策略输出上加噪声 | 简单,但噪声相关性差 |
| 熵正则化(SAC) | 最大化 π 的熵 | 数学优雅,KL 版本有理论保证 |
| Normalizing Flow | 变换简单分布为复杂分布 | 表达力强,计算开销增加 |
4.2 离散动作空间的探索
| 方法 | 适用场景 |
|---|---|
| UCB(Upper Confidence Bound) | Bandit 类任务,平衡探索/利用 |
epsilon-greedy |
简单任务,ε 从 1.0 线性/指数衰减到 0.01 |
| Gumbel-Softmax | 可微采样,连续近似离散,用于策略梯度 |
entropy_coef |
PPO 中加熵项,鼓励探索 |
4.3 经验回放(Replay Buffer)调优
python
# 经验回放不是越大越好
buffer_size = 100_000 # 太大 = 早期经验被稀释
buffer_size = 10_000 # 太小 = 样本多样性不足
# 优先回放(PER):高 TD Error 的样本更重要
priority = abs(TD_error) + ε
五、DAPO --- 自适应 Clip 的 PPO 改进
DAPO(Decoupled Clip and Dynamic Sampling Policy Optimization)是 2024-2025 年提出的 PPO 改进,核心解决 clip 导致的数据效率损失。
5.1 PPO-Clip 的根本问题
PPO: L^CLIP = min(r·A, clip(r, 1-ε, 1+ε)·A)
当 A > 0(优势动作):clip 阻止概率比 r 超过 1+ε
当 A < 0(劣势动作):clip 阻止概率比 r 低于 1-ε
→ 问题:即使 clip 后,被 clip 的样本对梯度贡献变成 0,
这些样本被完全浪费
5.2 DAPO 的三处核心改进
① Token-Level Clip(替代 Episode-Level Clip)
PPO 对整个 episode 的策略变化做 clip,DAPO 对每个 token 的策略变化做 clip,粒度更细,利用率更高。
② Dynamic Sampling(动态采样)
python
# 过滤掉没有信息的样本(优势≈0的样本)
# 这些样本 clip 后梯度贡献为0,没必要参与更新
mask = abs(advantage) > threshold
loss = policy_loss[mask].mean()
③ Decoupled Clip(解耦 Clip)
python
# PPO:clip 和 importance sampling 耦合
# DAPO:分开处理,clip 只作用在 ratio 上,不影响 advantage 的计算
ratio = pi_new / pi_old
clipped_ratio = clamp(ratio, 1-ε, 1+ε)
policy_loss = clipped_ratio * advantage
效果:在 ChatGLM、Shoot 等任务上,DAPO 相比 PPO 样本效率提升 1.5-3x。
六、GRPO --- 免 Critic 的策略优化
GRPO(Group Relative Policy Optimization)是 DeepSeek 系列提出的新范式,核心思想:不要 Critic,用样本组内的相对比较来估计优势。
6.1 GRPO vs PPO 的核心区别
PPO: 需要 Value Network V(s) → Critic 估计状态价值
两大网络(Actor + Critic)→ 调参翻倍
GRPO: 同一状态生成多个候选动作,组内相对排序 → 无需 Critic
6.2 GRPO 算法流程
1. 对每个状态 s,采样 G 个动作 {a_1, ..., a_G}
2. 对每个 (s, a_i) 估计 Q(s, a_i)(用 reward 或奖励模型)
3. 组内归一化优势:
A_i = (Q_i - mean(Q)) / std(Q)
4. 用 PPO-style clip 策略更新:
L = min(ratio · A_i, clip(ratio, 1-ε, 1+ε) · A_i)
5. KL 正则化(可选):
L += β · D_KL(π || π_old)
6.3 GRPO 的优势
| 方面 | PPO | GRPO |
|---|---|---|
| 网络数 | 2(Actor + Critic) | 1(只有 Actor) |
| Critic 调参 | 需要调 LR、GAE、value loss weight | 不需要 |
| 样本效率 | 中等 | 高(无 value 估计偏差) |
| 适用场景 | 通用,reward 噪声小 | 大模型 RLHF、reward 估计不稳定场景 |
6.4 GRPO 的注意事项
- 组大小 G :G 越大,相对排序越可靠,但计算成本越高。推荐
G=8~G=16 - Reward 噪声:如果 reward 本身噪声大(人类反馈),需要 reward model 平滑
- KL 约束:没有 Critic 时加 KL 项防止策略崩溃成 delta 分布
七、VERL --- 大规模训练工程优化
VERL(Rich Evolution via Large-scale Reinforcement Learning)不是算法,而是训练工程框架,核心解决大模型 RL 训练的系统瓶颈。
7.1 大模型 RL 的三个工程挑战
1. GPU 内存墙:Actor + Critic + Optimizer States → 显存 OOM
2. 通信瓶颈:多 GPU 采样/更新同步,GPU 利用率低
3. 离线数据效率:已有离线轨迹数据,RL 微调效率低
7.2 VERL 的核心策略
① 梯度累积 + 虚拟批次
实际 batch = 32
虚拟 batch = 256(通过梯度累积多次前向累积梯度)
→ 用小显存跑大 batch 训练
② Actor-Critic 分离部署
GPU 0-7: Actor 网络(推理,显存占用低)
GPU 8-15: Critic 网络(训练,高显存)
All-to-All 通信:Advantage 计算
→ 减少 Critic 推理的显存占用
③ 离线数据复用
python
# 对离线轨迹做 advantage 重估计
# 用新 Critic 对旧轨迹重新计算 A(s,a)
# 不需要重新采样,直接复用已有轨迹
offline_advantages = new_critic.estimate(old_trajectories)
7.3 配套调参建议(配合 VERL 框架)
| 参数 | 框架默认值 | 大模型调优建议 |
|---|---|---|
gradient_accumulation_steps |
1 |
4 ~ 8 |
micro_batch_size |
1 |
4 ~ 8 |
adam_epsilon |
1e-8 |
1e-6(大模型防震荡) |
max_grad_norm |
1.0 |
0.5 ~ 2.0 |
八、调试 Checklist(按优先级)
🔴 第一优先级(几乎必做)
- Reward scaling(除以 std 或 clamp)
-
max_grad_norm = 0.5~10.0 - 学习率
3e-4~1e-4 - 检查 Critic Loss 是否为 NaN
🟡 第二优先级(效果显著)
-
clip_range = 0.1~0.2(过大=不稳定,过小=不学习) - GAE
λ = 0.9~0.95 -
entropy_coef> 0(防止早熟) -
ppo_epochs = 4~10(太小样本浪费,太大过拟合) - 确认
num_envs并行环境数与 GPU 利用率匹配
🟢 第三优先级(锦上添花)
- LR 预热(warmup 500~1000 步)
- 余弦退火衰减
- Double Q 减小高估
- Priority Experience Replay
- Advantage 标准化(减 mean 除 std)
❌ 常见错误清单
| 错误 | 现象 | 解法 |
|---|---|---|
| LR 过大 | Loss 爆炸 → NaN | 降低 10x |
| clip_range 过大 | 策略崩溃 | 降到 0.1~0.2 |
| entropy_coef = 0 | 策略早熟,reward 卡住 | 增加到 0.01~0.1 |
| value_loss_weight 过大 | Critic 压制 Actor 更新 | 降到 0.5~1.0 |
| buffer 太小 | 样本多样性不足 | 至少 50000 |
| 单环境采样 | GPU 95% 时间在等数据 | 并行 num_envs >= 8 |
九、主流算法对照表
| 算法 | Critic | 适用场景 | 调参难度 | 样本效率 |
|---|---|---|---|---|
| PPO | 需要 | 通用首选 | ★★ | 中 |
| SAC | 需要(双Q) | 连续控制 | ★★ | 高 |
| TD3 | 需要(双Q+延迟更新) | 连续控制 | ★★★ | 高 |
| DQN | 需要(目标网络) | 离散动作 | ★ | 中 |
| GRPO | 不需要 | 大模型 RLHF,离线场景 | ★ | 高 |
| DAPO | 需要 | PPO 升级,离线+在线 | ★★ | 更高 |
调参的第一原则:先让系统稳定运行,再追求性能。Loss 不崩溃、Reward 不变差,比追求高 Reward 更优先。瓶颈定位永远先于调参。
十、VERL 系统参数调优(分布式 RL 训练)
示例脚本:examples/grpo_trainer/run_qwen3-32b_npu.sh
python
set -x
project_name='GRPO-Qwen3'
exp_name='GRPO-Qwen3-32b-npu'
gen_tp=4
RAY_DATA_HOME=${RAY_DATA_HOME:-"${HOME}/verl"}
MODEL_PATH=${MODEL_PATH:-"${RAY_DATA_HOME}/models/Qwen3-32B"}
TRAIN_FILE=${TRAIN_FILE:-"${RAY_DATA_HOME}/data/gsm8k/train.parquet"}
TEST_FILE=${TEST_FILE:-"${RAY_DATA_HOME}/data/gsm8k/test.parquet"}
python3 -m verl.trainer.main_ppo \
algorithm.adv_estimator=grpo \
data.train_files="${TRAIN_FILE}" \
data.val_files="${TEST_FILE}" \
data.train_batch_size=1024 \
data.max_prompt_length=2048 \
data.max_response_length=2048 \
data.filter_overlong_prompts=True \
data.truncation='error' \
data.shuffle=False \
actor_rollout_ref.model.path=${MODEL_PATH} \
actor_rollout_ref.actor.optim.lr=1e-6 \
actor_rollout_ref.model.use_remove_padding=True \
actor_rollout_ref.actor.ulysses_sequence_parallel_size=4 \
+actor_rollout_ref.actor.fsdp_config.mixed_precision.param_dtype=bf16 \
+actor_rollout_ref.actor.fsdp_config.mixed_precision.reduce_dtype=bf16 \
+actor_rollout_ref.actor.fsdp_config.mixed_precision.buffer_dtype=fp32 \
actor_rollout_ref.actor.ppo_mini_batch_size=64 \
actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=8 \
actor_rollout_ref.actor.use_kl_loss=True \
actor_rollout_ref.actor.entropy_coeff=0 \
actor_rollout_ref.actor.kl_loss_coef=0.001 \
actor_rollout_ref.actor.kl_loss_type=low_var_kl \
actor_rollout_ref.model.enable_gradient_checkpointing=True \
actor_rollout_ref.actor.fsdp_config.param_offload=True \
actor_rollout_ref.actor.fsdp_config.optimizer_offload=False \
actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=8 \
actor_rollout_ref.rollout.tensor_model_parallel_size=${gen_tp} \
actor_rollout_ref.rollout.name=vllm \
actor_rollout_ref.rollout.gpu_memory_utilization=0.7 \
actor_rollout_ref.rollout.n=4 \
actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=8 \
actor_rollout_ref.ref.fsdp_config.param_offload=True \
actor_rollout_ref.actor.use_torch_compile=False \
actor_rollout_ref.ref.use_torch_compile=False \
actor_rollout_ref.rollout.enable_chunked_prefill=True \
actor_rollout_ref.rollout.max_num_batched_tokens=32768 \
actor_rollout_ref.rollout.checkpoint_engine.update_weights_bucket_megabytes=4096 \
algorithm.use_kl_in_reward=False \
trainer.critic_warmup=0 \
trainer.logger=['console','tensorboard'] \
trainer.project_name="${project_name}" \
trainer.experiment_name="${exp_name}" \
trainer.n_gpus_per_node=8 \
trainer.nnodes=4 \
trainer.resume_from_path=checkpoints/ \
trainer.save_freq=500 \
trainer.test_freq=50 \
trainer.total_epochs=50 $@
10.1 基础路径与项目配置
| 参数 | 示例值 | 作用 |
|---|---|---|
project_name |
'GRPO-Qwen3' |
TensorBoard/WandB 项目名 |
exp_name |
'GRPO-Qwen3-32b-npu' |
当前实验命名,区分不同跑法 |
MODEL_PATH |
'models/Qwen3-32B' |
模型权重路径 |
TRAIN_FILE / TEST_FILE |
'gsm8k/train.parquet' |
训练/测试数据 |
resume_from_path |
'checkpoints/' |
中断后恢复训练的检查点路径 |
10.2 数据与 Token 长度
| 参数 | 值 | 作用 |
|---|---|---|
data.train_batch_size |
1024 |
一次梯度更新用的样本数 |
data.max_prompt_length |
2048 |
prompt token 上限 |
data.max_response_length |
2048 |
response token 上限 |
data.filter_overlong_prompts |
True |
过滤超长 prompt,避免 vLLM 崩溃 |
data.truncation |
'error' |
截断方式:'error' 抛异常比静默截断安全 |
data.shuffle |
False |
训练数据是否打乱 |
max_response_length 调参逻辑:
过短:模型无法完整生成回答 → reward 评估不准确
过长:vLLM 显存压力增大,throughput 下降
推荐:GSM8K → 512~1024,代码任务 → 2048~4096
10.3 分布式并行策略
| 参数 | 值 | 含义 |
|---|---|---|
gen_tp |
4 |
Tensor Parallelism,切分 Q/K/V/O 线性层 |
trainer.n_gpus_per_node |
8 |
每节点 GPU 数 |
trainer.nnodes |
4 |
节点总数 |
actor_rollout_ref.actor.ulysses_sequence_parallel_size |
4 |
Ulysses 序列并行(SP),对长序列有效 |
actor_rollout_ref.rollout.tensor_model_parallel_size |
${gen_tp} |
vLLM 推理时的 TP |
TP vs FSDP vs Ulysses 怎么选:
模型能装进单卡 → 不用 TP,只用 FSDP(更简单)
模型装不下 + 序列很长 → TP + Ulysses
序列不长 + 模型装不下 → FSDP 为主
10.4 FSDP 显存 Offload 策略(最关键的调参之一)
| 参数 | 值 | 显存节省 | 速度影响 |
|---|---|---|---|
param_offload=True |
参数 offload 到 CPU | ★★★★★ 最大 | 慢 2-3x |
optimizer_offload=False |
Optimizer states 留 GPU | 节省 | 保持速度 |
buffer_dtype=fp32 |
缓冲区用 fp32 | 更稳 | 略高显存 |
python
# 32B 模型,8卡,每卡约 40GB 显存
param_offload=True, optimizer_offload=False # 能跑,但慢
param_offload=True, optimizer_offload=True # 显存最省,但极慢
param_offload=False, optimizer_offload=False # 显存不够会 OOM
经验法则 :先 param_offload=True,如果 OOM 再开 optimizer_offload=True。
10.5 精度与梯度配置
| 参数 | 值 | 作用 |
|---|---|---|
param_dtype=bf16 |
参数用 bf16 | 省显存,足够精度 |
reduce_dtype=bf16 |
梯度聚合用 bf16 | bf16 聚合比 fp32 快 |
buffer_dtype=fp32 |
缓冲区用 fp32 | 计算安全,不易 NaN |
enable_gradient_checkpointing=True |
前向不存中间激活,用时重算 | 省显存 30-50% |
10.6 PPO Mini-Batch / Micro-Batch 配置
| 参数 | 值 | 含义 |
|---|---|---|
ppo_mini_batch_size |
64 |
一次 PPO 更新用的样本数 |
ppo_micro_batch_size_per_gpu |
8 |
每个 GPU 前向次数(gradient accumulation) |
rollout.log_prob_micro_batch_size_per_gpu |
8 |
rollout log prob 计算的 micro batch |
ref.log_prob_micro_batch_size_per_gpu |
8 |
reference model log prob 的 micro batch |
显存不够时的调参顺序:
1. 先减小 ppo_micro_batch_size(8 → 4 → 2)
2. 再减小 rollout.log_prob_micro_batch_size
3. 最后开 param_offload
10.7 vLLM Rollout 引擎配置
| 参数 | 值 | 作用 |
|---|---|---|
rollout.name |
'vllm' |
用 vLLM 而非 HF 推理,快 5-10x |
rollout.gpu_memory_utilization |
0.7 |
vLLM 用 70% 显存,30% 留溢出 |
rollout.n |
4 |
每个 prompt 生成 4 个 candidate(GRPO 用) |
rollout.enable_chunked_prefill |
True |
分块 prefill,省显存 |
rollout.max_num_batched_tokens |
32768 |
一次 batch 的最大 token 数 |
gpu_memory_utilization 调参:
0.7(保守):不易 OOM,但 throughput 低
0.8 ~ 0.85:常见推荐值
0.9+:吞吐最高,但多节点训练时易因通信触发 OOM
n=4 的意义(GRPO 核心):
GRPO 需要同个 prompt 生成 G 个动作 → 组内相对排序
n 就是 G,推荐 4~16
n 越大排序越可靠,但 rollout 成本线性增长
10.8 Actor / Reference / Critic 协同配置
| 参数 | 值 | 作用 |
|---|---|---|
use_kl_loss=True |
Actor 与 Ref 用 KL 约束 | 防止策略偏离 Ref 太远 |
kl_loss_coef |
0.001 |
KL 项权重,太大=学不动,太小=策略偏离 |
kl_loss_type |
'low_var_kl' |
低方差 KL 估计,比标准 KL 数值更稳定 |
entropy_coeff=0 |
不加熵正则 | GRPO 依赖组内相对排序,不需要额外熵项 |
use_kl_in_reward=False |
KL 不进 reward 函数 | KL 只做梯度约束,不做 reward 惩罚 |
10.9 KL 损失调参实战经验
kl_loss_coef 太小的表现:
→ 策略快速偏离 Reference Model
→ reward 可能很高但输出格式崩溃
→ 典型:模型开始输出乱码 / 重复 token
kl_loss_coef 太小的表现:
→ 策略几乎不更新,reward 不涨
→ 相当于原始 SFT 模型
参考范围:
小模型(7B):0.001 ~ 0.01
大模型(32B+):0.0005 ~ 0.001
开源模型(Qwen/Llama):0.001 ~ 0.005
10.10 其他 Trainer 配置
| 参数 | 值 | 作用 |
|---|---|---|
critic_warmup=0 |
Critic 不预热 | GRPO 不需要 Critic,设为 0 |
save_freq=500 |
每 500 步保存检查点 | |
test_freq=50 |
每 50 步跑一次评估 | |
total_epochs=50 |
总训练轮数 | |
logger=['console','tensorboard'] |
同时打印和记录 | WandB 换成 'wandb' |
10.11 完整调参 Checklist(VERL 分布式场景)
能跑起来(第一步):
-
gpu_memory_utilization从 0.7 开始 -
param_offload=True先开 -
ppo_micro_batch_size从小往大试(4 → 8 → 16) -
filter_overlong_prompts=True防止 vLLM 崩溃
性能调优(第二步):
-
param_offload=False提升速度(如果显存够) -
gpu_memory_utilization提到 0.8 -
enable_chunked_prefill=True开启 -
max_num_batched_tokens配合 batch_size 调
收敛调优(第三步):
-
kl_loss_coef从 0.001 开始,根据输出质量调 -
n=4(GRPO 组大小),reward 噪声大时加大 -
actor.optim.lr:大模型用更小的 LR(1e-6 ~ 5e-6 for 32B+) -
entropy_coeff=0对 GRPO 是对的,不要改成非 0
VERL 调参的本质 :不是调算法,是调显存 / 速度 / 稳定性的三角tradeoff。永远先让它稳定跑起来,再追性能。**