虽然其他答案完美解释了这个问题,但我将添加一些将张量转换为 numpy 数组的真实示例:
示例:共享存储
驻留在 CPU 上的 PyTorch 张量与 numpy 数组 na 共享相同的存储空间
import torch
a = torch.ones((1,2))
print(a)
na = a.numpy()
na[0][0]=10
print(na)
print(a)
输出:
tensor([[1., 1.]])
[[10. 1.]]
tensor([[10., 1.]])
示例:消除共享存储的影响,先复制numpy数组
为了避免共享存储的影响,我们需要将copy() numpy 数组na 转换为一个新的numpy 数组nac。 Numpy copy() 方法创建新的独立存储。
import torch
a = torch.ones((1,2))
print(a)
na = a.numpy()
nac = na.copy()
nac[0][0]=10
print(nac)
print(na)
print(a)
输出:
tensor([[1., 1.]])
[[10. 1.]]
[[1. 1.]]
tensor([[1., 1.]])
现在,只有 nac numpy 数组将被更改,nac[0][0]=10、na 和 a 行将保持原样。
示例:requires_grad=True 的 CPU 张量
import torch
a = torch.ones((1,2), requires_grad=True)
print(a)
na = a.detach().numpy()
na[0][0]=10
print(na)
print(a)
输出:
tensor([[1., 1.]], requires_grad=True)
[[10. 1.]]
tensor([[10., 1.]], requires_grad=True)
我们在这里调用:
na = a.numpy()
这将导致:RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.,因为 require_grad=True 的张量由 PyTorch AD 记录。请注意,tensor.detach() 是 tensor.data 的新方式。
这解释了为什么在使用numpy() 转换之前我们需要先detach()。
示例:requires_grad=False 的 CUDA 张量
a = torch.ones((1,2), device='cuda')
print(a)
na = a.to('cpu').numpy()
na[0][0]=10
print(na)
print(a)
输出:
tensor([[1., 1.]], device='cuda:0')
[[10. 1.]]
tensor([[1., 1.]], device='cuda:0')
示例:requires_grad=True 的 CUDA 张量
a = torch.ones((1,2), device='cuda', requires_grad=True)
print(a)
na = a.detach().to('cpu').numpy()
na[0][0]=10
print(na)
print(a)
输出:
tensor([[1., 1.]], device='cuda:0', requires_grad=True)
[[10. 1.]]
tensor([[1., 1.]], device='cuda:0', requires_grad=True)
如果没有detach() 方法,将设置错误RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.。
如果没有.to('cpu') 方法TypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. 将被设置。
您可以使用cpu(),但不要使用to('cpu'),但我更喜欢较新的to('cpu')。