news 2026/7/17 12:57:31

[Bug已解决] slice_scatter 在 CUDA 上重新原地-reinplace-失效 DISABLED test 绕过方案解决方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Bug已解决] slice_scatter 在 CUDA 上重新原地-reinplace-失效 DISABLED test 绕过方案解决方案

[Bug已解决] slice_scatter 在 CUDA 上重新原地(reinplace)失效(DISABLED test)绕过方案解决方案

一、现象长什么样

你用了 PyTorch 的torch.slice_scatter(把一段切片写回原张量的指定位置),并且场景涉及reinplace(重新原地化 / functionalization 下的 in-place 重放)——常见于torch.compile的 functional 化路径、或torch.func/ functorch 的变换里。结果遇到一个被官方DISABLED的测试:

DISABLED test_slice_scatter_reinplace_cuda (__main__.GPUTests)

即 pytorch/pytorch#145189。含义:slice_scatter在 CUDA 上,当走「reinplace(把 functional 视图重放成真正的 in-place 写回)」路径时,行为不正确 / 崩溃,测试被禁用。 对你来说,实际表现可能是:torch.compile后的模型里用到slice_scatter(或tensor[i:j] = x这种切片区赋值被编译成 slice_scatter),在 CUDA 上结果错或崩,而 CPU 上正常。 本文聚焦:slice_scatter 是什么、reinplace 是什么、为什么 CUDA 上这组合会坏、怎么绕过(用 clone 替代 in-place、关 functionalization 的 reinplace 等)

二、背景:slice_scatter 与 reinplace

torch.slice_scatter(input, src, dim, start, end):返回一个新张量,是在inputdim维度[start:end]位置放入src。它是input[..., start:end, ...] = src这种「切片区赋值」的函数式版本(不修改 input,返回新张量)。

import torch x = torch.zeros(4, 4) src = torch.ones(2, 4) out = torch.slice_scatter(x, src, dim=0, start=1, end=3) # out[1:3] == 1,其余为 0

reinplace(重新原地化):PyTorch 2.x 的functionalization(函数式化)机制把「in-place 操作」先记录成「functional 视图」,等需要时再「reinplace(重放成真正的原地写回)」。这在torch.compile/torch.func里很常见——编译器为了能 safely 做变换,先把 in-place 变 functional,最后再决定要不要真的 in-place。 问题:slice_scatter的 reinplace 路径在 CUDA 上有缺陷——functional 记录与真正重放时的设备/步长/别名处理不一致,导致重放写错位置或崩溃。

三、为什么 CUDA 上 slice_scatter reinplace 会坏

functionalization 的 reinplace 要处理「源张量 src 与目标切片是同一内存(别名)」的情况。在 CUDA 上:

  1. 步长/偏移计算在 reinplace 时错位slice_scatter的 reinplace 需要按dim/start/end把 src 拷回 input 的对应位置。CUDA 内核在算目标偏移时,若 input 是非连续或 src 与 input 别名,偏移算错 → 写错位置 / 越界。
  2. CUDA 异步 + 别名检测失效:functionalization 靠「别名分析」判断 src 是否和 input 共享存储;CUDA 上某些视图的别名信息在 reinplace 重放时没正确传递,导致「该原地写却新建」或「该新建却原地覆盖」→ 结果错。
  3. 与编译优化的交互torch.compile可能把slice_scatter融合进其它算子,reinplace 边界被打乱,CUDA 内核拿到错误的源/目标指针。 本质:slice_scatter的 reinplace(functional→in-place 重放)在 CUDA 下的别名/偏移处理有 bug,CPU 路径没事,CUDA 路径出错

四、最小可运行复现(带守卫)

下面演示slice_scatter的正常用法(CPU 稳),以及「被 compile 函数式化后 CUDA 可能出问题」的示意:

import torch def demo_slice_scatter_cpu(): x = torch.zeros(4, 4) src = torch.ones(2, 4) out = torch.slice_scatter(x, src, dim=0, start=1, end=3) print("slice_scatter 结果:\n", out) # out[1:3] 应为 1 def demo_with_compile(): if not torch.cuda.is_available(): print("[skip] 无 GPU,仅说明 compile + slice_scatter") return def f(x, src): return torch.slice_scatter(x, src, dim=0, start=1, end=3) x = torch.zeros(4, 4, device="cuda") src = torch.ones(2, 4, device="cuda") try: g = torch.compile(f) out = g(x, src) print("compile slice_scatter 形状:", out.shape) except Exception as e: if "slice_scatter" in str(e).lower() or "reinplace" in str(e).lower(): print("[确认] 命中 slice_scatter reinplace CUDA 问题 (#145189):", e) else: print("其它错误:", e) if __name__ == "__main__": demo_slice_scatter_cpu() demo_with_compile()

要点:CPU 上 slice_scatter 稳定;bug 在「CUDA + functionalization reinplace」组合。下面给绕过。

五、解决方案一:避免 in-place 语义,用 clone 替代

最根本的绕过:不要用「切片区原地赋值」的语义,改用「先 clone 再 functional 写」避免 reinplace:

import torch def safe_slice_write(x, src, dim=0, start=1, end=3): # 先 clone,再 slice_scatter(返回新张量),绝不原地改 x out = torch.slice_scatter(x.clone(), src, dim=dim, start=start, end=end) return out # 用法:需要原地语义时,手动赋值回原变量 x = torch.zeros(4, 4, device="cuda" if torch.cuda.is_available() else "cpu") src = torch.ones(2, 4, device=x.device) x = safe_slice_write(x, src) # 用返回值覆盖,而非原地

