DEV Community

Sho Tanaka (tsho)
Sho Tanaka (tsho)

Posted on Originally published at implicit-none.com on

PyTorch 2.14: clamp's Boundary Gradient Silently Changes, bfloat16 Complex Promotion Now Raises, cholesky/qr Removed

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.])

Enter fullscreen mode Exit fullscreen mode

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'

Enter fullscreen mode Exit fullscreen mode

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_cuda argument removed from torch.profiler.profile (use activities; confirmed gone via inspect.signature)
  • Custom ProcessGroup new_group() implementations must accept a backend keyword argument (otherwise TypeError)
  • torch.distributed.split_group() now returns GroupMember.NON_GROUP_MEMBER instead of None for non-member ranks
  • setup.py is now a shim : build / bdist_wheel / sdist print their replacement commands instead of executing (use pip or python -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`.

Enter fullscreen mode Exit fullscreen mode

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_ranktorch.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 switch generalization of torch.cond ships as a prototype — but it lives at torch._higher_order_ops.switch; torch.switch does not exist yet (confirmed on 2.14.0). torch.while_loop can now be captured in CUDA graphs
  • @dynamic_spec decorator : one declarative dynamic-shape spec shared across torch.compile, torch.export, and make_fx
  • Distributed overhaul : the new nccl2 backend ported from torchcomms (nonblocking communicators, eager splitting), and fault tolerance as a first-class c10d concept 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_sqrth added (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.compile remains 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 (now NotImplementedError)
  • torch.cholesky / torch.qr / profiler use_cuda migrations are mechanical — the error messages tell you exactly what to write
  • TorchScript-based deployments should start planning the torch.export migration — 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)

References

Top comments (0)