☰
OpenClaw-RL / slime 实战调试指南:精度对齐检查、训推分离调试与 SGLang IMA 排查
2026/10/13 8:46:46 网站建设 项目流程
  • 人工智能
  • 大模型
  • 强化学习
  • AI Agent
  • 微调

【免费下载链接】OpenClaw-RL

OpenClaw-RL: Train any agent simply by talking

项目地址:https://gitcode.com/gh_mirrors/op/OpenClaw-RL
点击查看免费下载

本文基于 slime 仓库的 Debug 指南 展开。slime 是 OpenClaw-RL 仓库内置的高性能 RL 训练框架(Megatron 训练后端 + SGLang 推理后端),本文聚焦 RL 训练中最棘手的三个问题域:模型精度对齐校验、训练/推理链路分离调试、以及大规模 rollout 中 SGLang illegal memory access 的定位思路。读完本文,你将掌握一套可复现的「训练第一步/第二步精度检查流程」、四个专门用于训推分离的调试参数,以及一套系统的 IMA 排查方法论。

一、为什么要先解决精度对齐问题

在 RL 训练中,rollout 生成质量与训练数值正确性互为前提:如果 rollout 生成的是乱码,后续的 reward、log_probs、advantage 计算全部失去意义;如果训练端 log_probs 与 reference 模型对不上,KL 惩罚与优势估计就会被污染。因此 slime 的调试指南把「精度对齐」放在第一位,并将其拆成两个阶段逐步验证。

二、训练第一步的精度检查

训练第一步是整条 RL 链路的「开机自检」。slime 建议按以下三个层次依次排查。

2.1 rollout 生成是否为「人话」

第一步先看 rollout 生成结果。如果生成内容不是正常语言,优先怀疑四类原因:

  1. 参数没有正常加载:检查日志中是否有 Megatron 成功加载 ckpt 的记录。对应源码路径 slime/slime/backends/megatron_utils/actor.py 中的initialize_model_and_optimizer调用,加载失败或路径错误时会在该环节暴露。
  2. 更新参数有误:确认所有参数都完成了转换与一一对应,特别是参数名是否根据并行配置做了转换。例如当pp_size > 1时,第二个 stage 提供的参数的 layer id 是否正确。一个比较彻底的办法:在对应模型的 SGLang 实现的load_weights中把加载到的所有参数保存下来,与 ckpt 中的参数逐一比对是否一致。从源码结构看,SGLang 侧的参数加载与权重同步逻辑位于 slime/slime/backends/sglang_utils 目录下。
  3. SGLang 特殊 buffer 释放问题:如果所有参数更新都正确仍出现乱码,有可能是 SGLang 中某些特殊 buffer 在 release 时被提前释放。
  4. pretrain 模型本身的差异:如果测试用的是 pretrain 模型,可以换成同结构的 instruct 版本,验证该乱码是否是 pretrain 模型特有的现象(例如 pretrain 模型对 chat template 不敏感导致的异常输出)。

2.2 rollout stats 中 log_probs 与 ref_log_probs 是否完全相等

查看打印的 rollout stats:log_probs与ref_log_probs应在第一步完全相等(即 kl=0),且数值较小。这是「训练端与推理端前向结果一致」的直接证据。

  • 如果不完全相等,一般是 Transformer Engine 中某些 non-deterministic kernel 导致的。典型例子:在某些 TE 版本中,Megatron 需要加--attention-backend flash强制使用 Flash Attention,从而避免 Context Parallelism(CP)下 fused attention 的数值不稳定。slime 的 Megatron 侧已将该参数纳入模型构建配置,相关逻辑见 slime/slime/backends/megatron_utils/model_provider.py 附近的attention_backend处理。
  • 如果数值较大(例如 > 1),则分两种情况:
    • 值非常大:基本是训练配置有问题(如 reward 计算、KL 系数、数据拼接等环节出错);
    • 值只是略大于 SFT loss 的水平(例如 instruct 模型的 logprob 到了 0.8 左右):大概率是数据不符合训练的 chat template,或不符合冷启动的数据分布。

2.3 推一训一场景下 kl 与 grad_norm 检查

在推一训一(num_steps_per_rollout == 1)的配置下进一步验证:kl 是否为 0、grad_norm 是否较小。

如果这里出现问题,基本上可以锁定为 Megatron / Transformer Engine 相关的 bug。文档中给出的典型例子是:MoE 模型需要开启--moe-permute-fusion(对应 Megatron 侧的 MOE permutation fusion 优化开关),否则数值与梯度行为不符合预期。KL 指标的实际计算位置可参考 slime/slime/backends/megatron_utils/loss.py 中kl的生成与传递逻辑,它在不同 advantage estimator(GRPO / PPO / Reinforce++ 等)下被用于构造 rewards 或优势。

