63

例如,我有尺寸为 (5) 的一维向量。我想将其重塑为二维矩阵(1,5)。

这是我使用 numpy 的方法

>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
>>> a.shape
(5,)
>>> a = np.reshape(a, (1,5))
>>> a.shape
(1, 5)
>>> a
array([[1, 2, 3, 4, 5]])
>>> 

但是我怎么能用 Pytorch 张量(和变量)做到这一点。我不想切换回 numpy 并再次切换到 Torch 变量,因为它会丢失反向传播信息。

这是我在 Pytorch 中所拥有的

>>> import torch
>>> from torch.autograd import Variable
>>> a = torch.Tensor([1,2,3,4,5])
>>> a

 1
 2
 3
 4
 5
[torch.FloatTensor of size 5]

>>> a.size()
(5L,)
>>> a_var = variable(a)
>>> a_var = Variable(a)
>>> a_var.size()
(5L,)
.....do some calculation in forward function
>>> a_var.size()
(5L,)

现在我希望它的大小为 (1, 5)。如何在不丢失 grad 信息的情况下调整变量中 pytorch 张量的尺寸或重塑其尺寸。(因为我会在后退之前输入另一个模型)

4

11 回答 11

45

利用 torch.unsqueeze(input, dim, out=None)

>>> import torch
>>> a = torch.Tensor([1,2,3,4,5])
>>> a

 1
 2
 3
 4
 5
[torch.FloatTensor of size 5]

>>> a = a.unsqueeze(0)
>>> a

 1  2  3  4  5
[torch.FloatTensor of size 1x5]
于 2017-04-17T12:01:27.807 回答
22

你可能会使用

a.view(1,5)
Out: 

 1  2  3  4  5
[torch.FloatTensor of size 1x5]
于 2017-04-11T11:27:11.093 回答
17

有多种方法可以重塑 PyTorch 张量。您可以将这些方法应用于任何维度的张量。

让我们从一个二维2 x 3张量开始:

x = torch.Tensor(2, 3)
print(x.shape)
# torch.Size([2, 3])

为了给这个问题增加一些鲁棒性,让我们2 x 3通过在前面添加一个新维度和在中间添加另一个维度来重塑张量,从而产生一个1 x 2 x 1 x 3张量。

方法1:添加维度None

使用(aka ) 的NumPy 样式插入Nonenp.newaxis在您想要的任何位置添加尺寸。这里

print(x.shape)
# torch.Size([2, 3])

y = x[None, :, None, :] # Add new dimensions at positions 0 and 2.
print(y.shape)
# torch.Size([1, 2, 1, 3])

方法2:解压

使用torch.Tensor.unsqueeze(i)(又名torch.unsqueeze(tensor, i)或就地版本unsqueeze_())在第 i 个维度添加一个新维度。返回的张量与原始张量共享相同的数据。在本例中,我们可以使用unqueeze()两次来添加两个新维度。

print(x.shape)
# torch.Size([2, 3])

# Use unsqueeze twice.
y = x.unsqueeze(0) # Add new dimension at position 0
print(y.shape)
# torch.Size([1, 2, 3])

y = y.unsqueeze(2) # Add new dimension at position 2
print(y.shape)
# torch.Size([1, 2, 1, 3])

在 PyTorch 的实践中,为批处理添加额外的维度可能很重要,因此您可能经常会看到unsqueeze(0).

方法三:查看

用于torch.Tensor.view(*shape)指定所有尺寸。返回的张量与原始张量共享相同的数据。

print(x.shape)
# torch.Size([2, 3])

y = x.view(1, 2, 1, 3)
print(y.shape)
# torch.Size([1, 2, 1, 3])

方法四:重塑

使用torch.Tensor.reshape(*shape)(aka torch.reshape(tensor, shapetuple)) 指定所有维度。如果原始数据是连续的并且具有相同的步幅,则返回的张量将是输入的视图(共享相同的数据),否则将是副本。此函数类似于 NumPyreshape()函数,因为它允许您定义所有维度并可以返回视图或副本。

print(x.shape)
# torch.Size([2, 3])

y = x.reshape(1, 2, 1, 3)
print(y.shape)
# torch.Size([1, 2, 1, 3])

此外,作者在 O'Reilly 2019 年出版的Programming PyTorch for Deep Learning中写道:

view()现在您可能想知道和之间有什么区别reshape()。答案是view()作为原始张量的视图运行,因此如果基础数据发生更改,视图也会更改(反之亦然)。但是,view()如果所需的视图不连续,可能会引发错误;也就是说,如果从头开始创建所需形状的新张量,它不会共享相同的内存块。如果发生这种情况,您必须先致电tensor.contiguous(),然后才能使用view(). 但是,reshape()所有这些都是在幕后完成的,所以总的来说,我建议使用reshape()而不是view().

方法5:resize_

使用就地函数torch.Tensor.resize_(*sizes)修改原始张量。该文档指出:

警告。这是一种低级方法。存储被重新解释为 C 连续,忽略当前步幅(除非目标大小等于当前大小,在这种情况下张量保持不变)。在大多数情况下,您将改为使用view(),它检查连续性,或reshape(),它在需要时复制数据。要使用自定义步幅就地更改大小,请参阅set_()

print(x.shape)
# torch.Size([2, 3])

x.resize_(1, 2, 1, 3)
print(x.shape)
# torch.Size([1, 2, 1, 3])

我的观察

如果您只想添加一个维度(例如,为批次添加第 0 个维度),请使用unsqueeze(0). 如果您想完全改变维度,请使用reshape().

也可以看看:

pytorch中的reshape和view有什么区别?

view() 和 unsqueeze() 有什么区别?

在 PyTorch 0.4 中,是否建议在可能的情况下reshape使用view

