Chapter 11

常见错误与性能调优

📌 本章问题汇总基于 GitHub issues / verl Slack 频道高频项 · commit 9c38b8bb1876 。

RLHF 是"训练框架 + 推理引擎 + 调度系统"的合奏,故障点比纯训练框架多。本章按"出错时间线"组织。

11.1 启动阶段错误

现象原因修复
ImportError: cannot import name '...' from 'tensordict'tensordict 版本不在锁定区间 降到 0.8.x
ray.exceptions.RaySystemError: ... port already in use之前 Ray 实例没关 ray stop --force 再重启
FileNotFoundError: examples/data_preprocess/gsm8k.py recipe 子仓没拉 git submodule update --init --recursive recipe
Hydra 报 could not override 'xxx' 字段不存在 看第 8 章 8.6 节查字段
HYDRA_FULL_ERROR not set 报错信息被截 HYDRA_FULL_ERROR=1
vLLM init 报 CUDA mismatch PyTorch / CUDA / vLLM 版本不一致用 docker 镜像
Megatron 加载 HF checkpoint 失败 没转格式 用 Megatron-Bridge 转

11.2 训练阶段错误

现象原因修复
rollout 阶段 OOM vLLM gpu_memory_utilization 太大降到 0.5;升 rollout TP
训练阶段 OOM actor 显存不够 开 FSDP offload;降 ppo_micro_batch_size_per_gpu;开 grad ckpt
resharding 阶段 OOM weight gather 占满显存 开 streaming sharding;缩 actor TP
NCCL hang(多卡) 某 worker 卡住 NCCL_DEBUG=INFO;查异常 rank
训练后 logp 与 rollout logp 差异大 训推 mismatch rollout_correction 或换 vexact
第一步训练就 NaN 数据 / 模板坏 查 prompt template;查样本 token id 越界
训几十步后 NaN 梯度爆炸 grad_clip;降 lr
Ray actor 自死 worker 内部异常 ~/ray_results/<exp>/ 下 stderr

11.3 算法层面的"不对劲"

症状多半原因调哪几个字段
reward 不涨 lr 太小 / KL 太重 actor.optim.lr;降 kl_loss_coef
reward 飙升但生成变蠢 reward hacking 补 format / length 惩罚;RM 多样性
KL 失控 lr 高 + KL 系数低 降 lr;升 kl_loss_coef;clip 收紧
response 越训越短 短回答 reward 更高 加长度奖励;用 SimPO 风格归一
response 越训越长(GRPO 常见)长 reward 高 + token-level loss 没开开 DAPO 风格 token-level loss
熵坍塌 策略变确定性 entropy_coef;clip-higher
采样多样性差 temperature 太低 升到 1.0 - 1.2

11.4 性能调优清单

训练阶段 throughput 低

  1. actor.use_remove_padding=true(变长去 pad);
  2. actor.enable_gradient_checkpointing=true(激活重算);
  3. liger-kernelactor.use_liger=true
  4. torch.compileactor.use_torch_compile=true
  5. actor.ppo_micro_batch_size_per_gpu(显存允许下);
  6. FlashAttention:actor.use_fused_kernels=true

rollout 阶段慢

  1. rollout.max_num_batched_tokens
  2. rollout.enable_chunked_prefill=true
  3. rollout.tensor_model_parallel_size(小模型 TP 不要太大);
  4. rollout.gpu_memory_utilization(同时小心 OOM);
  5. 试 SGLang 后端做对比;
  6. rollout.max_num_seqs

resharding 慢

  1. 开 streaming weight transfer;
  2. 对 MoE 开 router replay;
  3. 训推后端权重布局要对齐(FSDP + vLLM 默认 OK,Megatron + SGLang 要看 sharding_manager 是否支持)。

11.5 监控指标速查

指标正常区间异常预警
reward/mean 缓慢上升 飙升 → 检查 reward 设计
kl/mean 0.001 - 0.1> 1 → 策略漂移严重
actor/entropy 2 - 6 < 1 → 熵坍塌
actor/grad_norm 0.1 - 1 > 10 → 梯度爆炸
actor/ppo_kl < clip_ratio触顶 → ratio 经常被 clip
actor/clip_frac 0.05 - 0.3 > 0.5 → lr 过高
response_length/mean 稳定或缓升 暴涨 → length hacking
throughput/rollout 跌 → 网络 / vLLM 异常

11.6 多机训练专属问题

现象修复
Ray dashboard 跨机看不到 worker 检查 ray_init.address;防火墙开 10001 / 8265 端口
NCCL 跨机带宽极低 nvidia-smi topo -m;启用 RDMA / IB
checkpoint 存到 NFS 慢 checkpoint 写本地,定期 rsync 到 NFS
多机时 Hydra 找不到 train_files 共享文件系统挂同路径;或 parquet 提前 copy 到每节点
跨机 ray worker 启动失败 检查 ssh 免密;RAY_BACKEND_LOG_LEVEL=debug

