Chapter 11

常见错误:Ray 死锁、显存爆、KL 失控

📌 commit 6c6056daa522 按训练时间线组织 — 启动 / 训练中 / 算法层

OpenRLHF 的故障范围比纯训练框架大一档,因为多了 Ray 调度 + vLLM 异步 + 4 个角色协同。 本章按"故障发生在哪个阶段"组织,给一份"看到这种现象 → 去哪里查"的对照表。

11.1故障调试金线

遇到任何问题,按这个顺序排查:

  1. 看 Ray dashboardhttp://<head_ip>:8265,看哪个 actor 是 DEAD;
  2. 看那个 actor 的 stderr:在 dashboard 里点进去,或 ray logs actor <ID>
  3. 看 Ray placement_groupray list placement-groups
  4. 看 NCCL debug logNCCL_DEBUG=INFO
  5. 用 max_samples=8 dry run:确认配置本身不是问题;
  6. 对照 examples/scripts/ 里的官方脚本:diff 自己的脚本,看缺啥。

11.2启动阶段错误

现象原因修复
ray.exceptions.RaySystemError 之前的 Ray 实例没关 ray stop --forceray start --head
PlacementGroup waiting forever 请求的 GPU 资源 > 实际拥有 ray status 看实际资源;检查 --xxx.num_gpus_per_node
vLLM init 极慢(> 10 分钟) flash-attn 编译 CUDA arch 不匹配 export TORCH_CUDA_ARCH_LIST="8.0;9.0"
RuntimeError: CUDA out of memory 启动时 colocate 模式但没开 sleep --vllm.enable_sleep --ds.enable_sleep
ImportError: cannot import LLM from vllm vLLM 版本不兼容 对照 requirements.txt 重装;考虑用 docker
模型下载超时 HF Hub 访问慢 国内用 export HF_ENDPOINT=https://hf-mirror.com
tokenizer chat template 缺失 base 模型没有 chat_template 显式传 --data.tokenizer_chat_template

11.3训练阶段错误

OOM

现象原因修复路径
rollout 阶段 OOM vLLM gpu_memory_utilization 太大 降到 0.4-0.5
训练阶段 OOM actor 训练显存超 gradient_checkpointing、降 max_tokens_per_gpu、上 adam_offload
resharding 阶段 OOM actor 权重 gather 后峰值过大 用 fully distributed 模式;或加 TP
第 N 步突然 OOM 遇到一条特别长的样本 --data.max_len 卡上限;filter overlong samples
checkpoint 保存时 OOM ZeRO-3 gather 完整权重 ckpt_ds_zero_to_universal.sh 分布式 save

NCCL hang

现象原因修复
训练前几步 hang actor↔vLLM 的 NCCL group 没建好 看 actor 和 vllm 进程 stderr,对齐 master_addr / master_port
多机训练 hang 跨节点网络不通 NCCL_DEBUG=INFO + NCCL_IB_DISABLE=0
训练若干 step 后 hang 某 actor crash 但其他还在等 RPC Ray dashboard 找 DEAD actor,看其 stderr
NCCL timeout 默认 30 分钟太短 export NCCL_TIMEOUT=3600

NaN / 数值不稳

现象原因修复
第 1 步就 NaN 数据格式坏 / template 错 跑 SFT 模型 baseline 验证数据
训了几十步 NaN 梯度爆炸 / fp16 数值范围窄 用 bf16;开 --algo.adam.grad_clip 1.0
policy_loss = inf importance ratio 飘到极端值 降 lr;开 --algo.advantage.is_correction_enable
value_loss 不下降 critic lr 太小或没初始化好 critic lr 升到 1e-5;检查是否从 RM 初始化

11.4算法层的"不对劲"

症状多半原因调哪几个字段
reward 不涨 lr 太小 / KL 太重 actor.adam.lr;降 algo.kl.init_coef
reward 飙升但生成质量降 reward hacking 补 length / format 惩罚;缩 epoch
KL 失控(涨到 100+) lr 太大 / KL coef 太小 algo.kl.use_adaptive;降 lr
熵坍塌(entropy → 0) 策略变 deterministic 升 temperature;clip-higher(DAPO 风格)
response 越训越长(GRPO 常见) 长 response reward 更高 开 token-level loss;加 length 惩罚
训了一会儿模型变蠢 policy 漂离 reference 过远 kl.init_coef;停训重启 lr 减半
clipfrac > 0.5 lr 过高 / clip 过紧 降 lr;clip 放宽到 0.3
grad_norm 爆涨 梯度异常 --algo.adam.grad_clip 1.0

