AREX Feed Article
PyTorch 发布 v2.15.0:重写的 NCCL 后端成为默认,Apple Silicon 获 FP8 与 MoE 解码快路径
北京时间 10 月 29 日凌晨 1 时 09 分,PyTorch 官方在 GitHub 发布 v2.15.0, 页面的 published_at 时间戳为 2026-10-28T17:09:49Z,经 核实。这个版本同时动了训练基础设施的三块底座:重写后的 NCCL 后端从 2.14 时的可选 nccl2 转正,接管所有 nccl 进程组;torch.distributed 新增实验性的单侧传输(one-sided transfers)API,第一个后端是 NIXL,传输可被 CUDA graph 捕获;Apple Silicon 的 MPS 后端补上 float8_e4m3fn 与 _scaled_mm,并给 grouped_mm 加了面向 MoE(混合专家)模型解码的快路径,官方称 MoE 解码吞吐提升 1.32~1.34 倍 tokens/s。
给出 2.15 的规模:自 2.14 以来 3,117 个 commit、583 位贡献者。同一批变更还包含几处升级时会直接遇到的不兼容点:import torch 在同一进程内只能初始化一次,Python 3.10 的 wheel 停发,MPS 后端要求 macOS 15 及以上,用 2.15 保存的分布式 checkpoint 无法被 2.14 读取。
每个 nccl 进程组都换上新实现,hang 时 flight recorder 自动落盘
模型跨多块 GPU 训练时,GPU 之间要靠通信后端不断交换数据;发布博客指出,在 NVIDIA 硬件上这个后端就是 NCCL(NVIDIA 集合通信库)。PyTorch 2.14 已把从 torchcomms 移植的重写版 NCCL 后端以 nccl2 名义预览,2.15 里它成为 backend="nccl"——也是 init_process_group() 默认 CUDA 后端——的实际实现()。不想切换的作业有两个回滚开关:创建进程组前在每个 rank 上设 TORCH_DIST_USE_NCCL2=0,或直接写 backend="nccl-legacy";release notes 同时写明,这两个回滚路径将在下一个版本移除,官方建议迁移到 nccl 或 nccl-lazy。
新后端的行为差异在 release notes 里逐条列出。communicator 在 init_process_group()/new_group() 时急切创建,没用到的组也会占 GPU 显存;每个进程组绑定一块 CUDA 设备——优先取创建时传入的 device_id,否则按 LOCAL_RANK % torch.cuda.device_count() 推断——torch.cuda.set_device() 不再被读取,张量放在另一块 GPU 上会报 Expected tensor on cuda:X but found tensor on cuda:Y 一类错误。一个进程管理多块 GPU 的用法目前仍需要 nccl-legacy。读后端对象的代码也要改:dist.get_backend_impl() 返回新后端类,isinstance(..., ProcessGroupNCCL) 会是 False,comm_split_count() 这类旧方法不复存在。官方给的两个出口:需要并发点对点通信重叠的场景用 nccl-lazy,每对 send/recv peer 拿到自己的 communicator 和 stream;不想在 new_group 时就预占约 200 MiB 显存的,用新增的 ProcessGroupNCCL.Options.lazy_init,让 communicator 推迟到首次使用时才创建。
博客把生产环境的可调试性列为这套机制的目标:集群规模下,一块 GPU 卡住就能停掉整场训练,定位原因过去往往要手工复现故障。2.15 的 flight recorder 与后端无关,集合通信 hang 住时会把 post-mortem 写到磁盘;watchdog 健康状态发布到 debug server,任何一个 rank 超时,都会触发所有 rank 的 flight recorder 落盘。新 NCCL 后端、MPI、UCC 这些此前没有内建支持的后端现在也记录 flight recorder,新后端健康检查失败时同样 dump。配套还有实验性的纯 Python watchdog torch.distributed._watchdog(),检测 Python 分布式后端里挂起的 CPU 与 GPU 操作,超时后 dump 线程栈。新后端的重配置支持 shrink/grow 快路径——需要 NCCL 2.29 或更新,让幸存的 rank 跳过完整 bootstrap;ROCm 侧对应 RCCL 2.30.7。
单侧传输进入 torch.distributed,transports 经 store 直连对端
torch.distributed 这一版新增了实验性模块 torch.distributed._transport(),用于单侧数据搬运,NIXL 是第一个后端。与集合通信路径不同,transports 通过 store 连接对端,不需要先建进程组,也不依赖集合通信操作;Transport.read_stream/write_stream 把传输排进 CUDA stream,因此整段传输可以被 torch.cuda.graph 捕获。release notes 把这组 API 标注为 API Unstable,接口尚未承诺稳定。
FSDP2 与流水线并行:精度、图捕获与通信时机下放到参数粒度
FSDP2(全分片数据并行,入口是 fully_shard)把几处此前只能整体开关的控制拆到了参数级别。新增的 MixedPrecisionPolicy(param_dtype_override_fn=...) 允许精度敏感的参数——博客点名 MoE router gates 和 norm weights——单独留在 fp32,其余部分照常 bf16 训练,且每个 fully_shard 组仍只有一次 all-gather。完整的梯度累积步现在可以捕获进单个 CUDA graph。
一处默认行为变更需要显式处理:reduce_dtype=None 时,梯度不再默认按 param_dtype 累积和归约,而是跟随参数的 grad_dtype()。常见的 fp32 参数加 param_dtype=bf16 组合下,梯度累积和 reduce-scatter 从 bf16 变为 fp32,reduce-scatter 字节量翻倍;官方给的应对办法是显式设置 reduce_dtype。想让梯度归约与后续计算重叠的,可以调用 finalize_backward(async_op=True),它返回一个 GradientReductionHandle。
流水线并行的改动集中在内存占用和通信时机:接收缓冲区改为在每次接收前才分配,而不是预先为所有 microbatch 备好;forward 输出在发送完成后即释放;调度接受 max_outstanding_sends 预算,FSDP 的 unshard 错峰排进各 rank 的启动 bubble,而不是在 step 开始时一并发出。按 schedule 确定的每条有向 rank-to-rank 边现在各拿一个专用 P2P communicator;对应配置项从 pipeline_per_direction_p2p 改名为 pipeline_per_edge_p2p,旧名无别名,写入直接抛 AttributeError。
Apple Silicon:FP8 进 MPS,解码改走 gemv 快路径
MPS 后端这版的两条主线是低精度和解码。torch.float8_e4m3fn 在 MPS 上可用,_scaled_mm 支持 tensorwise 与 rowwise scaling,并为 decode 尺寸的形状提供 gemv(矩阵-向量乘)快路径。新实现的原生 grouped_mm 面向 MoE 模型,其 gemv 路径就是官方 1.32~1.34 倍 tokens/s 提升的来源,测试机型为 M3 Ultra;这一数字为项目自报,本文未做独立验证。
其余内核数字同样出自官方 release notes 与博客:对 128,256 词条做单行 softmax 快 8 倍;upsample backward 最高快 21.7 倍;归约统一到同一组内核后,norm 全归约快 100 倍以上;F.linear 改走 gemv 后几何均值提速 1.23 倍,小规模投影最高 5 倍;512×512 矩阵的 QR 分解从约 7 秒降到 1.5 毫秒,三角求解改为分块实现。这些改动的共同背景是更多 MPS 算子从 MPSGraph 迁到原生 Metal 内核。
并发控制补齐了 CUDA 后端已有的形态:torch.mps.Stream、current_stream()、default_stream()、set_stream() 与 torch.mps.stream() 上下文管理器公开,另有 Tensor.record_stream。门槛同步抬高:MPS 现在要求 macOS 15 及以上(),macOS 14 已过支持期、相关 workaround 被移除,在这类系统上 torch.backends.mps.is_available() 返回 False。
Blackwell 解码每层少一次 kernel launch,三家硬件平台同时扩容
NVIDIA 侧的解码优化集中在 NVGEMM——2.14 加入的 CuTeDSL GEMM(通用矩阵乘)后端。它现在把 ModelOpt NVFP4 线性层的标量反量化因子折叠进 GEMM 本身,解码时每层省去一次独立的 pointwise kernel launch;一个有界、形状感知的候选策略补上 nvMatmulHeuristics 漏掉的 Blackwell NVFP4 解码形状;kernel 之间可用 programmatic dependent launch,让 Triton 消费者与上一个 GEMM 的尾部重叠。release highlights 对效果的措辞是「通过更少、重叠更好的 kernel launch 让 Blackwell 上 4-bit NVFP4 LLM 解码更快」,未给出具体倍数。
平台矩阵的变化大多在发布工程层面。默认 PyPI wheel 从 CUDA 13.0 挪到 CUDA 13.2(13.2.2 toolkit),旁边提供 CUDA 13.4 GA wheel,后者实验性支持 NVIDIA Rubin GPU;cu126 与 cu130 不再构建。CUDA 13 wheel 要求 NVIDIA 驱动 580 以上、Turing(sm_75)及更新的 GPU,Maxwell、Pascal、Volta 用户需要留在 2.14。AMD 侧,Inductor 在 gfx950 上支持 FlyDSL 模板自动调优,覆盖 GEMM、ragged grouped_mm 与 MXFP4/MXFP8 scaled_mm(FlyDSL 可选,需 0.3.x);gfx1250(MI450)获得 Tensor Data Mover 支持,博客称其为对下一代 Instinct 的预览支持,并已进入 wheel 架构列表;ROCm 10.0 wheel 与 7.14 并存,全部 ROCm wheel 改用 AMD 的 TheRock 包构建,ROCm 改为以 pip 依赖安装;ROCm 7.2 wheel 与 gfx900/gfx906 内核(MI25、MI50/MI60、Radeon VII)被移除。Intel GPU 方向,SYCL 内核改用 free-function 写法,大部分现有内核已迁移;XPU profiler 获得 kernel 级 graph replay 可见性、XCCL collectives 的跨 rank 关联与多 GPU 硬件计数器;torch.xpu.Event 支持跨进程共享。
Python 支持扩到 3.11~3.15(含自由线程 free-threaded 的 3.14t 和 3.15t),Python 3.10 wheel 停发(),pip 在 3.10 上找不到 2.15 wheel。torch.compile 在 Python 3.15 上恢复可用——2.14 会直接抛 RuntimeError: torch.compile is not supported on Python 3.15+,这个版本把检查挪到 3.16+;3.15/3.15t wheel 基于 ABI 冻结后的 CPython 3.15.0rc2 构建。
升级前要过的坎:import torch 每个进程只能初始化一次
Python 前端的变更直接改了报错行为():importlib.reload(torch)、del sys.modules["torch"] 后重新 import、乃至 import torch 失败后的重试,现在都会抛 ImportError,错误信息写明 torch can only be initialized once per process。官方解释,重新执行模块体在 2.14 里本来就不安全——当时的报错(如 Only a single TORCH_LIBRARY can be used to register the namespace triton)或段错误具有误导性;正常使用不受影响,成功的 import 会留在 sys.modules 里短路。
分布式 checkpoint 有一处数据层面的不兼容变更:元数据现在记录张量 strides(),2.15 保存的 checkpoint 无法被 2.14 及更早版本加载,会报 CheckpointException: too many values to unpack (expected 5),且没有写回旧格式的开关;反向不受影响,2.15 能读旧 checkpoint。嵌套张量(nested tensors)被移出 weights_only=True 的默认白名单,加载含嵌套张量的 checkpoint 需用 torch.serialization.safe_globals 显式放行。其余不兼容还包括:有序效应算子在 selective activation checkpointing 下默认保存而非重算输出,可能增加激活显存;torch.ops.* 与自定义算子的 C++ 异常与警告改走 PyTorch 原生翻译,用户自定义的 pybind 异常翻译失效,TORCH_WARN 在 -W error 下会变成异常;C++ 栈符号化默认从 addr2line 改为 dladdr。
PyTorch 团队同时把这次发布的答疑安排在 2026 年 11 月 5 日上午 11 时(太平洋时间)的,主讲为 Meta 的 Tristan Rice、Natalia Gimelshein、Huy Do 与 Jane Xu,主持是 Gottbrath Tech 的 Chris Gottbrath。对依赖旧 NCCL 行为的作业来说——一个进程管理多块 GPU 的用法目前仍要求 nccl-legacy——迁移窗口就是这一个版本。