
PyTorch 2.14 来了。
这次更新把很多 Python 用户会遇到的基础能力继续补齐:Python 3.15 和自由线程版 Python 3.15t 的 wheel 覆盖更完整;线性代数新增矩阵极分解、矩阵平方根,同时移除旧版分解接口;自动求导、vmap、优化器和 linear_cross_entropy 也都有实用改进。
目录
Python 版本支持
线性代数:新增分解接口与旧接口迁移
自动求导:距离函数二阶梯度与边界梯度规则
torch.accelerator:统一访问加速器随机数状态
大词表训练:linear_cross_entropy
优化器:Muon、LBFGS 与融合式 CPU 修复
vmap:更多普通张量代码可以自动批量化
arange 修复
Sequential 类型提示
升级建议
Python 版本支持
PyTorch 2.14 扩展了 Python 3.15 和 Python 3.15t 的二进制包覆盖范围。官方发布说明中提到,2.14 发布了 Python 3.15 和 3.15t 的 wheel 包,覆盖:
Linux x86-64 / aarch64;
Windows x86-64;
苹果芯片版 macOS;
对应平台上的 CPU、CUDA、ROCm、XPU 等适用构建。
需要注意的是,这里的支持主要是二进制包和 eager 运行时层面。官方说明也明确提到:torch.compile 在 Python 3.15 上仍未支持。因此,如果你的项目强依赖 torch.compile,暂时仍建议使用已经验证过的 Python 版本。
从 PyTorch 2.14 起,Python 3.15 和 3.15t 的官方 wheel 覆盖更完整。
但如果项目依赖 torch.compile,先不要急着迁到 Python 3.15。
线性代数:新增分解接口与旧接口迁移
PyTorch 2.14 在线性代数上有两类变化:新增更高层的矩阵函数,移除早已废弃的旧接口。
矩阵极分解 torch.linalg.polar
矩阵极分解可以把一个矩阵拆成两部分:
A = U @ H
其中 U 表示类似方向或旋转的部分,H 是对称 / 厄米的正半定部分。这个分解在正交约束、数值优化、几何变换、矩阵近似等场景中会出现。
过去如果要在 PyTorch 里做极分解,通常需要自己基于奇异值分解手写一段:
import torch
A = torch.randn(8, 4)
u, s, vh = torch.linalg.svd(A, full_matrices=False)
U = u @ vh
H = vh.mH @ torch.diag_embed(s) @ vh
PyTorch 2.14 新增 torch.linalg.polar(),现在可以直接写:
import torch
A = torch.randn(8, 4)
U, H = torch.linalg.polar(A)
print(torch.allclose(A, U @ H, atol=1e-5, rtol=1e-5))
这个接口适用于行数不少于列数的矩阵。它默认使用可移植的奇异值分解实现;对于符合条件的 CUDA 输入,也可以使用 cuSOLVER QDWH 加速。2.14 还补充了 torch.linalg.polar 在 CPU、CUDA 和 MPS 上的反向传播支持。如果你的损失函数依赖极分解结果,现在可以更自然地把它放进训练图里。
矩阵主平方根 torch.linalg.matrix_sqrth
普通数字的平方根很好理解:s * s = a。矩阵也有类似概念:如果一个矩阵 S 满足:
S @ S == A
那么 S 就是矩阵 A 的一个平方根。PyTorch 2.14 新增的 torch.linalg.matrix_sqrth 用于计算对称或厄米正定矩阵的主平方根。
这类操作常见于协方差矩阵处理、白化变换、二阶优化、核方法和部分几何深度学习算法。以前用户常常需要自己写特征值分解版本:
import torch
x = torch.randn(16, 5, 5)
A = x @ x.mT + 1e-3 * torch.eye(5)
evals, evecs = torch.linalg.eigh(A)
S = evecs @ torch.diag_embed(evals.sqrt()) @ evecs.mH
现在可以直接调用标准接口:
import torch
x = torch.randn(16, 5, 5)
A = x @ x.mT + 1e-3 * torch.eye(5)
S = torch.linalg.matrix_sqrth(A)
print((S @ S - A).abs().max())
这个新接口支持批量输入、自动求导、vmap 和 torch.compile。这点很重要:它不是只能处理单个矩阵的小工具,而是可以进入现代 PyTorch 的函数变换和编译流程。
移除 cholesky 与 qr 旧接口
这一版也正式移除了两个旧线性代数接口:torch.cholesky() / Tensor.cholesky() 和 torch.qr() / Tensor.qr()。
Cholesky 分解常用于正定矩阵,把矩阵分解成三角矩阵形式,例如协方差矩阵、多元高斯分布、线性方程求解中都会遇到。现在应使用 torch.linalg.cholesky():
# 旧写法
lower = torch.cholesky(a)
upper = torch.cholesky(a, upper=True)
# 新写法
lower = torch.linalg.cholesky(a)
upper = torch.linalg.cholesky(a).mH
注意:torch.linalg.cholesky() 返回的是下三角因子。如果过去使用 upper=True,迁移时需要显式取共轭转置 .mH。
QR 分解会把矩阵拆成正交矩阵 Q 和上三角矩阵 R。它常用于最小二乘、数值线性代数、矩阵正交化等场景。现在应使用 torch.linalg.qr():
# 旧写法
q, r = torch.qr(a)
q_full, r_full = torch.qr(a, some=False)
# 新写法
q, r = torch.linalg.qr(a, mode="reduced")
q_full, r_full = torch.linalg.qr(a, mode="complete")
迁移时主要注意 some 参数的替代关系:some=True 对应 mode="reduced",some=False 对应 mode="complete"。
自动求导:距离函数二阶梯度与边界梯度规则
cdist 和 pdist 支持二阶梯度
torch.cdist 和 torch.pdist / torch.nn.functional.pdist 都是成对距离函数。
torch.cdist(x, y) 计算两组点之间的两两距离。例如 x 有 4 个点,y 有 5 个点,每个点都是 3 维向量,那么输出形状就是 [4, 5]:
import torch
x = torch.randn(4, 3)
y = torch.randn(5, 3)
d = torch.cdist(x, y)
print(d.shape) # torch.Size([4, 5])
torch.pdist(x) 则计算同一组点内部的两两距离。它不会返回完整的 [N, N] 矩阵,而是返回压缩后的一维结果,长度为 N * (N - 1) / 2:
import torch
x = torch.randn(4, 3)
d = torch.pdist(x)
print(d.shape) # torch.Size([6])
这些函数在对比学习、聚类、度量学习、点云处理、分子建模、物理仿真等任务里很常见。只要你的损失函数里有样本之间的距离,就可能会碰到它们。
PyTorch 2.14 为 torch.cdist 和 torch.nn.functional.pdist 增加了二阶梯度支持。一阶梯度是普通训练最常用的梯度:损失函数对参数求导。二阶梯度则是梯度的梯度,常见于元学习、隐式层、部分二阶优化方法、物理建模和需要海森矩阵 / 雅可比矩阵信息的算法。
过去,下面这类代码可能会因为 _cdist_backward 或 _pdist_backward 没有二阶导数定义而失败:
import torch
x = torch.randn(4, 3, requires_grad=True)
y = torch.randn(5, 3, requires_grad=True)
loss = torch.cdist(x, y).sum()
# create_graph=True 表示后面还要继续对梯度求导
gx, = torch.autograd.grad(loss, x, create_graph=True)
# PyTorch 2.14 起,这类二阶梯度路径可以工作
second, = torch.autograd.grad(gx.sum(), x)
这个更新的意义不是让普通训练突然变快,而是减少高级训练方法中的绕路实现。以前如果距离函数阻断了二阶梯度,你可能要改写距离计算或手动推导;现在可以更自然地使用 PyTorch 的自动求导。
clamp / min / max 边界点梯度规则变化
clamp_min(x, bound) 的数学含义是取 x 和 bound 中较大的那个。问题出现在 x == bound 的边界点:这时函数不可导,框架需要选择一个次梯度。
PyTorch 2.14 调整了 clamp 和 min/max 在不可导边界或相等值处的次梯度规则,使其跟所选调度器签名的输入空间保持一致。
当 clamp 的边界是标量时,边界被视为固定参数。输入刚好等于边界时,输入梯度从旧版本的 1 变为最小范数次梯度 0:
import torch
x = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(x, 0.0).backward()
print(x.grad) # 2.14: tensor(0.)
当边界本身也是张量时,边界也是可微输入空间的一部分。此时相等值情况会把梯度平均分给输入值和边界值:
value = torch.tensor(0.0, requires_grad=True)
bound = torch.tensor(0.0, requires_grad=True)
torch.clamp_min(value, bound).backward()
print(value.grad, bound.grad) # 2.14: tensor(0.5000) tensor(0.5000)
这个变化通常只影响刚好卡在边界上的点。如果你的测试里断言了这类边界梯度,或者模型中刻意依赖旧版本相等值分支行为,可以用 torch.where 显式写出想要的规则。
torch.accelerator 统一访问加速器随机数状态
PyTorch 过去很多设备相关接口都以具体后端命名,例如 torch.cuda、torch.xpu、torch.mps。这种写法很直观,但问题是:如果你想写一份能在多种加速器上运行的训练代码,就会出现很多后端判断。
torch.accelerator 的作用可以理解为:给当前可用的加速器后端提供一个更统一的入口。这样代码不必总是写死 cuda,也更容易迁移到其他加速器后端。
深度学习训练里有很多随机操作:初始化参数、dropout、随机采样、数据增强等。我们平时常说设置随机种子,但严格来说,随机数生成器不只有一个初始种子,还有一个不断前进的状态。
如果只保存种子,未必能恢复到训练中途的精确随机位置;如果保存随机数生成器状态,就可以更精确地恢复随机数流。这对检查点、复现实验、调试随机性问题都很重要。
以前 CUDA 代码常写成这样:
import torch
torch.manual_seed(1234)
if torch.cuda.is_available():
cuda_state = torch.cuda.get_rng_state()
这种写法直接绑定 CUDA。PyTorch 2.14 新增了后端无关的加速器随机数检查接口:
torch.accelerator.initial_seed()
torch.accelerator.get_rng_state()
torch.accelerator.get_rng_state_all()
可以写成:
import torch
torch.manual_seed(1234)
seed = torch.accelerator.initial_seed()
state = torch.accelerator.get_rng_state()
all_states = torch.accelerator.get_rng_state_all()
它们的意义分别是:
initial_seed():查看当前加速器随机数生成器的初始种子;
get_rng_state():获取当前加速器设备的随机数生成器状态;
get_rng_state_all():获取所有加速器设备的随机数生成器状态。
这类接口主要服务于多硬件训练脚本、测试框架和实验复现工具。普通单卡用户不一定频繁调用,但一旦你要写同一份代码在不同加速器上运行的工具,它会明显减少后端分支。
大词表训练 linear_cross_entropy
训练语言模型时,最后一步通常是把每个词元的隐藏状态投影到整个词表,再计算交叉熵。假设批大小为 8,序列长度为 1024,词表大小为 50000,那么未归一化分数张量的形状就是 [8, 1024, 50000]。这个中间张量非常大,即使只是临时产生,也会带来明显的显存压力。
传统写法大致如下:
import torch.nn.functional as F
# hidden: [批大小, 序列长度, 隐藏维度]
# linear_weight: [词表大小, 隐藏维度]
logits = F.linear(hidden, linear_weight)
# 未归一化分数会被显式物化成 [批大小, 序列长度, 词表大小]
loss = F.cross_entropy(
logits.flatten(0, 1),
target.flatten(0, 1),
)
linear_cross_entropy 的背景就是这个问题:它把线性投影和交叉熵放在一个接口里计算,尽量避免完整物化巨大的未归一化分数张量。对小分类任务来说,省下来的内存可能不明显;但对大词表大语言模型训练来说,这类融合接口能显著降低峰值显存。
融合后的写法类似这样:
import torch.nn.functional as F
loss = F.linear_cross_entropy(
hidden,
linear_weight,
target,
reduction="mean",
)
这里的关键区别是:用户不再先手动算 logits = F.linear(...),而是把 hidden、linear_weight 和 target 直接交给融合损失函数。
LinearCrossEntropyOptions 则是给这个融合计算传配置的对象。因为融合实现内部可以采用不同的累积策略、分块策略和精度 / 显存折中方式,所以 PyTorch 提供了配置对象让用户选择策略。例如 acc_policy 就是累积策略,用来控制权重梯度累积时更偏向精度、内存,还是自动选择。
import torch
import torch.nn.functional as F
options = torch.nn.LinearCrossEntropyOptions(
acc_policy="auto",
)
loss = F.linear_cross_entropy(
hidden,
linear_weight,
target,
reduction="mean",
options=options,
)
PyTorch 2.14 有两个和它相关的变化。
第一,分块路径继续补齐:当 target 是概率标签,并且 target 的数据类型与 input 匹配、target 不需要梯度时,现在也可以处理 reduction="mean" 和 reduction="sum"。概率标签常见于标签平滑、知识蒸馏、软标签训练等场景。
import torch
import torch.nn.functional as F
hidden = torch.randn(8, 128, 4096, device="cuda")
linear_weight = torch.randn(50000, 4096, device="cuda")
# 概率标签,而不是类别下标
target = torch.randn(8, 128, 50000, device="cuda").softmax(dim=-1)
loss = F.linear_cross_entropy(
hidden,
linear_weight,
target,
reduction="mean",
)
第二,LinearCrossEntropyOptions 的 balanced 策略被移除。官方建议改用 "compact"。原因是 "compact" 在 CUDA 上可以提供相同的权重梯度累积精度,同时使用更少内存;在其他设备的混合精度输入场景中,也已经使用等价的临时缓冲区布局。
# 旧写法
options = torch.nn.LinearCrossEntropyOptions(acc_policy="balanced")
# 新写法
options = torch.nn.LinearCrossEntropyOptions(acc_policy="compact")
如果你在 2.13 已经开始试用 LinearCrossEntropyLoss 或 linear_cross_entropy,升级前建议全局搜索一下 acc_policy="balanced"。这个改动不影响没用到该配置对象的普通交叉熵代码。
优化器:Muon、LBFGS 与融合式 CPU 修复
Muon 新增 spectral_unclamped 缩放选项
torch.optim.Muon 是 PyTorch 中较新的优化器。PyTorch 2.14 为它的 adjust_lr_fn 参数新增 "spectral_unclamped" 缩放选项。
可以理解为:Muon 在更新参数时会涉及一套学习率调整策略,adjust_lr_fn 用来选择这种调整方式。2.14 新增的 "spectral_unclamped" 给已经在试用 Muon 的用户多了一个实验选项。
optimizer = torch.optim.Muon(
model.parameters(),
lr=0.02,
adjust_lr_fn="spectral_unclamped",
)
如果你没有使用 Muon,可以暂时略过这一项;如果你正在比较 Muon 与 AdamW、SGD 等优化器的效果,这个新选项可以加入实验表。
LBFGS 支持 maximize
LBFGS 是一种拟牛顿优化方法。和 SGD、AdamW 这类一阶优化器不同,它会利用历史梯度信息近似二阶曲率,从而在某些小规模、较平滑、确定性的优化问题上收敛很快。
在深度学习里,LBFGS 不是最常见的通用训练优化器,但会出现在一些特定场景中,例如风格迁移、小模型或全批量优化、物理信息神经网络、需要较精细数值优化的实验代码。
PyTorch 里的 LBFGS 通常需要闭包函数,因为它可能在一次 step() 内多次重新计算损失函数和梯度:
optimizer = torch.optim.LBFGS(model.parameters(), lr=1.0)
def closure():
optimizer.zero_grad()
loss = compute_loss(model)
loss.backward()
return loss
optimizer.step(closure)
PyTorch 2.14 为 torch.optim.LBFGS 新增 maximize 参数。过去 LBFGS 默认最小化目标函数;如果你要最大化某个目标,常见做法是手动把目标取负:
# 旧写法:为了最大化目标函数,手动最小化其相反数
def closure():
optimizer.zero_grad()
loss = -compute_objective(model)
loss.backward()
return loss
现在可以直接表达我要最大化:
optimizer = torch.optim.LBFGS(
model.parameters(),
lr=1.0,
maximize=True,
)
def closure():
optimizer.zero_grad()
objective = compute_objective(model)
objective.backward()
return objective
optimizer.step(closure)
这让 LBFGS 与 PyTorch 中其他优化器的接口更一致,也减少了因为手动取负带来的阅读负担。此外,torch.optim.LBFGS.step() 在遇到空参数组时现在会成为空操作。这对动态构建参数组、按条件冻结参数的代码更友好。
融合式 CPU SGD / Adagrad 修复
优化器看起来只是几行 Python 调用,但内部实现并不一定真的是一个参数一个参数地 Python 循环更新。以 SGD 为例,最直观的写法可以理解成这样:
for p in model.parameters():
p -= lr * p.grad
这种写法容易理解,但当模型参数很多时,Python 循环和大量小张量操作会带来额外开销。为降低这类开销,PyTorch 的优化器通常会有多种实现路径:
逐参数循环路径:逻辑最直观,兼容性最好;
foreach 路径:把一组参数打包成批量张量操作,减少 Python 调度开销;
融合路径:进一步把多个更新步骤融合到更少的底层计算内核或实现中,减少中间开销,对应使用 fused=True 的情况。
所谓融合式 CPU 优化器,就是在 CPU 上使用这种融合实现的优化器路径。它的目标是提升参数更新效率,尤其是在参数数量很多、每步更新包含许多小操作时。
PyTorch 2.14 修复了融合式 CPU 优化器中的两个问题:torch.optim.SGD / torch.optim.Adagrad 可能跳过某些参数更新,以及 float16 / bfloat16 类型转换不正确。
这两个问题都属于不会改变接口,但会影响训练正确性的类型。跳过更新意味着某些参数本该在当前一步被修改,却没有被修改;低精度类型转换错误则可能让 float16 / bfloat16 参数或梯度在更新过程中发生不符合预期的数值转换。
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.01,
fused=True,
)
如果你一直使用默认优化器路径,可能感知不强;如果你在 CPU 上显式启用了融合式 SGD 或 Adagrad,尤其是低精度训练、单元测试、性能测试中使用了这些路径,升级后建议重新跑训练一致性测试。
vmap:更多普通张量代码可以自动批量化
torch.vmap 的作用是把一个处理单个样本的函数自动变成处理一批样本的函数。它有点像自动替你写批量维度上的 Python 循环,但通常更简洁,也更容易和自动求导、函数式变换组合。
例如我们有一个计算单个样本损失的函数:
import torch
def single_loss(x, y):
return ((x - y) ** 2).sum()
xs = torch.randn(32, 10)
ys = torch.randn(32, 10)
不用 vmap 时,可能写成 Python 循环:
losses = torch.stack([
single_loss(x, y)
for x, y in zip(xs, ys)
])
使用 vmap 后,可以写成:
batched_loss = torch.vmap(single_loss)
losses = batched_loss(xs, ys)
这在逐样本梯度、批量雅可比矩阵、元学习、函数式模型变换等场景里很有用。
vmap 的难点在于:不是所有 PyTorch 操作天然都知道多出来的批量维度该怎么处理。PyTorch 需要为各种算子补批量化规则。没有批量化规则时,可能报错,也可能走较慢的降级路径,并发出性能警告。
PyTorch 2.14 继续补齐这些规则,包括:
torch.searchsorted 的标量重载现在可在 vmap 下使用;
复制-视图类操作会通过已有批量化规则处理;
torch.repeat_interleave 在 repeats 带批量维度时新增批量化规则,但调用者需要提供统一的 output_size,因为每个样本的输出长度可能依赖数据;
原地 Tensor.masked_fill_() 新增原生批量化规则,避免较慢的降级路径和性能警告;
标量填充和比较在 vmap 下支持更完整,包括标量操作数位于加速器上的情况。
举个例子,masked_fill_ 常用于按掩码修改张量:
def fill_one(x, mask):
x = x.clone()
x.masked_fill_(mask, 0.0)
return x
xs = torch.randn(16, 8)
masks = xs < 0
out = torch.vmap(fill_one)(xs, masks)
这类代码过去可能触发降级路径警告;2.14 增加原生批量化规则后,vmap 覆盖面更完整,写函数式批量代码时会少一些障碍。
torch.arange 的长度计算修复
torch.arange(start, end, step) 常用于生成索引、时间步或网格。PyTorch 2.14 修复了它在“小数参数 + 整数输出数据类型”组合下可能计算错误长度的问题。
问题在于:如果 start、end 或 step 是小数,但输出数据类型是整数,旧逻辑可能过早截断小数,导致长度计算不正确。
类似下面这种代码,升级后建议重新跑相关测试,确认长度和边界行为符合预期:
import torch
x = torch.arange(0.1, 5.9, 1.0, dtype=torch.int64)
print(x)
这类问题乍看不大,但如果 arange 用来构造索引、时间步或位置编码,长度错一位就可能引发后续形状不匹配。
nn.Sequential 索引的静态类型更准确
torch.nn.Sequential 是 PyTorch 里最常见的容器之一。它把多个模块按顺序串起来,适合快速搭建简单网络。
运行时,Sequential 一直支持整数索引和切片:
import torch.nn as nn
model = nn.Sequential(
nn.Linear(10, 20),
nn.ReLU(),
nn.Linear(20, 2),
)
layer = model[0]
head = model[1:]
这里 model[0] 返回单个 Module,而 model[1:] 返回一个新的 Sequential。PyTorch 2.14 改进的是静态类型提示:整数索引会被类型检查器识别为 Module,切片会被识别为 Sequential。
这不会改变运行时行为,但对使用 pyright、mypy 或编辑器类型提示的项目很有帮助。大型工程里,类型提示越准确,重构时越不容易把单层模块和模块序列混在一起。
升级建议
如果准备从 PyTorch 2.13 升级到 2.14,可以优先检查下面几类代码:
Python 环境:如果想试 Python 3.15 / 3.15t,确认当前平台已有对应 wheel;如果依赖 torch.compile,暂时不要把运行环境切到 Python 3.15。
线性代数旧接口:搜索 torch.cholesky、.cholesky(、torch.qr、.qr(,迁移到 torch.linalg 命名空间。
LinearCrossEntropy:搜索 acc_policy="balanced",改为 acc_policy="compact";如果使用概率标签,可关注 2.14 对分块路径的新支持。
边界梯度测试:如果测试覆盖 clamp、min、max 在相等边界处的梯度,重新确认 2.14 的期望值。
vmap 代码:如果之前因为 searchsorted、repeat_interleave、masked_fill_ 等操作绕开了 vmap,可以重新测试是否能简化。
融合式 CPU 优化器:如果使用融合式 CPU SGD 或 Adagrad,建议升级后重新跑训练一致性测试。
整体来看,PyTorch 2.14 是一次基础能力继续补齐的版本。它没有只押注某一个醒目的大功能,而是在 Python 版本支持、线性代数、自动求导、vmap、优化器和正确性修复上一起向前推进。普通训练用户可以重点关注旧接口删除、linear_cross_entropy 和边界梯度变化;工具链、科学计算和高级训练方法用户,则更值得试试 matrix_sqrth、polar、二阶梯度、torch.accelerator 随机数接口和更完整的 vmap 支持。
以上就是“PyTorch 2.14 发布:Python 3.15 全平台支持,线性代数、自动求导、优化器继续补齐”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14480/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料