已开启
【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误/NaN(dynamic=True可规避):单stage恒正确,疑似融合kernel调优失败后回退路径未写预分配buffer #4831
GMOW创建于  27 天前
GMOW
GMOW
27 天前 创建

标题:【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误/NaN(dynamic=True可规避):单stage恒正确,疑似融合kernel调优失败后回退路径未写预分配buffer

建议标签:bug / 正确性 / inductor / mlir

环境信息

项 值
硬件 Atlas 800T A2(Ascend 910B3,64GB HBM)
CANN 9.1.0
PyTorch 2.7.1 与 2.9.0(两条配套版本线均复现,见版本对照)
torch_npu 2.7.1.post8 与 2.9.0.post6(均属 TorchNPU 26.1.0 配套)
torchvision 0.22.1(配 2.7.1)/ 0.24.0(配 2.9.0)
triton / triton_ascend 3.5.0 / 3.2.2
torch-mlir 0.0.1(repo.oepkgs.net 官方 wheel,aarch64/Python311)
Python 3.11.15
OS Ubuntu 24.04 aarch64

问题描述

按官方文档《Inductor》中 MLIR 模式的开启方式(options={"npu_backend": "mlir"}),
对 TorchBench 清单模型 resnet18(torchvision 官方实现)整图编译推理,
编译产物输出错误:或为错误值(与 Eager 差异 0.98),或直接为 NaN。
逐算子、单 stage 编译则完全正确。

复现步骤

import torch
import torch_npu
import torch_npu._inductor
import torchvision

model = torchvision.models.resnet18().npu().eval()   # TorchBench 清单模型
x = torch.randn(8, 3, 224, 224, device="npu")

with torch.no_grad():
    eager_out = model(x)

compiled = torch.compile(model, options={"npu_backend": "mlir"})   # 默认 dynamic=False
with torch.no_grad():
    mlir_out = compiled(x)

print((mlir_out - eager_out).abs().max())   # 2.7.1.post8: ~0.98;2.9.0.post6: nan

实测结果(torch_npu 2.7.1.post8,交付环境)

eager 两次运行 max diff: 0.000e+00        # 环境自检通过,排除卡/环境异常
eager vs compiled:       9.814e-01        # FAIL(任务书口径 atol=1e-3)
稳态加速比:              1.34x            # 性能有收益,但结果不可用

torch_npu 2.9.0.post6 下同一脚本输出 NaN(表现形式随版本不同,见版本对照)。

定位过程(系统二分,脚本与结论见配套材料 MLIR问题定位/)

不变式:单算子(conv/linear/bn/relu/pool)、Conv+BN+ReLU、残差块、
完整 BasicBlock、stem/layer1~4 各自单独编译——全部恒正确;
错误仅出现在多个 stage 编译为同一张图时。

触发组合随「版本 × 数据」变化(同一脚本不同条件下首个出错的组合不同):

条件 出错的组合 正常的组合
2.9.0 + 权重组A stem+layer1+layer2+layer3 layer1+2+3+4(不含 stem)
2.9.0 + 权重组B(torchvision) layer3+layer4;stem+layer1..4 stem+layer1+layer2+layer3
2.7.1 + 权重组B 完整 resnet18 stem+layer1+layer2+layer3

根因分析(证据链)

  1. MLIR 融合 pass 将 BN+ReLU / BN+add+ReLU 打包为单一融合 kernel
    (output_code.py 中为 mlir_fused__native_batch_norm_legit_no_training_add_relu_2
    等,全部经 async_compile.mlir_auto_fallback(...) 包装,调用约定为
    kernel.run(输入..., bufN, stream=...)——要求写入预分配 buffer)
  2. 编译期日志:Tuning accuracy failed, no valid kernels found, using fallback
    (失败名单 100% 为 BN 融合家族)。调优按实际数据校验精度,是否失败与
    运行数据相关
    ——解释了触发组合随权重/输入变化的现象
  3. mlir_auto_fallback 源码显示调优失败后回退 _load_fx_graph(FX 图执行),
    但回退路径不遵守"写入预分配 buffer"的调用约定
  4. 后续算子读到未初始化/残留设备内存 → 数值错误。NaN(读未触碰内存)与
    错值(读残留数据)两种表现均实测到
    ;错误幅度跨进程不稳定
    (0.28~2.0 / NaN),均与该机制吻合

版本对照(同一脚本、同一图结构)

环境 整图 resnet18 结果
torch 2.7.1 + torch_npu 2.7.1.post8(环境预装配套版本) FAIL,max_diff = 9.814e-01
torch 2.9.0 + torch_npu 2.9.0.post6 FAIL,两次运行分别实测 NaN 与 1.008e+00

两条配套版本线均复现;且同一版本不同运行的错误表现也会变化
(NaN=读未触碰内存,错值=读残留数据),与"读到何种无效内存"的机制推断一致。
证据日志:原始日志/08_Inductor-MLIR.log(2.7.1)与
原始日志/torch2.9.0_补充环境/08_Inductor-MLIR_torchvision.log(2.9.0)。

规避方案(已验证,可作为临时措施)

A/B 对比实验(同一模型、同一输入、同一进程内先后编译运行;代码见配套材料
MLIR问题定位/mlir_dynamic_AB_test.py,输出日志 mlir_dynamic_AB_test_output.log):

import torch
import torch_npu
import torch_npu._inductor
import torchvision

