关于 debug-model
面向可运行 PyTorch 参考模型的 MAX 移植调试技能,适用于输出不一致的情况。它通过张量转储比较,区分模型、解码状态与服务流水线故障。
主要功能
- 01逐层生成 HF 和 MAX 张量转储
- 02数值比较并定位差异
- 03并行调查工作流
- 04检查强制解码与增量解码
适用场景
- 01排查自定义 MAX 移植的对齐失败
- 02检查量化或多 GPU 移植改动
- 03调查 MAX 升级后的回归
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ modular/ skills --skill debug-model安装后在 Claude Code 中输入/debug-model确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/agent-workflow.mdcomparator-build.mdcomparator-output-patterns.mdstacked-failures.md详细介绍
奇偶一致性/连贯性故障排查协议
模型运行时没有报错,但输出不正确。标量 F.print 插桩会掩盖方向性错误,而且每增加一处插桩都要完整重新编译。请先构建逐层张量转储比较器。之后的每项检查都只需从磁盘读取 numpy 数据。
适用场景: MAX 输出与可运行并可插桩的 PyTorch 参考模型不一致。主要场景是自定义架构移植版虽能提供服务,却无法通过奇偶性或连贯性检查。同一协议也适用于已正常工作的移植版的量化变体、已正常工作的单 GPU 移植版的多 GPU 转换,以及 MAX 升级后的回归问题。只要存在可信的参考模型,均可使用此协议。
不适用场景:
- 服务加载时崩溃 → 修复配置、权重或模块(
import-model) - 模块尚未实现完成 →
import-model第 2 阶段 - 已验证的模型需要调整 logit 比较容差 → 这是阈值校准,本协议不涵盖
参考资料
| 文件 | 阅读时机 |
|---|---|
| comparator-build.md | 构建 HF/MAX 转储器和比较器 |
| comparator-output-patterns.md | 解读比较器输出、误报断崖、token-0 不变量 |
| agent-workflow.md | 调度并行调查 Agent |
| stacked-failures.md | 修复有所帮助,但验证仍未通过 |
如需了解 MAX 内置的运行时调试选项(NaN 检查、源代码回溯、算子日志),请参阅
MAX 调试工具。
max.nn.hooks.PrintHook(在 comparator-build.md 中介绍)会打印层的
输入和输出,便于快速排查。
协议
步骤 0:检查 HF 是否正常
在相同的 HF 仓库、提示词和检查点上运行 model.generate(...)。如果 HF
输出不连贯,请先修复分词器或聊天模板。问题不在 MAX 模型。
pixi run python -c "
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tok = AutoTokenizer.from_pretrained('<repo>')
model = AutoModelForCausalLM.from_pretrained('<repo>', dtype=torch.float32, device_map='auto')
text = tok.apply_chat_template([{'role':'user','content':'Hello!'}], tokenize=False, add_generation_prompt=True)
out = model.generate(**tok(text, return_tensors='pt').to(model.device), max_new_tokens=32, do_sample=False)
print(tok.decode(out[0]))
"
步骤 1:构建比较器
按照 comparator-build.md 操作。你需要三个
产物:HF 转储器、MAX 转储器(forward() 插桩 + 独立运行器)和比较器脚本。请在 MAX 的 forward() 内将转储张量转换为 FP32。
注意:请先验证转储器,再信任其结果。 在一个 MAX 已能正常提供服务的 ModuleV3 模型上运行两个转储器,并在其
forward()中添加插桩。使用olmo3,或通过--prefer-module-v3提供服务的llama3_modulev3。预期每一层的 cos ≈ 0.999,两边的prompt_tokens.npy完全相同,且post_embedcos = 1.0。达不到这些结果 就说明转储器有问题。在将任何内容用于比较移植版之前,请先修复转储器。
步骤 2:读取比较器输出,然后分支处理
按照
comparator-output-patterns.md 操作。在对模型进行二分排查之前,先检查误报断崖(hidden_states 索引错误、解码前缀转储缺少 attention_mask)。
根据首次通过检查的比较器运行结果,选择下一步:
- 某一层存在偏差 → 排查层级。继续步骤 3 至 5。
- 每一层都匹配(cos ≥ 0.99),但生成结果仍有偏差 → 模型的数学计算很可能正确。跳到步骤 6。不要对层进行二分排查。
- 模式符合误报断崖特征 → 修复转储器,重新转储,再次读取。不要使用有问题的比较器来调试模型。
当全局 cos 不明确时,计算逐 token 和逐维度的余弦切片:
cos_per_token = [cos(h[t], m[t]) for t in range(h.shape[0])]
cos_per_dim = [cos(h[:, d], m[:, d]) for d in range(h.shape[1])]
如果 HF 出现尖峰而 MAX 保持平坦,但 max_diff 较高,通常意味着 HF 构建了移植版中没有的注意力锚点。
步骤 3:调度调查 Agent
遵循 agent-workflow.md。一名主 Agent 分析转储并依据张量证据对假设进行排序。辅助 Agent 并行开展工作(权重统计、代码差异、内核检查、子 tap 准备)。主 Agent 完成定位前,不要调度尝试修复的 Agent。
步骤 4:重新编译前进行数值验证
针对每个假设:读取转储张量,计算修复后的结果,并与 HF 比较。匹配 → 重新编译。不匹配 → 尝试下一个假设。
步骤 5:应用修复,重新转储并再次比较
一次编译,一次冒烟测试,通过完整比较器(所有层的 cos > 0.99)。如果验证仍然失败,请参阅 stacked-failures.md。
步骤 6:Serve 与 pipeline
如果解码步骤 K 的 teacher-forced 转储与 HF 匹配,但生成文本仍然不同, 则模型计算很可能正确。先进行二分排查,再重新对层进行二分排查:
| 检查 | 通过 | 失败 → |
|---|---|---|
| Teacher-forced 转储 @ K | cos ≥ 0.99,argmax 匹配 | 步骤 1 到 5(模型错误) |
| 增量 pipeline 解码 @ K | token K 与 HF 匹配 | 解码状态错误(KV、卷积缓存) |
| Serve 与 pipeline @ K | 匹配 | 测试框架错误(分词器、聊天模板、token 恢复) |
如果缺少以下脚本,请创建:pipeline 解码比较、增量层转储、serve 比较脚本。如果 teacher-forced 和 pipeline 都通过,但 serve 失败,请勿修改模型。