[Bug已解决] Inductor 生成内核调用 empty_strided_cpu 负步长报错 Expected result 大于 0 解决方案

发布时间:2026/9/30 13:02:15

[Bug已解决] Inductor 生成内核调用 empty_strided_cpu 负步长报错 Expected result 大于 0 解决方案
[Bug已解决] Inductor 生成内核调用 empty_strided_cpu 负步长报错 Expected result 0 解决方案一、现象长什么样你用torch.compile编译了一个模型运行时却崩在 InductorPyTorch 的后端代码生成器生成的一段内核里报错形如[inductor] generated kernel calls empty_strided_cpu with a negative stride → Expected result 0或者更完整一点RuntimeError: Expected result 0, but got -N ... in empty_strided_cpu ... in inductor generated kernel triton_xxx意思是Inductor 在为一堆张量分配内存时计算出了一个「负的 stride步长」传给empty_strided_cputorch.empty_strided的 CPU 版而empty_strided要求 stride 必须 ≥ 0于是断言Expected result 0失败内核直接崩。 本 issuepytorch/pytorch#188227说的是Inductor 生成的某个 kernel 在推导输出张量的 stride 时算出了负数 stride导致 CPU 上的empty_strided_cpu调用失败。注意它常发生在 CPU 路径或某些 CPU fallback但根因在 Inductor 的 stride 推导逻辑。 本文聚焦empty_strided的 stride 约束、negative stride是怎么被 Inductor 算出来的、怎么绕过与修复。二、背景empty_strided 与 stride 约束torch.empty_strided(size, stride)创建一个按指定stride布局的张量import torch # 正常size(2,3), stride(3,1) 是连续的 t torch.empty_strided((2, 3), (3, 1)) print(t.stride()) # (3, 1)关键点stride的每个元素必须是非负整数 0。负 stride 在物理上意味着「反向遍历」但empty_strided的实现要求非负它假定内存按正步长分配。所以一旦传入负数就触发Expected result 0。 合法的反向视图怎么办用torch.as_strided或flip/ 转置得到而不是empty_strided直接给负 stride# 想要「看起来反向」的视图用 as_strided同样要求非负 stride 才可分配 # 或直接用 .flip()/.t() 得到逻辑上的反向底层 stride 仍非负 a torch.arange(6).reshape(2, 3) b a.t() # 转置stride 变了但非负 print(b.stride()) # (1, 2) —— 仍是合法的 c a.flip(1) # 逻辑反向底层是新的连续张量 print(c.stride()) # (3, 1)所以empty_strided永远不该拿到负 strideInductor 生成代码里出现负 stride是它的 stride 推导 bug。三、为什么 Inductor 会生成负 strideInductor 把 PyTorch 的 FX 图翻译成 Triton / CPU 内核时需要为每个中间张量推导内存布局stride。推导中有一类优化叫「stride 传播 / layout 推断」根据输入 stride 和算子的形状变换推断输出 stride以保留连续/非连续信息、减少copy_。 负 stride 出现的典型场景某个算子的 stride 变换公式在动态形状 / 特殊维度下算错比如把一个stride乘以-1来表示「该维被翻转」但这个中间 stride 又被直接喂给empty_strided_cpu而empty_strided不接受负号。view / reshape 的推导把负维度卷入 stride 计算当存在view把某维 size 变成 1、又叠加转置语义时推导出的组合 stride 可能为负。CPU fallback 路径某些算子在 GPU 没有实现、回退到 CPU 内核CPU 内核用的是empty_strided_cpu于是负 stride 在 CPU 上暴露GPU 端empty_strided可能容忍或行为不同掩盖了 bug。 简言之Inductor 的 layout 推断给empty_strided喂了个它不该接受的负 stride。这是 Inductor 代码生成阶段的逻辑缺陷不是你模型写错。四、最小可运行复现带守卫下面演示「empty_strided负 stride 直接崩」的原语以及「在torch.compile下可能间接触发」的结构。负 stride 原语无需 GPUcompile 触发需环境用守卫包裹。import torch def demo_empty_strided_negative(): # 直接演示负 stride 必然触发 Expected result 0 try: t torch.empty_strided((2, 3), (3, -1)) # 负 stride except RuntimeError as e: print([复现] empty_strided 负 stride 报错:, e) def demo_via_compile(): # torch.compile 下Inductor 可能在某些 shape 变换里生成负 stride if not torch.cuda.is_available(): # CPU 上也能触发 inductor 的 CPU 内核路径 pass def f(x): # 一些会触发 stride 推断的 op 组合示意 y x.transpose(0, 1) z y.contiguous() # 某些布局下 Inductor 推导 stride return z * 2 x torch.randn(4, 8) try: g torch.compile(f, backendinductor) out g(x) print(compile 输出形状:, out.shape) except RuntimeError as e: if empty_strided in str(e) and result 0 in str(e): print([确认] Inductor 生成负 stride 命中本 bug:, e) else: print(其它错误:, e) if __name__ __main__: demo_empty_strided_negative() demo_via_compile()要点demo_empty_strided_negative直接证明「负 stride 必崩」demo_via_compile是 Inductor 触发路径的示意实际触发依赖具体模型结构和版本。五、解决方案一关闭 Inductor 的 layout 优化快速绕过最直接绕过让 Inductor 不做激进的 stride 推断或干脆换一个 backendimport torch # 方案 A强制输出连续避免负 stride 布局传播 torch.compile(options{force_stride_order: False}) def my_model(x): ... # 方案 B关闭 inductor 的「保留布局」优化强制所有中间连续 torch._inductor.config.triton_conv_heuristics False # 视版本 torch._inductor.config.coordinate_descent_tuning False # 方案 C换用非 inductor backend如 eagers 的 aot_eager仅调试 # g torch.compile(f, backendeager)更稳的是直接禁用 inductor 的「freezing」与「layout 优化」相关开关具体名字随版本变化常见import torch._inductor.config as cfg cfg.triton.use_block_ptr False # 某些版本下关闭可绕过如仍崩降级 backend 为 eager / aot_eager验证模型本身逻辑正确只是没编译加速确认只是 inductor stride 推导的问题。六、解决方案二强制 contiguous 切断负 stride 传播如果你知道哪一步触发可在该步后加.contiguous()让 Inductor 不再基于「带负号语义的 stride」去推断下游import torch def safe_block(x): y x.transpose(0, 1) y y.contiguous() # 切断负/特殊 stride回归标准正 stride z y.view(y.size(0), -1) return z * 2原理contiguous()会生成一个新的、stride 全非负的连续张量下游 Inductor 拿到的是「干净」布局不再带上可能为负的中间 stride从而避免喂给empty_strided_cpu负数。七、解决方案三升级 PyTorch 到修复版本本 issue#188227是 Inductor 的已知缺陷官方会随版本修。升级后验证pip install --upgrade torch --index-url https://download.pytorch.org/whl/cu124 python -c import torch; print(torch.__version__)判断修复的标准同样模型torch.compile(backendinductor)不再报empty_strided_cpu ... Expected result 0且可正常产出内核。 临时在 CI 里规避对触发该 bug 的模型先不加torch.compile或加torch._dynamo.config.suppress_errors True让编译失败自动回退 eager仅应急会失去加速import torch._dynamo torch._dynamo.config.suppress_errors True # 编译失败自动退回 eager不崩八、解决方案四缩小触发面动态形状 / 特殊维度负 stride 常在动态形状或含 1 维 / 转置 / view 组合时触发。可临时把dynamicTrue关掉torch.compile(f, dynamicFalse)用静态形状避开推导分支避免把transpose后的张量直接塞进容易触发 stride 推断的算子先.contiguous()用torch.export代替torch.compile看是否绕过export 走另一套布局推导。九、排查清单报错含empty_strided_cpuExpected result 0→ 确认是 Inductor 负 stride bug#188227。先torch._dynamo.config.suppress_errors True应急回退 eager确认模型逻辑本身没错。在触发算子的关键步骤后加.contiguous()切断负 stride 传播。关torch.compile(dynamicTrue)改用静态形状或换backendeager验证。升级 PyTorch 到修复版本CI 里对触发模型暂时禁用 inductor。若想贡献修复定位 Inductorir.py/layout推断里把 stride 变负的位置确保传给empty_strided前stride.clamp_min(0)或改用as_strided的合法路径。十、小结[inductor] generated kernel calls empty_strided_cpu with a negative stride → Expected result 0#188227的本质是Inductor 在代码生成阶段推导中间张量的 stride 布局时算出了负数 stride并直接喂给torch.empty_strided要求 stride ≥ 0触发Expected result 0断言崩溃。它常暴露在 CPU fallback 内核路径根因在 Inductor 的 layout 推断逻辑而非你的模型写错。 应对应急torch._dynamo.config.suppress_errors True让编译失败回退 eager不崩绕过在触发步骤后加.contiguous()切断负 stride 传播关dynamicTrue避开动态形状分支换backendeager根本升级 PyTorch 到修复版本CI 中对触发模型暂时禁用 inductor。 记住empty_strided永远只接受非负 stride任何「看起来反向」的视图都应通过transpose/flip/as_strided的合法路径获得Inductor 不该把负号直接传给它。

