关于 debug
用于排查 ML 训练故障的 Skill,按证据收集、受控烟雾测试和明确标注不确定性的流程调查。面向诊断训练任务的 Agent,要求有工具输出支持后再判断原因。
主要功能
- 01五步证据优先流程
- 02检查进程、系统、GPU、磁盘和日志
- 03受控烟雾测试与单变量对照
- 04提供有证据的结论或不确定性报告
适用场景
- 01诊断 NaN、OOM、挂起或训练变慢
- 02调查损失或 GPU 利用率异常
- 03提出修复前检查日志与检查点
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ fcakyon/ phd-skills --skill debug安装后在 Claude Code 中输入/debug确认已加载。
详细介绍
调试:先取证,再行动
在 ML 调试中,代价最高的一类错误是仅凭看似合理的推测就断言原因,然后尝试用“修复”掩盖真正的问题。这项技能要求严格遵循以下顺序:探查 → 假设 → 冒烟测试 → 对照 → 断言。
当助手在没有工具输出佐证的情况下声称找到了原因时,Agentic Stop hook 会从 reason 路由到此处。
何时运行
用户刚刚说了以下任意内容:
- “为什么 X 失败了/发散了/出现 NaN/OOM/卡住了/变慢了/崩溃了”
- “loss 在上升”“指标看起来很奇怪”“GPU 利用率是 0”
- “调试这个”“诊断”“排查故障”“调查这次运行”
- 粘贴日志片段并询问哪里出了问题
五步协议
第 1 步:低成本探查
形成任何假设之前,先收集低成本证据。以下操作都不会耗费超过几秒:
进程状态:
ps aux | grep -E '(python|train|torchrun|accelerate)' | grep -v grep
进程还在运行吗?是僵尸进程还是已终止进程?是否有多个实例?
内核/系统事件:
dmesg | tail -100 # OOM kills, hardware errors, NFS errors
journalctl -xe --since "1 hour ago" | tail -50
GPU 状态:
nvidia-smi
nvidia-smi --query-gpu=utilization.gpu,memory.used,temperature.gpu --format=csv
GPU 到底在使用吗?“训练”期间 GPU 处于空闲状态,说明进程卡在数据加载上,或者已经退出。
磁盘/文件系统:
df -h /path/to/run-dir
du -sh /path/to/run-dir/*
磁盘空间耗尽了吗?检查点没有写入吗?
日志回溯: 读取训练日志最后几百行。不要只相信用户的总结,他们可能只是粗略浏览过。查找:
- 异常回溯
- 重复出现的“loss=NaN”或“grad_norm=Inf”
- 提前停止的提示(运行可能已正常完成)
- _最后_一次成功的 epoch/step(进度停在了哪里)
检查点状态:
ls -la /path/to/run-dir/checkpoints/
最近一次检查点是什么时候写入的?从它的大小能看出什么?空的 .pt 文件与一个写到一半的 2GB 文件情况不同。
第 2 步:提出假设(明确标注为假设)
探查之后,说明_可能_发生了什么,并明确表述为假设:
“假设:此次运行因 OOM 而失败,因为 dmesg 显示 3 分钟前发生了
oom-kill,且进程已消失。尚未排除的其他假设:(a) NFS 写入超时;(b) 被同级进程显式终止。”
绝不要直接跳到“原因是 X”。假设标签明确指出了你尚不确定的内容。
第 3 步:冒烟测试
确认或否定假设,成本最低的方法是在受控条件下复现故障特征:
- OOM 假设:使用
batch_size=1重跑 1 步。如果成功运行,则确认是 OOM;如果以相同方式失败,则说明并非 OOM。 - 数据假设:使用内存中的合成数据集重跑。如果运行正常,则问题可能与数据路径有关。
- 模型假设:仅对单个 batch 执行前向传播,并使用
eval()模式。Loss 是有限值吗?输出正常吗? - 优化器假设:使用
lr=0重跑。如果 loss 仍然爆炸,说明损失函数本身有问题(而不是优化器)。 - 分布式假设:在 1 张 GPU 上重跑。如果运行正常,则问题可能与 DDP/NCCL 有关。
30 秒的冒烟测试胜过 30 分钟的重启祈祷。
第 4 步:对照
如果冒烟测试的结果不明确,就运行对照测试:只更改失败配置中的一个变量,然后重跑冒烟测试。差异有助于缩小可能的原因机制。
常见的对照维度(每次只更改一个):
- 单源数据与多源数据
- 默认 workers 与调整后的 workers
- 开启与关闭混合精度
- 开启与关闭梯度检查点
- 开启与关闭 torch.compile
第 5 步:断言原因
只有在证据经过探查、冒烟测试和对照逐步累积之后,才能断言原因。断言应引用能够证明原因的具体工具输出:
“根因:NFS 写入超时。证据:dmesg 显示 14:23 出现
nfs server X not responding(与最后一次写入检查点的时间是同一分钟),且使用batch=1进行的冒烟测试重现了超时。建议的修复方法:为检查点绑定挂载本地临时目录,并在 epoch 结束时 rsync 到 NFS。”
如果证据没有逐步累积,就不要将假设升级为原因。应说明“我目前还不知道”,并提出下一步探查。
应避免的做法
- “可能是 X,我试试 Y” → 不要这样做。先探查。
- 通过做出小改动来重新运行,以此诊断问题。先进行冒烟测试,再有意重新运行。
- 只引用用户的描述作为证据:重新阅读实际日志。
- 当产物与之矛盾时,仍停留在第一个看似合理的原因上。
输出
一份简洁的诊断报告,包含:(1) 探查结果;(2) 假设;(3) 冒烟测试结果;(4) 原因或尚不确定的结论;(5) 建议的后续操作。每项判断都要引用支持它的工具输出。