我有两个相同的张量列表(大小不同),但对于第一个张量,所有张量都分配给了cuda设备。例如:
list1=[torch.tensor([0,1,2]).cuda(),torch.tensor([3,4,5,6]).cuda(),torch.tensor([7,8]).cuda()]
>>> list1
[tensor([0, 1, 2], device='cuda:0'), tensor([3, 4, 5, 6], device='cuda:0'), tensor([7, 8], device='cuda:0')]
list2=[torch.tensor([0,1,2]),torch.tensor([3,4,5,6]),torch.tensor([7,8])]
>>> list2
[tensor([0, 1, 2]), tensor([3, 4, 5, 6]), tensor([7, 8])]
我想根据索引数组从列表中提取一些张量:
ind=torch.tensor([0,2])
>>> ind
tensor([0, 2])
所以我的解决方案是做这样的事情:
np.array(list1)[ind]
np.array(list2)[ind]
我的问题是为什么它与在cuda设备上定义的张量的第一个列表一起使用,而对第二个列表给出错误,如下所示:
>>> np.array(list1)[ind]
array([tensor([0, 1, 2], device='cuda:0'),
tensor([7, 8], device='cuda:0')], dtype=object)
>>> np.array(list2)[ind]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: only one element tensors can be converted to Python scalars
编辑: 只是为了澄清,因为张量具有不同的形状,所以不会引发错误。以下示例说明了这一点:
list3=[torch.tensor([1,2,3]).cuda()]
list4=[torch.tensor([1,2,3]).cuda(),torch.tensor([4,5,6]).cuda()]
list5=[torch.tensor([1,2,3])]
list6=[torch.tensor([1,2,3]),torch.tensor([4,5,6])]
结果是:
>>> np.array(list3)
array([tensor([1, 2, 3], device='cuda:0')], dtype=object)
>>> np.array(list4)
array([tensor([1, 2, 3], device='cuda:0'),
tensor([4, 5, 6], device='cuda:0')], dtype=object)
>>> np.array(list5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: only one element tensors can be converted to Python scalars
>>> np.array(list6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: only one element tensors can be converted to Python scalars
答案 0 :(得分:1)
np.array
尝试将列表的每个元素转换为numpy数组。仅CPU张量支持此功能。简短的答案是,您可以显式指示numpy使用dtype=object
创建一个数组,以使CPU情况正常工作。要了解到底发生了什么,让我们仔细看看这两种情况。
首先请注意,如果您尝试在CUDA张量上使用np.array
,则会出现以下错误
np.array(torch.zeros(2).cuda())
TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.
在您的示例中,numpy尝试将list1
的每个元素转换为numpy数组,但是引发了一个异常,因此它只解决了使用dtype=object
创建数组的情况。
你最终会
np.array([torch.tensor([0,1,2]).cuda(), torch.tensor([3,4,5,6]).cuda(), torch.tensor([7,8]).cuda()])
只是一个指向不同对象的容器
array([tensor([0, 1, 2], device='cuda:0'),
tensor([3, 4, 5, 6], device='cuda:0'),
tensor([7, 8], device='cuda:0')], dtype=object)
对于CPU张量,PyTorch知道如何转换为numpy数组。因此,当您运行
np.array(torch.zeros(2))
您得到一个dtype为float32
的numpy数组
array([0., 0.], dtype=float32)
当numpy成功将list2
中的每个元素转换为numpy数组,然后尝试将它们堆叠为单个多维数组时,问题出在您的代码中。 Numpy期望每个列表项代表一个多维数组的一行,但是在您的情况下,它发现并非所有行都具有相同的形状,因此不知道如何进行并引发异常。
解决此问题的一种方法是显式指定dtype应该保留object
。这基本上告诉numpy“不要先尝试将条目转换为numpy数组”。
np.array([torch.tensor([0,1,2]), torch.tensor([3,4,5,6]), torch.tensor([7,8])], dtype=object)
现在给出与情况1类似的结果
array([tensor([0, 1, 2]),
tensor([3, 4, 5, 6]),
tensor([7, 8])], dtype=object)