Python Pyrotch重塑张量维数

Python Pyrotch重塑张量维数,python,numpy,deep-learning,pytorch,tensor,Python,Numpy,Deep Learning,Pytorch,Tensor,例如,我有维度为(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]]

例如,我有维度为(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张量(和变量)做到这一点呢。我不想切换回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)。 如何在不丢失梯度信息的情况下调整变量中pytorch张量的大小或形状。(因为我将在后退之前输入另一个模型)

您可以使用

a.view(1,5)
Out: 

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


或者可以使用“-1”表示不必指定元素的数量

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

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

这个问题已经得到了彻底的回答,但我想为经验较少的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)
对于张量形状的就地修改,应该使用 :

在PyTorch中,如果一个操作(如
tensor.resize()
)的末尾有一个下划线,则该操作会对原始的tensor进行
修改

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

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

此外,您可以在torch张量中简单地使用
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])

假设以下代码:

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
另一种方法是使用
调整大小
就地操作:

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

小心使用
调整大小
或使用
自动加载
的其他就地操作。请参阅以下讨论:

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

让我们从二维
2x3
张量开始:

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

<强>为了对这个问题增加一些稳健性,让我们在前面加上一个新的维度并在中间添加另一个维度来修改<代码> 2×3 张量,产生一个<代码> 1×2 x 1 x 3 < /代码>张量。< /强>

方法1:添加
None
可以在任何地方使用NumPy样式。看

方法2:无问题 使用(也称为a.a.或就地版本
unsqueze(
)在第i个维度添加新维度。返回的张量与原始张量共享相同的数据。在本例中,我们可以使用
unqueze()
两次来添加两个新维度

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的实践中,这可能很重要,因此您可能经常看到
unsqueze(0)

方法3:观点 用于指定所有尺寸。返回的张量与原始张量共享相同的数据

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

y = x.view(1, 2, 1, 3)
print(y.shape)
# torch.Size([1, 2, 1, 3])
方法4:重塑 使用(aka)指定所有尺寸。如果原始数据是连续的并且具有相同的步长,则返回的张量将是输入视图(共享相同的数据),否则它将是副本。此函数与NumPy函数类似,它允许您定义所有尺寸,并可以返回视图或副本

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

y = x.reshape(1, 2, 1, 3)
print(y.shape)
# torch.Size([1, 2, 1, 3])
此外,在奥雷利2019年的书中,作者写道:

现在,您可能想知道
view()
重塑()
之间有什么区别。答案是
view()。但是,如果所需的视图不连续,
view()
会抛出错误;也就是说,如果从头开始创建所需形状的新张量,它将不会共享相同的内存块。如果发生这种情况,必须先调用
tensor.continuous()
,然后才能使用
view()
。但是,
restrape()
会在幕后完成所有这些工作,因此一般来说,我建议使用
restrape()
而不是
view()

方法5:调整大小_ 使用在位函数修改原始张量。文件规定:

警告。这是一种低级方法。存储被重新解释为C-连续,忽略当前步长(除非目标大小等于当前大小,在这种情况下,张量保持不变)。在大多数情况下,您会希望使用检查连续性的
view()
,或者如果需要,使用复制数据的
restrape()
。要使用自定义步幅在适当位置更改大小,请参见
设置()

我的观察 如果只想添加一个维度(例如,为批次添加第0个维度),则使用
取消查询(0)
。如果要完全更改维度,请使用
重塑()

另见:

是用来复制这个方法的

它位于and之后,位于
dir(火炬)
包中

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)
输出:

但是你知道它也可以作为和的替代品吗

输出:


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

从einops导入重新排列
ans=重新排列(张量,'h->1h')
我强烈建议你试试

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

注意,这不会修改原始的tensor
a
。它只是创建了一个视图。您声明另一种方法是使用resize_uuu.in-place操作,但您的代码使用
重塑
print(x.shape)
# torch.Size([2, 3])

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

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

x.resize_(1, 2, 1, 3)
print(x.shape)
# torch.Size([1, 2, 1, 3])
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])
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])
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])