用途
Experiment Debugger 用于修复阻碍实验产生有效结果的工程故障。它的核心定位是把「bug」与「科学问题」分开:如果代码本身是坏的、错误的或不可复现的,应先修复代码,再去解读实验结果。
适用场景
根据资料,该技能适用于以下情况:
- 训练崩溃,或产生 NaN loss、NaN 梯度、inf 值
- GPU OOM 错误阻塞训练,或意外导致批量大小被迫减小
- 训练速度显著慢于预期
- 数据加载成为瓶颈,或产生损坏的批次
- 指标数值不可能、不稳定,或多次运行之间不一致
- 在固定随机种子后仍无法复现某次运行
- 配置文件或检查点在两次运行之间被悄悄改动
- TensorBoard、WandB 或日志输出缺失或错位
同时资料明确指出不适用的情况:不用于解读「出乎意料但有效」的结果(应使用 result-diagnosis);不用于选择基线或设计实验(应使用 baseline-selection-audit 和 experiment-design-planner)。
协作关系
资料建议将该技能与以下技能配合使用:
- result-diagnosis:工程问题已修复、结果有效但仍令人意外时使用
- run-experiment:bug 解决后重新提交修正后的任务
- run-status-monitor:探查日志产物,确认修复是否生效
- data-pipeline-manager:当 bug 可追溯到数据加载、预处理或划分问题时使用
- research-project-memory:记录影响实验有效性判断的调试决策
技能目录结构
<installed-skill-dir>/
├── SKILL.md
└── references/
└── failure-taxonomy.md
渐进式加载
- 始终阅读 references/failure-taxonomy.md
- 在向用户询问信息之前,先阅读任务日志、训练日志和配置文件
- 当 bug 可能复发或影响其他运行时,阅读 memory/risk-board.md
核心原则
资料列出的原则包括:
- 不要在不理解原因的情况下,通过修改配置或模型来「压掉」bug
- 修复前,先在尽可能小的设置下复现 bug
- 区分数值不稳定、代码 bug、硬件问题和数据 bug
- 与随机种子相关的不可复现,几乎总是数据顺序、框架或环境问题,而不是随机事件
- 指标 bug 常常是静默的:一个能无报错计算的指标,仍可能是错的
- 工程修复不应改变实验原本要检验的内容
工作步骤
第 1 步 — 收集运行上下文
读取训练日志(logs/、wandb/、runs/、output/ 或 docs/ops/runs/<run-id>-status.md)、配置文件(configs/、experiments/、jobs/<run-id>.yaml 等)、错误信息或回溯(复制精确错误)、硬件上下文(GPU 类型、CUDA 版本、框架版本)以及被运行代码的 git commit。记录:失败模式(crash、NaN、OOM、slow、metric、repro 或 silent error)、失败发生在训练的哪个阶段(第 0 步、训练早期、训练中期、评估)、失败是确定性的还是间歇性的。
第 2 步 — 对失败模式分类
阅读 references/failure-taxonomy.md,选择一个主要模式:
- nan-gradient:loss 或梯度中出现 NaN 或 inf
- oom:GPU 显存溢出
- slow-training:训练吞吐低于预期
- slow-data:数据加载是瓶颈
- metric-error:指标值不可能、为负、准确率大于 1、形状错误或可疑地取整
- repro-failure:固定种子后结果仍不同
- crash:进程以非零码退出、SIGKILL 或超时且无输出
- silent-error:运行完成但结果明显错误或缺失
若多个模式同时成立,按优先级列出。
第 3 步 — NaN / 梯度调试
当模式为 nan-gradient 时:检查 NaN 出现在第 0 步还是很多步之后(第 0 步 NaN 几乎总是数据或初始化 bug;晚期 NaN 通常意味着不稳定);检查损失函数中的 log(0)、除零或负数开方;检查学习率是否过大导致梯度爆炸;检查混合精度错误(FP16 下溢/溢出常见,可用 torch.autocast 配 dtype=torch.float32 隔离);添加梯度范数日志(torch.nn.utils.clip_grad_norm_ 配 max_norm=1.0 可稳定并暴露问题层);检查极小批量下的批归一化(批量大小 1 可能产生 NaN 的 BN 统计量);运行 torch.autograd.set_detect_anomaly(True) 定位具体算子;记录最先产生 NaN 的层或操作。
第 4 步 — GPU OOM 调试
当模式为 oom 时:从错误信息识别 GPU 总显存与峰值分配显存;判断 OOM 发生在模型初始化、前向、反向还是评估阶段;尝试将批量大小减半,若解决则计算每样本显存;检查内存泄漏(张量跨步保留在 Python 列表中、loss 变量中保留了计算图);检查是否意外翻倍分配(梯度检查点被关闭、未使用 flash attention 的全序列注意力);在 OOM 那一步用 torch.cuda.memory_summary() 做剖析;检查任务是否通过 SLURM --mem-per-gpu 或 RunAI 资源规格申请了正确的 GPU 显存。
第 5 步 — 训练慢 / 数据慢调试
当模式为 slow-training 或 slow-data 时:从日志获取基线吞吐(样本/秒或 token/秒);用 nvidia-smi 或 run-status-monitor 检查 GPU 利用率(若低于 80%,说明训练受数据饥饿或 CPU 限制);检查数据加载 worker 数量(num_workers=0 或过小是常见瓶颈);检查数据集位于网络文件系统还是本地 NVMe(网络 I/O 可能占主导);检查预处理是每批在线进行还是离线缓存;检查每个 epoch 是否从磁盘重读而非放内存或 RAM 盘缓存;用 torch.profiler 剖析若干步找出主要开销。
第 6 步 — 指标错误调试
当模式为 metric-error 时:检查指标归约方式(按样本平均还是按批次平均,批量大小不等会破坏批次均值指标);检查类别标签编码(0 起始还是 1 起始,one-hot 还是整数);检查评估是否使用与训练相同的预处理(分词器、归一化、数据增强);检查 padding token 是否被计入 loss 或指标;检查指标是在整个评估集上一次计算还是从 mini-batch 累积;用期望值完全已知的微小合成样例验证指标;对序列指标(BLEU、ROUGE、F1)检查分词与归一化规则。
第 7 步 — 可复现性调试
当模式为 repro-failure 时:检查种子覆盖(torch.manual_seed、numpy.random.seed、random.seed 和 torch.cuda.manual_seed_all);检查非确定的 CUDA 算子(torch.backends.cudnn.deterministic = True 与 torch.backends.cudnn.benchmark = False);检查多 worker 数据加载(shuffle + 多 worker + 无 worker_init_fn 是顺序非确定性的常见来源);检查浮点累加顺序(多 GPU 归约在无显式设置时不保证跨运行确定);检查环境是否一致(CUDA 版本、cuDNN 版本、PyTorch 版本、Python 版本);检查是否从非预期的步数加载了检查点;若无法实现确定性,则记录预期方差并报告多种子下的均值 ± 标准差。
第 8 步 — 写下发现与修复
定位根因后:在 docs/ops/runs/<run-id>-debug.md 中记录 bug、根因与修复;用修复更新配置或代码,不要依赖临时命令行覆盖;运行冒烟测试确认修复(短运行、小数据);若该 bug 暴露了对其他运行的复发性风险,更新 memory/risk-board.md;交给 run-experiment 重新提交修正后的任务。
最终检查
在宣布 bug 已修复之前:冒烟测试通过且不再出现该失败模式;修复已提交到代码或配置,而不只是 shell 覆盖;修复不改变实验原本要检验的内容;记忆写回覆盖任何新风险或数据/环境发现。
限制
资料未提供该技能的具体安装命令、许可方式、价格、平台限制或性能数据,这些信息暂未提供。