三、训练第二步的检查

进入训练第二步后,对于训推一体(colocate)模式,核心检查点是:

  • 能否正确加载第二步(即从第一步训练的模型状态继续 rollout);
  • 是否会出现 OOM(显存溢出)。

这一步主要暴露的是资源规划类问题,可结合 slime 的 placement group 分配逻辑(见 slime/slime/ray/placement_group.py)来核对训练、推理各自的 GPU 预算是否冲突。

四、训练与推理分离调试:四个关键参数

slime 支持将训练部分和推理部分完全拆开分别调试,带来两个直接收益:

  • 调优/debug推理部分时,只用少量卡就能启动任务(不必拉起完整训练栈);
  • 调优/debug训练部分时,可以固定模型输入,彻底去除 rollout 的随机性,让训练问题可复现。

这组参数在 slime/slime/utils/arguments.py 的add_debug_arguments中定义。

4.1--debug-rollout-only:只跑推理,不加载 Megatron

开启后,slime 将不加载 Megatron 训练栈,只初始化 SGLang,用于单独调试推理部分。

源码层面的行为佐证:

  • 在 slime/slime/backends/megatron_utils/actor.py 中,debug_rollout_only时 actor 初始化直接return 0跳过模型/优化器构建;
  • slime/slime/backends/sglang_utils/sglang_engine.py 中将 actor GPU 数量置 0;
  • 训练侧的train/save_model/update_weights等入口在 megatron actor.py 与 [L1416-L1444] 中均被短路(仅记录 rollout 数据后返回)。

同时,开启该参数后 slime 会自动调整资源配置(见 arguments.py):关闭 colocate 与 offload,并强制train_memory_margin_bytes=0(因为不涉及训练显存预留)。

4.2--debug-train-only:只跑训练,不初始化 SGLang

开启后,slime 将不加载 SGLang,只初始化 Megatron,用于单独调试训练部分。

源码行为佐证:

  • 在 slime/slime/ray/rollout.py 中,debug_train_only时all_rollout_engines直接置空,不创建任何 rollout engine;
  • slime/slime/ray/placement_group.py 中只按 actor(及 critic,若启用 PPO)的 GPU 数量创建 placement group;
  • eval 阶段也会被跳过(见 slime/slime/ray/rollout.py)。

4.3--save-debug-rollout-data /your/saved/debug/data_{rollout_id}.pt:保存每次 rollout 结果

开启后,每次 rollout 的结果都会被保存,可与--debug-rollout-only配合使用。注意路径中必须包含{rollout_id}占位符,实际保存方式为args.save_debug_rollout_data.format(rollout_id=rollout_id):

  • 训练数据保存为data_0.pt、data_1.pt…(rollout_id 为数字);
  • eval 数据保存为data_eval_0.pt、data_eval_1.pt…(带eval_前缀),对应实现见 slime/slime/ray/rollout.py 的_save_debug_rollout_data:文件内含rollout_id与samples(由Sample.to_dict()序列化)。

此外,slime 还提供--dump-details参数:一旦设置,会自动把save_debug_rollout_data推导为{dump_details}/rollout_data/{rollout_id}.pt(见 arguments.py),适合整体导出调试数据。

4.4--load-debug-rollout-data /your/saved/debug/data_{rollout_id}.pt:回放固定输入

开启后,会从args.load_debug_rollout_data.format(rollout_id=rollout_id)加载数据,并且不会初始化 SGLang(自动设置debug_train_only=True)。这样训练部分的输入完全固定,可以放心地切换各种并行策略、损失函数或超参进行调优,而无需担心 rollout 随机性的干扰。

对应实现细节:

  • arguments.py 在参数校验阶段检测到load_debug_rollout_data后自动强制debug_train_only=True;
  • slime/slime/ray/rollout.py 的_get_rollout_data中,不再调用生成函数,而是直接torch.load(...)["samples"]并还原为Sample对象;
  • 配套参数--load-debug-rollout-data-subsample <ratio>可以只取前后各一半样本进行快速调试(见 arguments.py 与 rollout.py),适合样本量较大的场景。

⚠️ 互斥约束:debug_rollout_only与debug_train_only不能同时开启,代码中对此有显式断言(见 arguments.py)。

4.5 配套工具:查看已保存的 rollout 数据

仓库还提供了查看 dump 数据的独立脚本 slime/slime/utils/debug_utils/display_debug_rollout_data.py,可直接以模块方式运行:

python -m slime.utils.debug_utils.display_debug_rollout_data \ --load-debug-rollout-data /your/saved/debug/data_{rollout_id}.pt