11.7 提 issue 的最小信息清单

  1. verl commit hash:git -C /path/to/verl rev-parse HEAD
  2. 关键依赖:pip list | grep -i 'torch\|vllm\|sglang\|ray\|hydra\|tensordict'
  3. OS + CUDA + driver:uname -a; nvcc --version; nvidia-smi
  4. 启动命令 + Hydra --cfg job 输出;
  5. 完整 stderr(含 Ray worker stderr,路径在 ~/ray_results/);
  6. 能否在 NaiveWorkerGroup 模式(绕过 Ray)复现?

11.9 TransferQueue:rollout → train 的零拷贝管道

main_ppo_sync.py(同步路径)和 fully_async 都用 TransferQueue 取代默认的 ray put/get。verl/experimental/transfer_queue/ 里的实现要点:

启用:

algorithm:
  transfer_queue:
    enabled: true
    max_queue_length: 256        # 队列长度上限

启用后 main 入口会自动设 TRANSFER_QUEUE_ENABLE=1 环境变量(main_ppo.py:71)。看监控时多了 tq/queue_lentq/wait_time_ms 两个指标——前者长期满 = train 跟不上 rollout,后者长 = rollout 跟不上 train。

11.10 Fully Async 与 One-Step Off-Policy 实战数据

这两个特性详细机制见 ch05.13–5.14,本节给"什么时候选哪个"的决策表。README 公布的 benchmark:

配置硬件 / 模型相对 colocate-sync 加速最终精度
colocate sync(baseline) 128 卡 Qwen2.5-7B DAPO 1.00× baseline
one-step off-policy (Megatron) Qwen2.5-Math-7B DAPO +23–40% 65.7% AIME(vs 60.5%)
fully_async (FSDP) 128 卡 Qwen2.5-7B DAPO 2.35× 持平 baseline
fully_async (Megatron) 同上 2.67× 持平 baseline

实战选型经验:

11.11 Checkpoint engine:5 种后端

verl/checkpoint_engine/ 提供多后端 checkpoint 写入。读 checkpoint_engine/base.py 能看到统一接口,下面是已经有的实现:

后端用途典型选择
nccl 纯 NCCL collective 同步 checkpoint,无外部依赖fully_async 默认
hccl 华为昇腾 NPU 等价 NPU 集群
kimi Kimi(月之暗面)私有协议 商业部署,需要授权
mooncake Mooncake KV / weight 缓存 分离训练-推理集群
nixl NVIDIA NIXL(GPUDirect RDMA) InfiniBand 集群

选项分散在 rollout.checkpoint_engine 子段。一般用户用 NCCL;多机 IB 集群可以试 NIXL;Mooncake / Kimi 是合作客户的扩展点,社区版本默认不启用。

11.12 Router Replay 对 MoE 训练吞吐的影响

ch06.10 已经讲了 R2 / R3 的语义,这里给"开了 router replay 之后实测吞吐变化"参考(这是 README 没强调但很重要的事实):

router_replay.mode训练吞吐相对 disabled训练稳定性
disabled 1.00× ★ IS ratio 大方差,DAPO 可能不收敛
R2 0.95× ★★★ 训练侧 replay rollout 路由,稳定
R3 0.85× ★★★★ 双向 replay,最稳但有跨 step 同步开销

"5% 吞吐换收敛性"对于 671B / 235B 这种 MoE 是非常划算的——不开 R2 / R3 可能整个训练发散,等于 -100%。

11.13 compute_throughout_metrics 的指标怎么读

ray_trainer.py:1733compute_throughout_metrics 每步会输出 throughput 相关指标。这套指标是判断"我哪里是瓶颈"的关键,速查表:

指标含义判读
throughput/total_tokens_per_sec 全局每秒 token 跌 = 整体瓶颈
throughput/gen_tokens_per_sec_per_gpu 单卡 rollout 速度 跌 = vLLM/SGLang 问题;查 KV cache 是否打满
throughput/train_tokens_per_sec_per_gpu 单卡训练速度 跌 = engine 问题;查 dynamic_bsz / sequence packing
timing/gen rollout wall time 占总时间一半以上 = 推理瓶颈
timing/old_log_prob old log_prob forward 时间 意外 > 0 时 = bypass_mode 没开
timing/adv advantage 计算时间 GRPO 应当 < 100ms
timing/update_critic critic 更新时间 GRPO 时应为 0
timing/update_actor actor 更新时间 看 ppo_epochs × ppo_mini_batch_size 是否合理

"为什么 verl 训练这么慢?"绝大多数情况是 timing/gen 大头——往 vLLM / SGLang 这边查,而不是 actor 那边。

11.8 心法

三句话原则
  1. 能用 docker 不要自己装——把环境问题排除掉一半;
  2. 小批样本先 dry run——data.train_batch_size=8 max_response_length=256,验证 reward 与训练循环;
  3. 关注监控指标的变化形态而不是绝对值——一个抖动 / 突变比一个高低值更值得排查。