model = torchvision.models.resnet18().npu().eval()
x = torch.randn(8, 3, 224, 224, device="npu")

# MLIR 默认(dynamic=False)→ FAIL
out_a = torch.compile(torchvision.models.resnet18().npu().eval(),
                      options={"npu_backend": "mlir"}, dynamic=False)(x)

# MLIR + dynamic=True(规避方案)→ PASS
out_b = torch.compile(torchvision.models.resnet18().npu().eval(),
                      options={"npu_backend": "mlir"}, dynamic=True)(x)

实测输出(body=stem+layer1+layer2+layer3,eager 基线 absmax=10.0006):

配置                             eager基线 absmax     max_diff  判定
------------------------------------------------------------------------
eager(基线,两次自检)                        10.0006     0.000000  PASS
MLIR dynamic=False(默认)                 10.0006     1.000986  FAIL(数值错误)
MLIR dynamic=True(规避)                  10.0006     0.000000  PASS

dynamic=True 完全修复(两次独立实验均如此);dynamic=False(默认)错误依旧。
另:TORCHINDUCTOR_LAYOUT_OPTIMIZATION=0 不能规避,反而触发输出 NaN 的
另一条错误路径。使用 MLIR 模式的用户当前应显式开启动态 shape 追踪并做输出校验。

期望

  1. 修复 MLIR 融合 kernel 调优失败后回退路径的 buffer 写入约定
    (mlir_auto_fallback → _load_fx_graph 不写 bufN)
  2. Kernel compiled failed! / Tuning accuracy failed 静默回退建议至少打印
    告警级别日志,便于用户感知
  3. 文档补充:MLIR 模式建议配合 dynamic=True 使用,并做输出正确性校验

证明材料

交付示例 08 运行截图(2.7.1 环境,FAIL 与性能对比):

Inductor-MLIR后端:正确性FAIL与性能对比

A/B 规避方案对比实验截图(dynamic=True 修复验证):

MLIR dynamic A/B 对比

完整材料:任务2-torch.compile体验与实践/Inductor-MLIR/(脚本+截图)、
补充-测试报告与原始日志/MLIR问题定位/(8 个定位脚本+结论+AB日志)、
补充-测试报告与原始日志/原始日志/08_Inductor-MLIR.log

likedislike
TorchNPU-BotTorchNPU-Bot成员
27 天前 添加了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
27 天前 评论:

issue待分派,添加triage-review标签

likedislike
GMOWGMOW
27 天前 修改标题为 “【26.1.0众测】Inductor-MLIR整图编译resnet18输出数值错误(与Eager差异0.28~2.0,dynamic=True可规避),已二分定位到临界编译组合”,原标题为“【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误(与Eager差异0.28~2.0,dynamic=True可规避),已二分定位到临界编译组合”
GMOWGMOW
27 天前 修改了issue 的描述
TorchNPU-BotTorchNPU-Bot成员
26 天前 添加了label:bot-triaged;删除了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
26 天前 评论:

检测到当前 issue 已关联 PR,自动添加标签:bot-triaged

likedislike
GMOWGMOW
20 天前 修改标题为 “【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误(与Eager差异0.28~2.0,dynamic=True可规避),已二分定位到临界编译组合”,原标题为“【26.1.0众测】Inductor-MLIR整图编译resnet18输出数值错误(与Eager差异0.28~2.0,dynamic=True可规避),已二分定位到临界编译组合”
GMOWGMOW
20 天前 修改了issue 的描述
TorchNPU-BotTorchNPU-Bot成员
20 天前 添加了label:help-wanted
TorchNPU-Bot
TorchNPU-Bot成员
20 天前 评论:

检测到社区任务相关 issue,自动添加标签:help-wanted

likedislike
GMOWGMOW
20 天前 修改了issue 的描述
GMOWGMOW
19 天前 修改了issue 的描述
GMOWGMOW
19 天前 修改了issue 的描述
GMOW
GMOW
17 天前 评论:

查重补充说明(2026-09-25):

本 issue 与以下同主题 issue 相关(同一底层 bug 的不同模型/表现):

  • #4793(ResNet50,max diff 3.8e+02,更早报告)
  • #4836(torchvision ResNet18,同期)
  • #5063(resnet18 输出 NaN)、#5116(resnet18 allclose=False,后续)

本 issue 在上述报告基础上补充了根因定位与规避方案(如有重复敬请合并,以下信息供汇总参考):

  1. 二分定位:单算子/单 stage 恒正确,错误仅在多 stage 整图编译时出现;触发组合随「版本×数据」变化
  2. 根因链:BN 融合 kernel Tuning accuracy failed → 静默回退 _load_fx_graph → 回退路径不写预分配 buffer → 后续算子读未初始化/残留内存(错值与 NaN 两种表现)
  3. 规避方案:dynamic=True 完全修复(A/B 实验验证,或可帮助上述各位在修复前使用 MLIR 后端)
  4. 双版本验证:2.7.1.post8 与 2.9.0.post6 均复现(错值 / NaN)
likedislike
GMOWGMOW
17 天前 修改标题为 “【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误/NaN(dynamic=True可规避):单stage恒正确,疑似融合kernel调优失败后回退路径未写预分配buffer”,原标题为“【26.2.0众测】Inductor-MLIR整图编译resnet18输出数值错误(与Eager差异0.28~2.0,dynamic=True可规避),已二分定位到临界编译组合”
GMOWGMOW
17 天前 修改了issue 的描述