相关新闻

人形机器人视觉系统:从感知到具身认知的技术闭环

人形机器人视觉系统:从感知到具身认知的技术闭环

2026/9/28 17:34:16

1. 人形机器人不是“会走路的铁疙瘩”,而是需要视觉中枢的活体系统最近刷到不少短视频:一个金属骨架的人形机器人在展厅里稳步行走、挥手致意,甚至能接住抛来的球。评论区一片惊叹,“中国智造太强了”“科幻照进现实”。但我在实验…

具身智能落地实战:制造业、物流与电力的工业级方案设计

具身智能落地实战:制造业、物流与电力的工业级方案设计

2026/8/26 12:31:21

1. 什么是具身智能?它不是“会动的AI”,而是能真正理解物理世界的行动主体“具身智能 行业应用方案解决方案”这个标题里,最常被误解的其实是“具身”两个字。很多人第一反应是“哦,就是给AI装个机器人身体”,然后联想…

基于pywinauto的微信桌面端自动化工具开发实战

基于pywinauto的微信桌面端自动化工具开发实战

2026/8/28 9:21:17

1. 项目概述:为什么我们需要一个微信桌面端自动化工具?在数字化办公和社群运营成为常态的今天,微信早已超越了即时通讯的范畴,成为了一个集客户服务、社群管理、内容分发、支付交易于一体的超级平台。无论是运营人员需要定时向多个…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/29 22:00:59

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/28 16:01:49

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/29 19:20:49

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/30 8:20:32

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/28 16:01:48

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/28 5:05:21

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/28 16:01:48

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…