Introduction
PyTorch 2.14.0 was released on September 2, 2026. The official release notes lead with the shiny features, but this post prioritizes the changes that silently alter numbers or make previously working code raise. Same policy as my JAX release-notes series: every behavior below was verified by actually running both 2.13.0 and 2.14.0 (CPU wheels, Python 3.12, macOS arm64).
Breaking changes
1. Boundary subgradients of clamp / min / max changed — results change silently
This is the change to check first. The gradient of clamp at a scalar boundary, when the input sits exactly on the boundary, changed from 1 to 0.
import torch
x = torch.tensor([1.0], requires_grad=True)
torch.clamp(x, max=1.0).sum().backward()
print(x.grad)
# PyTorch 2.13: tensor([1.])
# PyTorch 2.14: tensor([0.])
No exception is raised. Only the gradient values change. If your model uses clamp for activation or loss clipping, elements sitting exactly on the boundary stop receiving gradient, which can subtly shift training curves. Per the release notes, this aligns boundary subgradients with the dispatcher schema's input space; for ties against tensor bounds, gradient is now split evenly (I confirmed torch.maximum at a tie was already 0.5/0.5 — that case is unchanged).
If you keep golden-value gradient tests, they will fail loudly and correctly on upgrade. If you don't, you will not notice this change.
2. bfloat16 × complex promotion moves to bcomplex32 — working code now raises
Mixed bfloat16/complex operations used to promote to complex64. They now promote to the new torch.bcomplex32 shell dtype (real and imaginary parts stored as bfloat16) — and its operator coverage is limited:
t = torch.tensor([1.0], dtype=torch.bfloat16)
r = t + 1j
# PyTorch 2.13: computes in torch.complex64
# PyTorch 2.14: NotImplementedError: "add_stub" not implemented for 'BComplex32'
Code that ran fine through 2.13 crashes. If your bfloat16 model touches complex numbers (hand-rolled RoPE, FFT preprocessing), add an explicit t.to(torch.complex64) cast. Note that tensor-tensor mixing (bfloat16 + a complex64 tensor) still promotes to complex64 as before — what changed is promotion through Python complex scalars and result_type.
3. torch.cholesky / torch.qr finally removed
Both had been deprecated since 1.9 (2021) and now raise RuntimeError. Migration is mechanical:
| Old | New |
|---|---|
torch.cholesky(A) |
torch.linalg.cholesky(A) |
torch.cholesky(A, upper=True) |
torch.linalg.cholesky(A).mH |
torch.qr(A) |
torch.linalg.qr(A, mode='reduced') |
torch.qr(A, some=False) |
torch.linalg.qr(A, mode='complete') |
The error messages spell out the replacements, so this won't slow anyone down — but note the timeline (deprecated in 1.9, removed in 2.14). It matters for the TorchScript section below.
4. Other breaking changes (brief)
-
use_cudaargument removed fromtorch.profiler.profile(useactivities; confirmed gone viainspect.signature) -
Custom ProcessGroup
new_group()implementations must accept abackendkeyword argument (otherwiseTypeError) -
torch.distributed.split_group()now returnsGroupMember.NON_GROUP_MEMBERinstead ofNonefor non-member ranks -
setup.pyis now a shim :build/bdist_wheel/sdistprint their replacement commands instead of executing (use pip orpython -m build) - Dynamo's TVM backend now requires
tvm.relax.frontend.torch(relay-era options removed)
Deprecations — TorchScript's visible warnings are the biggest signal
torch.jit.script / trace / save / load now emit user-visible FutureWarnings instead of the usually hidden DeprecationWarning. Measured:
FutureWarning: `torch.jit.script` is deprecated. Please switch to
`torch.compile` or `torch.export`.
Given that cholesky/qr just completed the "deprecated in 1.9 → removed in 2.14" arc, read this as the start of TorchScript's removal countdown. If production inference depends on TorchScript artifacts (.pt files from torch.jit.save), this is the release to start planning the torch.export migration.
Also deprecated: activation checkpointing's behavior of ignoring saved_tensors_hooks (pass respect_saved_tensors_hooks explicitly), and torch.distributed.config.compile_on_one_rank → torch.compiler.config.compile_on_one_rank.
Feature highlights
- NVGEMM : CuTeDSL-generated CUTLASS kernels land in Inductor, autotuned alongside Triton and ATen (epilogue fusion, NVFP4 GEMM)
-
Multi-way control flow : a
switchgeneralization oftorch.condships as a prototype — but it lives attorch._higher_order_ops.switch;torch.switchdoes not exist yet (confirmed on 2.14.0).torch.while_loopcan now be captured in CUDA graphs -
@dynamic_specdecorator : one declarative dynamic-shape spec shared acrosstorch.compile,torch.export, andmake_fx -
Distributed overhaul : the new
nccl2backend ported from torchcomms (nonblocking communicators, eager splitting), and fault tolerance as a first-classc10dconcept with in-place process-group reconfiguration plus a Flight Recorder -
Apple Silicon native linear algebra : SVD (Jacobi kernel),
eigh, QR, and Cholesky go native on MPS -
torch.linalg.polar()/torch.linalg.matrix_sqrthadded (polar decomposition and principal square roots of SPD matrices; confirmed both exist in 2.14.0) -
Python 3.15 and 3.15t (free-threaded, no-GIL) wheels — but
torch.compileremains unsupported on 3.15 , so no-GIL experiments are eager-mode-only for now
Environment notes
CUDA 13.x (13.0–13.4), cuDNN 9.24, Triton 3.8.0, ROCm 7.14 (wheels built from the TheRock pip SDK), and XPU native graph capture requires oneAPI 2026.1+.
Summary
-
Two pre-upgrade checks : (1) training code with values sitting on
clamp/min/max boundaries — verify gradient golden tests (silently 1→0); (2) bfloat16 mixed with complex scalars — add explicit casts (nowNotImplementedError) -
torch.cholesky/torch.qr/ profileruse_cudamigrations are mechanical — the error messages tell you exactly what to write -
TorchScript-based deployments should start planning the
torch.exportmigration — making the warnings visible is step one toward removal - Verification environment: every snippet in this post was executed on torch 2.13.0 and 2.14.0 (CPU wheels, Python 3.12, macOS arm64)
Top comments (0)