原理:绕开 functionalization 的 reinplace(它只在「真 in-place 记录」时触发),用slice_scatter纯 functional 返回值,不触发 reinplace 路径。

六、解决方案二:关掉 torch.compile 的 reinplace / functionalization 相关优化

若 bug 在 compile 路径,可关掉触发 reinplace 的优化:

import torch # 用 fullgraph=False 容错,或关 in-place 重放相关 compiled = torch.compile(f, fullgraph=False) # 更细:某些版本可用选项关闭 functionalization 的 reinplace # torch._functorch.config.* 视版本;常见做法是避免在该算子前后做 in-place

另一个思路:把用到slice_scatter的函数从编译图里摘出来,用torch.compiler.disable包住:

import torch @torch.compiler.disable def slice_op(x, src): return torch.slice_scatter(x, src, dim=0, start=1, end=3) def model(x, src): y = other_compute(x) y = slice_op(y, src) # 这一段不进编译图,避开 reinplace 缺陷 return y

七、解决方案三:用等价的 index_put / 索引赋值替代

slice_scatter可用index_put_/ 高级索引替代,避开该算子的 reinplace 路径:

import torch def slice_scatter_via_index(x, src, dim=0, start=1, end=3): out = x.clone() # 用切片索引赋值(等价语义) if dim == 0: out[start:end] = src elif dim == 1: out[:, start:end] = src return out x = torch.zeros(4, 4) src = torch.ones(2, 4) out = slice_scatter_via_index(x, src) print(out[1:3]) # 全 1

out[start:end] = src这种 Python 切片赋值在 functionalization 下走的是不同的(更成熟的)reinplace 路径,不一定触发 slice_scatter 那个缺陷。

八、解决方案四:升级并关注该测试启用

#145189 是内部测试被禁用,官方会修(CUDA 下 slice_scatter 的 reinplace 别名/偏移处理)。升级:

pip install --upgrade torch --index-url https://download.pytorch.org/whl/cu124

判断修复:该 DISABLED 测试被启用且通过,即代表 CUDA 下 slice_scatter reinplace 修好。修复前,用「clone 替代 in-place / disable 编译段 / 等价 index 赋值」绕过。

九、排查清单

  1. slice_scatter在 CUDA 上结果错/崩且涉及 compile / torch.func → 确认 #145189(CUDA reinplace 缺陷)。
  2. CPU 正常、CUDA 异常 → 基本可定位到 CUDA reinplace 路径。
  3. 绕开:用x.clone()+slice_scatter返回值(纯 functional,不触发 reinplace);
  4. @torch.compiler.disable把该算子移出编译图;
  5. 等价替代:用out[start:end] = src切片赋值或index_put
  6. 升级:关注该 DISABLED 测试启用即代表修复。

十、小结

DISABLED test_slice_scatter_reinplace_cuda(#145189)的本质是:torch.slice_scatter(切片区写回)在 CUDA 上,当走 functionalization 的「reinplace(functional 视图重放成真正 in-place 写回)」路径时,别名/偏移处理有 bug——src 与 input 别名、或非连续布局下,重放写错位置或崩溃。CPU 路径没事,CUDA 路径出错。 应对:

  • 纯 functional 绕过:先x.clone()slice_scatter取返回值,绝不原地改,不触发 reinplace;
  • 移出编译图@torch.compiler.disable包住该算子,避开 compile 的 reinplace 缺陷;
  • 等价替代:用out[start:end] = src切片赋值或index_put,走更成熟的 reinplace 路径;
  • 等升级:关注该 DISABLED 测试启用即代表修复。 记住:slice_scatter 的 reinplace 在 CUDA 下有别名/偏移 bug。想要原地语义,就先 clone 拿返回值再覆盖原变量——既安全又等价

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 12:57:07

终极Windows Defender禁用指南:5步彻底释放系统性能

终极Windows Defender禁用指南:5步彻底释放系统性能 【免费下载链接】defender-control An open-source windows defender manager. Now you can disable windows defender permanently. 项目地址: https://gitcode.com/gh_mirrors/de/defender-control Win…

作者头像 李华
网站建设 2026/7/17 12:56:36

CPM4OSSP-SERVER分发管理详解:如何实现自动化软件包分发部署

CPM4OSSP-SERVER分发管理详解:如何实现自动化软件包分发部署 【免费下载链接】CPM4OSSP-SERVER The server of centralized management platform for operating system software package 项目地址: https://gitcode.com/openeuler/CPM4OSSP-SERVER 前往项目官…

作者头像 李华
网站建设 2026/7/17 12:56:06

如何在Windows上实现窗口置顶:PinWin终极免费指南

如何在Windows上实现窗口置顶:PinWin终极免费指南 【免费下载链接】PinWin Pin any window to be always on top of the screen 项目地址: https://gitcode.com/gh_mirrors/pin/PinWin 你是否经常在Windows电脑上工作时,发现重要的参考文档总被其…

作者头像 李华
网站建设 2026/7/17 12:54:50

基于Java语言的招聘系统/类Boss直聘系统/招聘小程序的设计与实现

一、招聘系统市场背景分析企业用工需求的增长:随着经济的复苏和企业的发展壮大,各行业企业的用工需求不断增加。无论是新兴的科技行业,还是传统的制造业、服务业,都需要招聘大量的人才来支持业务拓展,为招聘系统创造了…

作者头像 李华
网站建设 2026/7/17 12:54:02

Navicat无限重置试用期:3种简单方法永久破解Mac版试用限制

Navicat无限重置试用期:3种简单方法永久破解Mac版试用限制 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 还在为…

作者头像 李华