关于 pt2-bug-basher
面向 PyTorch 开发者的调试技能,覆盖 Dynamo、Inductor、AOTAutograd 和 FX 图中的编译故障。它按环境检查、最小化复现、测试、诊断和验证的步骤引导排查。
主要功能
- 01检查 conda 环境和 PyTorch 导入
- 02复现并精简故障案例
- 03代码调查前添加回归测试
- 04分类错误并收集编译产物
- 05指导根因分析与测试验证
适用场景
- 01排查 torch.compile 图中断
- 02将 Inductor 故障缩减为最小案例
- 03诊断编译模型的数值不匹配
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pytorch/ pytorch --skill pt2-bug-basher安装后在 Claude Code 中输入/pt2-bug-basher确认已加载。
详细介绍
PT2 Bug Basher
调试 PyTorch 2 编译器栈(Dynamo、Inductor、AOTAutograd、FX 图)中的测试失败和运行时错误。
工作流摘要
- 检查环境 -- 询问用户要使用哪个 conda 环境。检查
$CONDA_DEFAULT_ENV,确认该环境已激活。然后运行python -c "import torch; print(torch.__version__)",确认可以导入 torch,并报告其版本。如果环境未激活或无法导入 torch,请停止操作,并让用户先激活正确的环境。 - 复现 -- 稳定地复现故障
- 缩减 -- 将复现用例缩减为尽可能小的独立案例。移除无关的模型逻辑,使用最小张量形状,并隔离触发 Bug 的具体算子或模式。
- 添加单元测试 -- 在深入搜索代码或调查根因之前,先完成此步骤。 在代码库中添加一个能捕获该 Bug 的失败测试。将其放在具体且符合主题的测试文件中(例如,
test/dynamo/test_repros.py、test/inductor/test_torchinductor.py、test/export/test_export.py)。避免使用test/dynamo/test_misc.py——该文件已经过于庞大;请找到与 Bug 所属领域匹配的、更具体的测试文件。使用torch.testing._internal.common_utils.TestCase和run_tests。修复前测试必须失败,修复后必须通过。先写测试能让你始终保持目标明确——在开始探索代码库之前,你就能清楚地知道“修复完成”是什么样子。 - 在 main 上验证 -- 使用
EnterWorktree创建一个检出到main的工作树。将新测试文件复制到该工作树中,并在那里运行测试,确认它在 main 上失败。如果测试在 main 上通过,请停止——测试可能没有捕获到正确的 Bug,或者 Bug 可能已经修复。使用ExitWorktree(action: remove)退出工作树,并返回工作分支后再继续。 - 收集日志 -- 使用合适的
TORCH_LOGS设置运行 - 分类 -- 使用 错误分类 表确定类别
- 检查产物 -- 通过
TORCH_COMPILE_DEBUG=1检查 FX 图、IR 和生成的代码 - 找出根因 -- 从错误出发,沿编译流水线追溯
- 修复 -- 应用修复
- 验证 -- 运行新增的单元测试以及附近相关的现有测试(例如,如果你更改了
is_exporting的行为,也要运行现有的test_is_exportingexport 测试)。使用pytest -k按名称快速运行相关测试。所有测试通过后,任务才算完成。 - 自我审查 -- 在提交更改前,使用
/pr-review技能审查自己的修改。修复它指出的所有问题。 - 庆祝 -- 总结更改:解释根因、修改了什么以及原因,并说明新增和验证了哪些测试。然后告诉用户 Bug 已解决。添加一句有趣、多样的鼓励语或彩蛋(例如双关语、引言,或 Bug 被拍扁的 ASCII 艺术图)。简短一些,每次都换个说法。
调查策略
优先使用直接工具,而非 meta_codesearch
直接使用 Grep、Glob 和 Read 探索代码。不要启动 meta_codesearch Agent——它们速度慢且成本高。下面的架构知识和关键源文件部分应能提供足够背景,帮助你确定查找方向。针对函数名执行定向 Grep 总是更快。
确认当前所处的编译模式
在阅读实现代码之前,先确定编译模式。这些模式会共用代码,但在重要方面有所不同:
torch.compile——Dynamo + Inductor。tx.export=False,不会激活_compiling_state_context()。torch.export(严格模式)——tx.export=True,_compiling_state_context()处于激活状态。torch.export(非严格模式,默认)——通过fullgraph_capture使用 Dynamo,但tx.export可能与严格模式不同。_compiling_state_context()处于激活状态。检查torch._export.config.use_new_tracer_experimental——它会改变所使用的代码路径。
区分跟踪时与运行时
许多 PT2 错误都源于混淆这两者:
- 跟踪时:在 Dynamo 的符号解释器内部。Dynamo 会拦截函数调用,并可能将其常量折叠(例如,
is_exporting()→ConstantVariable(True))。 - 运行时:真实张量、真实 Python 调用,以及
torch.compiler._is_exporting_flag这类模块级标志。
调试时,直接在源文件中临时添加 print() 语句,而不是从外部进行猴子补丁——分发链会使猴子补丁不可靠。
收集信息
根据错误类别选择合适的诊断工具:
- 快速概览:
TORCH_LOGS="+dynamo,graph_breaks,recompiles" python your_script.py - 完整调试产物:
TORCH_COMPILE_DEBUG=1 python your_script.py——会创建包含 FX 图、Inductor IR 和生成代码的torch_compile_debug/ - 仅生成代码:
TORCH_LOGS="output_code" python your_script.py - 结构化跟踪:先运行
TORCH_TRACE=/path/to/trace python your_script.py,然后运行tlparse /path/to/trace - 单线程运行(用于 pdb):
TORCHINDUCTOR_COMPILE_THREADS=1 python your_script.py
错误分类
根据错误消息和回溯对故障进行分类:
| 错误模式 | 类别 | 跳转到 |
|---|---|---|
日志中出现 Unsupported: ... 或 graph break | 图中断 | 图中断 |
BackendCompilerFailed | Inductor/后端崩溃 | 后端编译器故障 |
RecompileError 或 cache_size_limit | 重新编译 | 重新编译问题 |
| 精度不匹配 / 数值输出错误 | 精度 | 精度问题 |
InternalTorchDynamoError | Dynamo 错误 | 内部错误 |
| 段错误或 CUDA IMA | 运行时崩溃 | 运行时崩溃 |
| Triton 断言 / 索引越界 | Triton 内核错误 | Triton 故障 |
按类别调试
图中断
图中断会将编译后的图拆分为更小的子图,常常导致性能下降或行为异常。
诊断:
TORCH_LOGS="graph_breaks" python your_script.py
关键文件:
torch/_dynamo/exc.py——Unsupported异常类torch/_dynamo/variables/——大多数图中断决策发生的位置
常见原因:
- 不受支持的 Python 结构(依赖数据的控制流、不受支持的内置函数)
- 无法跟踪的张量操作(对输入执行原地操作、不受支持的数据类型)
- 调用无法跟踪的函数
修复方法:
- 阅读图中断消息,找出不受支持的操作
- 检查是否存在分解实现或受支持的替代方案
- 如果该操作确实无法跟踪,可考虑使用
torch._dynamo.allow_in_graph或重构用户代码
后端编译器故障
BackendCompilerFailed 表示 Inductor(或其他后端)在编译期间崩溃。
诊断:
TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=2 python your_script.py
这会生成 minifier_launcher.py,用于隔离出最小的故障图。
关键文件:
torch/_dynamo/repro/after_aot.py-- 用于 AOT 后故障的复现/缩减器torch/_inductor/-- 后端本身
修复方法:
- 运行缩减器,获得最小复现
- 检查 FX 图(
TORCH_COMPILE_DEBUG=1),了解涉及哪些算子 - 检查问题是否出在降级(
torch/_inductor/lowering.py)、调度或代码生成 - 如果错误出在代码生成阶段,查看生成的输出代码
重新编译问题
当守卫条件过于具体,导致缓存未命中时,就会发生过度重新编译。
诊断:
TORCH_LOGS="recompiles,recompiles_verbose,guards" python your_script.py
关键配置:
torch._dynamo.config.recompile_limit(默认值:8)torch._dynamo.config.fail_on_recompile_limit_hit-- 设为True可在达到限制时触发硬错误
常见原因:
- 更改张量形状,却未将其标记为动态
- 多次调用之间发生变化的 Python 标量值
- 调用之间的全局状态发生变化
修复方法:
- 从日志中读取重新编译的原因
- 找出未通过的守卫
- 使用
torch._dynamo.mark_dynamic()将相关维度标记为动态,或修复导致守卫不稳定的根源
精度问题
编译后的模型与急切模式产生的数值结果不同。
诊断:
TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=4 python your_script.py
这会使用 fp64 参考结果比较编译模式与急切模式,并在精度检查失败时转储复现文件。
关键工具:
torch/_dynamo/debug_utils.py--same_two_models()、backend_accuracy_fails()、cast_to_fp64()torch._dynamo.config.repro_tolerance(默认值:1e-3)
修复方法:
- 从缩减器获取最小故障图
- 以 fp64 精度比较急切模式与编译模式的输出
- 对算子进行二分查找,找出结果开始偏离的算子
- 检查已知的数值问题(归约顺序、融合内核、数据类型提升)
Dynamo 内部错误
InternalTorchDynamoError 表示 Dynamo 本身存在错误。
诊断:
TORCHDYNAMO_VERBOSE=1 python your_script.py
# or equivalently:
TORCH_LOGS="+dynamo" python your_script.py
关键文件:
torch/_dynamo/symbolic_convert.py-- 字节码解释器torch/_dynamo/variables/-- 变量跟踪系统torch/_dynamo/guards.py-- 守卫生成
修复方法:
- 使用
TORCHDYNAMO_VERBOSE=1获取完整堆栈跟踪 - 找出导致崩溃的字节码指令或变量类型
- 创建最小复现(错误消息通常会包含缩减器路径)
- 如有需要,使用
TORCHINDUCTOR_COMPILE_THREADS=1和 pdb 进行调试
运行时崩溃
执行编译后的代码时发生段错误和 CUDA 非法内存访问错误。
诊断(使崩溃变得可复现):
PYTORCH_NO_CUDA_MEMORY_CACHING=1 CUDA_LAUNCH_BLOCKING=1 python your_script.py
对于 CUDA IMA,添加 NaN 检查:
TORCHINDUCTOR_NAN_ASSERTS=1 python your_script.py
对于 Inductor 级别的同步调试:
torch._inductor.config.triton.debug_sync_kernel = True # sync after every kernel
torch._inductor.config.triton.debug_sync_graph = True # sync before/after graph
修复方法:
- 使用
PYTORCH_NO_CUDA_MEMORY_CACHING=1 CUDA_LAUNCH_BLOCKING=1使崩溃变得可复现 - 检查是否存在输入不匹配(形状、设备、数据类型)
- 使用
TORCH_LOGS="output_code"检查生成的内核代码 - 使用
TORCHINDUCTOR_NAN_ASSERTS=1找出第一个产生错误值的内核 - 检查动态形状问题(历史上这是 IMA 的常见来源)
Triton 内核故障
Triton 断言失败,或生成的内核中出现索引越界。
诊断:
TORCH_LOGS="output_code,schedule" python your_script.py
关键文件:
torch/_inductor/codegen/triton.py-- Triton 代码生成torch/_inductor/scheduler.py-- 内核融合决策
修复方法:
- 从
output_code日志中获取生成的 Triton 内核 - 检查索引计算是否存在差一错误或错误的步长计算
- 查看 IR(
TORCH_COMPILE_DEBUG=1),追溯到对应的 FX 算子 - 检查融合决策是否产生了无效的索引组合
关键源文件
| 文件 | 用途 |
|---|---|
torch/_dynamo/exc.py | 异常层级结构与错误格式化 |
torch/_dynamo/debug_utils.py | 缩减器支持、准确性检查、输入序列化 |
torch/_dynamo/repro/after_dynamo.py | 用于 Dynamo 阶段故障的复现/缩减器 |
torch/_dynamo/repro/after_aot.py | 用于 AOTAutograd 后故障的复现/缩减器 |
torch/_dynamo/repro/aoti.py | 用于 AOTI 故障的复现/缩减器 |
torch/_dynamo/config.py | Dynamo 配置(复现级别、重新编译限制) |
torch/_dynamo/variables/torch.py | Torch 函数处理、跟踪状态函数 |
torch/_dynamo/variables/higher_order_ops.py | HOP 跟踪(cond、map 等) |
torch/_dynamo/symbolic_convert.py | 字节码解释器、InstructionTranslator |
torch/_dynamo/convert_frame.py | 帧编译、fullgraph_capture 入口 |
torch/_dynamo/functional_export.py | 新的导出跟踪器(_dynamo_graph_capture_for_export) |
torch/_dynamo/eval_frame.py | torch._dynamo.export、optimize_assert |
torch/_export/_trace.py | 导出流水线(_export、_strict_export、_non_strict_export、_export_to_aten_ir) |
torch/_export/utils.py | _compiling_state_context() |
torch/compiler/__init__.py | is_compiling()、is_exporting()、运行时标志 |
torch/_higher_order_ops/cond.py | torch.cond 实现与代理跟踪 |
torch/_higher_order_ops/utils.py | 用于 HOP 分支跟踪的 reenter_make_fx |
torch/_inductor/config.py | Inductor 配置(调试标志、跟踪设置) |
torch/_inductor/debug.py | DebugContext、图可视化、IR 日志记录 |
torch/_logging/_registrations.py | 所有已注册的日志别名和产物 |
使用缩减器
缩减器会将失败的图缩减为最小复现:
# Step 1: Generate the minifier launcher
TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=2 python your_script.py
# Step 2: Run the minifier
python minifier_launcher.py minify
# Step 3: Run the minimized repro
python minifier_launcher.py run
对于准确性问题,请使用级别 4:
TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=4 python your_script.py