于 2020-01-05T19:48:48.887 回答
16

对于张量形状的 就地tensor.resize_()修改,您应该使用:

In [23]: a = torch.Tensor([1, 2, 3, 4, 5])

In [24]: a.shape
Out[24]: torch.Size([5])


# tensor.resize_((`new_shape`))    
In [25]: a.resize_((1,5))
Out[25]: 

 1  2  3  4  5
[torch.FloatTensor of size 1x5]

In [26]: a.shape
Out[26]: torch.Size([1, 5])

在 PyTorch 中,如果操作末尾有下划​​线(如tensor.resize_()),那么该操作会in-place修改原始张量。


此外,您可以简单地np.newaxis在火炬张量中使用来增加尺寸。这是一个例子:

In [34]: list_ = range(5)
In [35]: a = torch.Tensor(list_)
In [36]: a.shape
Out[36]: torch.Size([5])

In [37]: new_a = a[np.newaxis, :]
In [38]: new_a.shape
Out[38]: torch.Size([1, 5])
于 2017-12-06T05:32:27.363 回答
6

这个问题已经得到了彻底的回答,但我想为经验不足的 python 开发人员补充一点,你可能会发现*操作符与view().

例如,如果您有一个特定的张量大小,您希望不同的数据张量符合,您可以尝试:

img = Variable(tensor.randn(20,30,3)) # tensor with goal shape
flat_size = 20*30*3
X = Variable(tensor.randn(50, flat_size)) # data tensor

X = X.view(-1, *img.size()) # sweet maneuver
print(X.size()) # size is (50, 20, 30, 3)

这也适用于 numpy shape

img = np.random.randn(20,30,3)
flat_size = 20*30*3
X = Variable(tensor.randn(50, flat_size))
X = X.view(-1, *img.shape)
print(X.size()) # size is (50, 20, 30, 3)
于 2017-11-29T20:30:24.823 回答
6

或者你可以使用它,'-1' 意味着你不必指定元素的数量。

In [3]: a.view(1,-1)
Out[3]:

 1  2  3  4  5
[torch.FloatTensor of size 1x5]
于 2017-10-08T03:13:51.180 回答
3

torch.reshape()用于欺骗numpy reshape方法。

它出现在view()torch.resize_()之后,并且在dir(torch)包内。

import torch
x=torch.arange(24)
print(x, x.shape)
x_view = x.view(1,2,3,4) # works on is_contiguous() tensor
print(x_view.shape)
x_reshaped = x.reshape(1,2,3,4) # works on any tensor
print(x_reshaped.shape)
x_reshaped2 = torch.reshape(x_reshaped, (-1,)) # part of torch package, while view() and resize_() are not
print(x_reshaped2.shape)

出去:

tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
        18, 19, 20, 21, 22, 23]) torch.Size([24])
torch.Size([1, 2, 3, 4])
torch.Size([1, 2, 3, 4])
torch.Size([24])

但是你知道它也可以作为squeeze()unsqueeze()的替代品吗?

x = torch.tensor([1, 2, 3, 4])
print(x.shape)
x1 = torch.unsqueeze(x, 0)
print(x1.shape)
x2 = torch.unsqueeze(x1, 1)
print(x2.shape)
x3=x.reshape(1,1,4)
print(x3.shape)
x4=x.reshape(4)
print(x4.shape)
x5=x3.squeeze()
print(x5.shape)

出去:

torch.Size([4])
torch.Size([1, 4])
torch.Size([1, 1, 4])
torch.Size([1, 1, 4])
torch.Size([4])
torch.Size([4])
于 2020-09-22T09:34:58.987 回答
1
import torch
>>>a = torch.Tensor([1,2,3,4,5])
>>>a.size()
torch.Size([5])
#use view to reshape

>>>b = a.view(1,a.shape[0])
>>>b
tensor([[1., 2., 3., 4., 5.]])
>>>b.size()
torch.Size([1, 5])
>>>b.type()
'torch.FloatTensor'
于 2018-11-26T22:39:12.720 回答
1

据我所知,重塑张量的最佳方法是使用einops. 它通过提供简单而优雅的功能解决了各种重塑问题。在您的情况下,代码可以写成

from einops import rearrange
ans = rearrange(tensor,'h -> 1 h')

我强烈建议您尝试一下。

顺便说一句,您可以将它与 pytorch/tensorflow/numpy 和许多其他库一起使用。

于 2021-04-07T11:52:04.397 回答
0
import torch
t = torch.ones((2, 3, 4))
t.size()
>>torch.Size([2, 3, 4])
a = t.view(-1,t.size()[1]*t.size()[2])
a.size()
>>torch.Size([2, 12])
于 2020-03-02T16:27:14.843 回答
0

假设以下代码:

import torch
import numpy as np
a = torch.tensor([1, 2, 3, 4, 5])

以下三个调用具有完全相同的效果:

res_1 = a.unsqueeze(0)
res_2 = a.view(1, 5)
res_3 = a[np.newaxis,:]
res_1.shape == res_2.shape == res_3.shape == (1,5)  # Returns true

请注意,对于任何生成的张量,如果您修改其中的数据,您也在修改 a 中的数据,因为它们没有数据的副本,而是引用 a 中的原始数据。

res_1[0,0] = 2
a[0] == res_1[0,0] == 2  # Returns true

另一种方法是使用resize_就地操作:

a.shape == res_1.shape  # Returns false
a.reshape_((1, 5))
a.shape == res_1.shape # Returns true

小心使用resize_或其他就地操作autograd。请参阅以下讨论:https ://pytorch.org/docs/stable/notes/autograd.html#in-place-operations-with-autograd

于 2019-01-17T19:20:16.780 回答