11.5vLLM 相关问题

现象修复
权重同步慢 检查 --vllm.sync_backend nccl 而不是 gloo;NVLink 是否通
rollout 阶段速度抖动 --vllm.enforce_eager,让 CUDA graph 优化
vLLM logits 和训练 logits 偏差大 --algo.advantage.is_correction_enable
sleep mode 报错 vLLM 版本 < 0.9 不支持,升级或去掉 enable_sleep
vLLM init 时报 memory utilization too high colocate 时降 gpu_memory_utilization 到 0.4

11.6多机训练专属问题

现象修复
Ray worker 跨机连不上 head 防火墙开 10001 / 8265 / 6379 端口
跨节点 NCCL 带宽极低(< 10 GB/s) nvidia-smi topo -m;IB 没启用
跨节点 placement_group 永远 PENDING STRICT_PACK 凑不齐;改 PACK 或减少需求
checkpoint 路径在某节点找不到 用 NFS / S3 / 共享存储
SLURM 调度时间不同步 所有节点 NTP 校时

11.7监控指标速查(再贴一次)

指标正常区间异常预警
reward/mean 缓慢上升 飞涨 → 检查 reward 设计
kl_coef 初值附近浮动 飙升 → policy 漂离过快
kl 0.001 – 0.1 > 1 → 策略坏了
actor/entropy 2 – 6 < 1 → 熵坍塌
actor/grad_norm 0.1 – 1 > 10 → 梯度爆炸
actor/clipfrac 0.05 – 0.3 > 0.5 → lr 过高
response_length/mean 稳定或缓升 暴涨 → length hacking
throughput/sps 跌 → 网络 / vLLM 异常

11.8提 issue 的最小清单

  1. OpenRLHF commit + version;
  2. pip list | grep -iE 'torch|vllm|deepspeed|ray|flash|transformers'
  3. 启动脚本(隐去模型路径);
  4. Ray dashboard 截图 + DEAD actor 的 stderr;
  5. NCCL_DEBUG=INFO 的 log;
  6. 能否在 max_samples=8 上复现?
  7. 能否在 docker 镜像里复现?

11.9异步训练(async_enable)的踩坑

2025-05 引入的 --train.async_enable 让 generate 和 train 并行(ch08.10 提过)。新坑:

现象真实原因修复
开了 async 后训练精度反而降 generate 用的是 N step 前的 policy → off-policy 太严重调小 --train.async_queue_size(默认 4,可降到 2)
开 async + colocate_all 启动报错 两个互斥 async 时不要 colocate_all,可保留 colocate_actor_ref
IS ratio 经常 > 2 或 < 0.5 off-policy 偏离过远 --algo.advantage.is_correction_enable --algo.is.mode icepop
vLLM 卡在 generate 不返回 async 模式下 vLLM 任务 queue 满 --train.async_queue_size 或调大 --vllm.num_engines

11.10Partial rollout 模式的 caveat

OpenRLHF 还有个更激进的 --train.partial_rollout_enable:让 vLLM 在中途 pause / resume,跟训练步交错执行。优点:吞吐再提 20-40%;代价:

11.11Dynamic batch 的设置陷阱

--train.dynamic_batch_enable + --train.max_tokens_per_gpu 让 batch 按 token 数算(而不是按样本数)。看起来很美,但有两个常见坑:

避坑
max_tokens_per_gpu 设太大,OOM 在某个长样本 从 8192 起调;ZeRO-3 时翻倍要小心
batch 数不稳定,wandb 上看 step 时间忽长忽短 正常现象;按 token / sec 而不是 step / sec 评估吞吐
grad_accum 算不对 dynamic batch 自动调整 grad_accum_steps 使 token 总数 = global_batch_token_size
跟 packing_samples 重复 两者可以同开,packing 在数据侧,dynamic batch 在调度侧

11.12Ring Attention 长 CoT 启用 checklist

训长 CoT(> 16K context)时几乎一定要开 ring attention。但开错一个 flag 就 hang。来源 openrlhf/models/ring_attn_utils.py:9

11.13心法

三句话

1. 能用 docker 不要自己装——把环境问题排除掉一半;

2. max_samples=8 dry run——任何修改先 dry run 验证;

3. 看 Ray dashboard 找 DEAD actor——RLHF 多进程 hang 几乎都是某个 actor 死了,其他在等。