Pytorch 张量到 numpy 数组

Posted

技术标签:

【中文标题】Pytorch 张量到 numpy 数组【英文标题】:Pytorch tensor to numpy array 【发布时间】:2018-09-20 22:32:48 【问题描述】:

我有一个 pytorch 张量,大小为 torch.Size([4, 3, 966, 1296])

我想使用以下代码将其转换为numpy 数组:

imgs = imgs.numpy()[:, ::-1, :, :]

谁能解释一下这段代码在做什么?

【问题讨论】:

Understanding Python's slice notation的可能重复 您的问题非常令人困惑。您已经有一个.numpy() 电话。你到底对什么感到困惑?你不明白python中的切片符号吗? 顺便说一句,您可能需要在保存数据之前致电.detach(),例如x.detach().numpy() 如果你的张量有毕业生......你也可能需要打电话给cpu()。我认为这应该可行:x.detach().cpu().numpy() 转换为 numpy 时,应在 cpu 之前调用 detach 以防止多余的渐变复制。见discuss.pytorch.org/t/… 【参考方案1】:

您要转换的张量有 4 个维度。

[:, ::-1, :, :] 

: 表示第一个维度应该照原样复制并转换,第三个和第四个维度也是如此。

::-1 表示对于第二个轴,它会反转轴

【讨论】:

你确定吗?对我来说,它看起来更像是轴 0,2,3 是按原样复制的,而轴 1 是相反的。 真实答案:x.detach().cpu().numpy() 转换为 numpy 时,应在 cpu 之前调用 detach 以防止多余的渐变复制。见discuss.pytorch.org/t/… x.detach().cpu().numpy() 为我工作~!【参考方案2】:

我相信你也必须使用.detach()。我不得不将我的张量转换为 Colab 上使用 CUDA 和 GPU 的 numpy 数组。我是这样做的:

# this is just my embedding matrix which is a Torch tensor object
embedding = learn.model.u_weight

embedding_list = list(range(0, 64382))

input = torch.cuda.LongTensor(embedding_list)
tensor_array = embedding(input)
# the output of the line below is a numpy array
tensor_array.cpu().detach().numpy()

【讨论】:

当然你必须使用detach,因为你最初在 GPU 上创建了一个 PyTorch 张量。如原始帖子所示,如果它是在 CPU 中创建的,则不适用。 我认为即使你的张量在CPU中,如果你想要一个raw张量,你必须.detach() 转换为numpy 时,应在cpu 之前调用detach,以防止多余的渐变复制。见discuss.pytorch.org/t/…【参考方案3】:

如果您的变量附加了一些毕业生,您可以使用此语法。

y=torch.Tensor.cpu(x).detach().numpy()[:,:,:,-1]

【讨论】:

这与这里的其他答案相比对这个问题没有任何贡献。 cpu 调用中的 x 是什么意思? 您确定需要.cpu() 电话吗? 转换为 numpy 时,应在 cpu 之前调用 detach 以防止多余的渐变复制。见discuss.pytorch.org/t/…【参考方案4】:

你的问题措辞很糟糕。你的代码(有点)已经做了你想要的。你到底对什么感到困惑? x.numpy()回答你问题的原标题:

Pytorch 张量转 numpy 数组

你需要从你的标题开始改进你的问题。

无论如何,以防万一这对其他人有用。您可能需要调用 detach 才能使您的代码正常工作。例如

RuntimeError: Can't call numpy() on Variable that requires grad.

所以请致电.detach()。示例代码:

# creating data and running through a nn and saving it

import torch
import torch.nn as nn

from pathlib import Path
from collections import OrderedDict

import numpy as np

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

num_samples = 3
Din, Dout = 1, 1
lb, ub = -1, 1

x = torch.torch.distributions.Uniform(low=lb, high=ub).sample((num_samples, Din))

f = nn.Sequential(OrderedDict([
    ('f1', nn.Linear(Din,Dout)),
    ('out', nn.SELU())
]))
y = f(x)

# save data
y.numpy()
x_np, y_np = x.detach().cpu().numpy(), y.detach().cpu().numpy()
np.savez(path / 'db', x=x_np, y=y_np)

print(x_np)

cpu 在分离之后。见:https://discuss.pytorch.org/t/should-it-really-be-necessary-to-do-var-detach-cpu-numpy/35489/5


另外,我不会在 slicking 上做任何 cmet,因为那是题外话,这不应该是你问题的重点。看到这个:

Understanding slice notation

【讨论】:

【参考方案5】:

虽然其他答案完美解释了这个问题,但我将添加一些将张量转换为 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]=10naa 行将保持原样。

示例: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')

【讨论】:

【参考方案6】:

这对我有用:

np_arr = torch_tensor.cpu().detach().numpy()

【讨论】:

我认为顺序有所不同,也许这样更好? x.detach().cpu().numpy()

以上是关于Pytorch 张量到 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章

[Pytorch]Tensor

Pytorch——张量 Tensors

pytorch学习系列文章第二篇——张量

小白学习PyTorch教程一PyTorch基本操作

为啥我们在 Pytorch 张量上调用 .numpy() 之前调用 .detach()?

pytorch 模块