pytorch张量转numpy必须满足两个条件:张量在cpu上且无梯度依赖(requires_grad=false),否则报错;最稳妥写法是tensor.detach().cpu().numpy(),顺序不可颠倒,且非连续张量需先.contiguous()。

PyTorch张量转NumPy数组:用.numpy()但必须满足条件
直接调用.numpy()是最常见做法,但失败率很高——根本原因在于PyTorch要求张量必须在CPU上、且不能有计算图依赖(即requires_grad=False)。GPU张量或带梯度的张量会直接报错:RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
- 先确认设备:
tensor.is_cuda为True时,必须先.cpu() - 再确认梯度:
tensor.requires_grad为True时,必须先.detach()(不改变数据,只切断梯度流) - 最稳妥写法:
tensor.detach().cpu().numpy(),适用于训练中任意张量 - 注意:如果张量是0维(标量),
.numpy()返回的是Python原生类型(如float32),不是数组;需显式加np.array()或用.item()
NumPy数组转PyTorch张量:优先用torch.from_numpy()
torch.from_numpy()创建的是共享内存的张量,修改任一端数据,另一端同步变化。这是高效但危险的操作——如果你后续要对张量做.to(device)或.requires_grad_(True),必须确保原始NumPy数组生命周期足够长,否则可能引发未定义行为。
- 不要用
torch.tensor(np_array)代替,它会复制数据、丢失共享特性,且默认requires_grad=False,类型也可能被意外转换(如np.float64→torch.float32) - 若需独立副本,明确用
torch.as_tensor(np_array).clone(),比torch.tensor()更轻量 - NumPy数组dtype必须是PyTorch支持的(如
np.float32、np.int64),np.float64转成torch.float64需手动指定dtype=torch.float64
跨设备/梯度场景下的典型错误与修复
实际调试中最常卡在这几类组合:GPU张量转NumPy、训练循环中反向传播后取值、多线程读取NumPy视图。这些不是“不会写”,而是没意识到内存模型约束。
-
tensor.cuda().numpy()→ 报错:RuntimeError: Can't convert a CUDA tensor to a NumPy array→ 改为tensor.cpu().numpy() -
loss.backward(); loss.numpy()→ 报错:Can't call numpy() on Tensor that requires grad→ 改为loss.detach().numpy() - 用
torch.from_numpy()后调.cuda()→ 原NumPy数组仍在CPU内存,但张量已搬走,共享失效 → 此时应改用torch.tensor(np_array, device='cuda')重新分配
类型与内存布局兼容性:别忽略contiguous()
NumPy数组默认C连续,但PyTorch张量经过.transpose()、.narrow()等操作后可能变成非连续(tensor.is_contiguous() == False)。此时.numpy()会静默失败或报错:RuntimeError: can't convert non-contiguous tensor to numpy。
- 安全写法:统一加
.contiguous()兜底,如tensor.contiguous().detach().cpu().numpy() - 非连续张量转NumPy前必须
.contiguous(),否则即使成功也可能返回错误视图 - NumPy转PyTorch一般不受影响,但若NumPy本身是非C连续(如
np.asfortranarray()),torch.from_numpy()会报错,需先.copy()
torch.from_numpy(a)传给Dataloader后,在worker里修改a,主线程看到的张量值就变了。这种问题不会报错,只会让结果不可复现。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











