已关闭
[Bug]: [triton_experimental] int64 boundary downcast collapses non-dense layouts, AllenaiLongformerBase accuracy failure #4701
AACAES创建于 9月8日关闭于 21 天前
9月8日 添加了label:triage-review
TorchNPU-Bot
9月8日 评论:
9月8日 评论:
issue待分派,添加triage-review标签


9月8日 添加了label:bot-triaged;删除了label:triage-review
TorchNPU-Bot
9月8日 评论:
9月8日 评论:
检测到当前 issue 已关联 PR,自动添加标签:bot-triaged


huyuchao
9月9日 评论:
9月9日 评论:
根因已确认并修复:Tensor.to() 对非 dense 布局静默塌缩为 contiguous,而 kernel load 公式按编译期记录的旧 stride 编译——与本 issue 的分析一致。
修复 PR:#46074(_layout_preserving_downcast,接入 _memoized_downcast 全部输入参数 cast 点)
- 视图 + contiguous root(含本 issue 的重叠
as_strided视图、gapped slice、broadcast 视图):cast root 后as_strided重建视图,stride 完整保留; - 非视图 broadcast(
copy.deepcopy后的 meshgrid buffer:_base被切断但 stride 保留(0,1)/(1,0)):按 varying axis 提取 1-D 再 cast——dense 物化对(1,0)会把flat[row]读成 row-0 常量。
验证(aarch64 NPU,triton-ascend 3.2.2):
| 用例 | 修复后 | 反事实(打回裸 .to()) |
|---|---|---|
本 issue 复现(重叠 as_strided i64) |
mismatches=0 | mismatches=2260992(与本 issue 报告的 bad=2260992 逐位一致) |
meshgrid deepcopy stride (1,0)(Super_SloMo 94.69 路径) |
0 | 5088 |
端到端:Super_SloMo accuracy 94.693779 FAIL → PASS(2.44e-05)。
注:本 PR 覆盖 kernel 输入参数侧的全部布局类;issue 尾注提到的输出侧 empty_like/回写多余物化属性能问题,留作后续跟进。


21 天前 添加了label:resolved
在提交新问题之前,请确保您已经在社区中搜索过相关问题,并使用了社区中提供的资源/工具后,仍未找到满意的解决方式。
⚠️ 安全信息提醒:请仔细检查提供的文本内容,确保其不包含敏感数据信息,包括但不限于:
在分享配置信息或代码示例时,请将敏感信息脱敏处理,或使用
<TOKEN>等占位符替代原有内容。环境信息
huggingface.py --accuracy --cold-start-latency --train --float32 --backend inductor --npu-backend triton🐛 问题描述
问题现象
AllenaiLongformerBase 训练 accuracy check 失败(指标 33.22,远超容差)。逐步定位排除 Longformer 数学逻辑、BMM、optimizer 后,确认错误源头在 backward
index_put的索引张量 producer:最小复现(NPU,triton_experimental 后端):
错误索引经 scatter 放大到
value.weight.grad max_abs=0.0043,12 层累计放大后表现为最终精度失败。根因分析
NPU 向量核不支持 int64/float64,triton_experimental 在 kernel 参数边界做降档(boundary downcast):codegen 把
*i64签名改写为*i32,launcher 侧运行时Tensor.to(torch.int32)转换数据。问题出在
Tensor.to()对非 non-overlapping-and-dense 布局会静默塌缩为 contiguous:as_strided视图是重叠视图(stride(98304,16384,64,1)下相邻元素重叠,view numel 2359296 > storage 1179648),非 dense;.to(torch.int32)无法零拷贝,按逻辑值重新填充 → 结果天然是 contiguous 布局(stride 从(98304,16384,64,1)变为(196608,49152,64,1));x0 + 16384*x1 + 98304*x2),套在 materialize 后的缓冲上寻址含义完全改变 → 读错位置。eager 模拟逐位复现实测数字(bad=2260992),确认机制。同类风险覆盖所有非 dense 布局(重叠视图、gapped slice、broadcast/expand)的 i64/fp64 kernel 参数;输出侧
empty_like与回写tmp.to(src_dt)也存在同根因的布局塌缩/多余物化。期望行为
boundary downcast 的转换缓冲必须保持参数的原始 stride(成为编译期寻址公式的合法替身),而非静默塌缩为 contiguous。
复现步骤
import torch, torch_npu def fn(a): return a.as_strided((12, 4, 768, 64), (98304, 16384, 64, 1)).contiguous().view(-1) x = torch.arange(1179648, dtype=torch.int64, device="npu") out = torch.compile(fn, options={"npu_backend": "triton_experimental"})(x) ref = x.as_strided((12, 4, 768, 64), (98304, 16384, 64, 1)).contiguous().view(-1) print((out != ref).sum().item()) # 期望 0,实际 2260992 欢迎加入社区,感谢您对社区的贡献 🎉!