它会遍历 0~999 的 rollout_id 并按train/eval两类前缀自动发现文件,展示每条样本的prompt、response、reward、status、metadata等白名单字段,并基于保存的样本重新计算性能指标(compute_perf_metrics_from_samples),适合在加载调试数据前先快速确认数据内容是否符合预期。同目录下还有 replay_reward_fn.py 与 send_to_sglang.py 等配套调试工具,分别用于回放 reward 函数与将数据重新发送给 SGLang。

五、Debug SGLang illegal memory access(IMA)

在大规模 RL 训练中,不时会遇到 SGLang 的 illegal memory access(IMA,非法内存访问)问题。这类错误通常伴随 CUDA 报错并导致引擎崩溃,slime 给出了如下四条递进式的排查建议。

5.1 开启CUDA_LAUNCH_BLOCKING=1

CUDA_LAUNCH_BLOCKING=1 bash your_rl_script.sh

该环境变量会让 CUDA kernel 同步执行,报错时能直接定位到触发崩溃的 kernel,而不是在异步执行后丢出一个泛化的 IMA。这是所有 CUDA 类调试的第一步。

5.2 开关投机采样与 CUDA Graph

开启/关闭投机采样(speculative decoding)与CUDA Graph的组合,观察问题是否消除:

  • IMA 经常出现在CUDA Graph replay 的 padding中;
  • 也可能与投机采样与主模型的差异有关(投机 draft 模型与 target 模型行为不一致时,replay 的显存布局可能错位)。

通过两组开关的各种组合(如只开 graph、只开投机、全关),可以快速缩小问题范围。slime 通过--sglang-前缀将 SGLang 的全部参数无缝透传(见 introducing_slime 博客),因此可以灵活控制这些开关。

5.3 关闭 deepep

如果训练或推理中开启了deepep(DeepEP:用于跨节点 MoE all2all 通信优化的库),可以尝试关闭后对比是否有差别:

  • SGLang 侧通过--sglang-moe-a2a-backend deepep、--sglang-deepep-mode auto等参数控制(参考 deepseek-r1 示例);
  • Megatron 侧通过--moe-enable-deepep控制(参考 glm4.5-355B-A32B 示例)。

deepep 涉及自定义的 all2all 与显存复用路径,是 IMA 的高发区之一,关闭它是重要的二分定位手段。

5.4 使用 CUDA Core Dump 定位报错 kernel

如果上述开关无法定位问题,可以尝试CUDA Core Dump方式,在崩溃时抓取 GPU 侧的完整内存快照与 kernel 调用栈,从而精确定位出错 kernel。这一方法最早由 vLLM 团队在公开博客中系统介绍(CUDA Core Dump: An Effective Tool to Debug Memory Access Issues and Beyond),其核心思路是:将 CUDA 崩溃转储为 core dump,再通过分析工具还原出具体是哪一行 kernel、哪个内存地址触发了非法访问,相比反复试开关效率高得多。建议将其作为 IMA 排查链路的最后手段。

六、调试方法论小结

调试目标关键手段对应源码/文档
推理精度训练第一步 rollout「人话」检查、log_probs == ref_log_probs(kl=0)debug.md、loss.py
训练数值num_steps_per_rollout==1下 kl=0、grad_norm 小;开启--moe-permute-fusion、--attention-backend flashmodel_provider.py
推理侧分离--debug-rollout-only+--save-debug-rollout-dataarguments.py
训练侧分离--debug-train-only/--load-debug-rollout-data(自动置位 debug_train_only)rollout.py
数据检查display_debug_rollout_data查看 dump 样本display_debug_rollout_data.py
IMA 定位CUDA_LAUNCH_BLOCKING、开关投机/Graph、关闭 deepep、CUDA Core Dump本指南第五节

最后提醒两点实践前提:

  1. 并行配置影响参数名:当pp_size > 1时,不同 stage 的 layer id 与参数名都会随并行策略变化,精度对齐检查时必须按实际并行配置核对;
  2. 分离调试的定位边界:--debug-rollout-only场景下 slime 会强制关闭 offload 与显存预留相关配置,因此分离调试通过不代表训推一体(colocate)模式也能通过,第二步的「训推一体加载与 OOM 检查」仍需在完整模式下验证。

遵循上述流程,可以在 RL 训练初期快速把「推理侧乱码」「训练侧数值异常」和「大规模推理侧崩溃」三类最常见问题隔离到最小复现单元,再用分离调试参数与源码级检查手段逐个击破。

  • 人工智能
  • 大模型
  • 强化学习
  • AI Agent
  • 微调

【免费下载链接】OpenClaw-RL

OpenClaw-RL: Train any agent simply by talking

项目地址:https://gitcode.com/gh_mirrors/op/OpenClaw-RL
点击查看免费下载

相关推荐

上一篇:iPhone照片打不开?免费的HEIC转JPG工具:5步出图,支持批量
下一篇:NoFences 免费桌面分区完整指南:从零编译到图标归位

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

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

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

立即咨询