例如,我有一维带维(5)的向量。我想将其重塑为2D矩阵(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 Tensor(和Variable)做到这一点。我不想切换回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)。 如何在不丢失梯度信息的情况下调整变量张量的大小或重新整形。 (因为我会在向后进入另一个模型)
答案 0 :(得分:17)
使用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]
答案 1 :(得分:14)
你可以使用
a.view(1,5)
Out:
1 2 3 4 5
[torch.FloatTensor of size 1x5]
答案 2 :(得分:7)
对于张量的就地修改,你绝对应该使用 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
修改。
此外,您只需在手电筒Tensor中使用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])
答案 3 :(得分:5)
有多种重塑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
张量。
None
添加维度在任何需要的地方使用NumPy样式的insertion of None
(aka np.newaxis
) to add dimensions。参见here。
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])
使用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的实践中,adding an extra dimension for the batch可能很重要,因此您可能经常会看到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)
(又名torch.reshape(tensor, shapetuple)
)指定所有尺寸。如果原始数据是连续的并且具有相同的步幅,则返回的张量将是输入视图(共享相同的数据),否则将是副本。此函数与NumPy reshape()
函数的相似之处在于,它使您可以定义所有尺寸,并可以返回视图或副本。
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()
。
使用就地函数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()
。
What's the difference between reshape and view in pytorch?
What is the difference between view() and unsqueeze()?
In PyTorch 0.4, is it recommended to use reshape
than view
when it is possible?
答案 4 :(得分:4)
或者您可以使用它,' - 1表示您不必指定元素的数量。
In [3]: a.view(1,-1)
Out[3]:
1 2 3 4 5
[torch.FloatTensor of size 1x5]
答案 5 :(得分:4)
这个问题已经得到了彻底的解答,但是我想为经验较少的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)
答案 6 :(得分: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'
答案 7 :(得分:1)
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])
答案 8 :(得分:1)
据我所知,重塑张量的最佳方法是使用 einops
。它通过提供简单而优雅的功能解决了各种重塑问题。在你的情况下,代码可以写成
from einops import rearrange
ans = rearrange(tensor,'h -> 1 h')
我强烈建议您尝试一下。
顺便说一句,您可以将它与 pytorch/tensorflow/numpy 和许多其他库一起使用。
答案 9 :(得分: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中的原始数据。 / p>
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
答案 10 :(得分: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])