Python Pytorch 重塑张量维度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43328632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 22:53:44  来源:igfitidea点击:

Pytorch reshape tensor dimension

pythonnumpydeep-learningpytorchtensor

提问by Haha TTpro

For example, I have 1D vector with dimension (5). I would like to reshape it into 2D matrix (1,5).

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

Here is how I do it with numpy

这是我如何使用 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]])
>>> 

But how can I do that with Pytorch Tensor (and Variable). I don't want to switch back to numpy and switch to Torch variable again, because it will loss backpropagation information.

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

Here is what I have in Pytorch

这是我在 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,)

Now I want it size to be (1, 5). How can I resize or reshape the dimension of pytorch tensor in Variable without loss grad information. (because I will feed into another model before backward)

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

采纳答案by Haha TTpro

Use torch.unsqueeze(input, dim, out=None)

使用 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]

回答by Lelik

you might use

你可能会用

a.view(1,5)
Out: 

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

回答by kmario23

For in-placemodification of the shape of the tensor, you should use tensor.resize_():

对于张量形状的就地修改,您应该使用 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])

In PyTorch, if there's an underscore at the end of an operation (like tensor.resize_()) then that operation does in-placemodification to the original tensor.

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



Also, you can simply use np.newaxisin a torch Tensor to increase the dimension. Here is an example:

此外,您可以简单地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])

回答by Mou Cai

or you can use this, the '-1' means you don't have to specify the number of the elements.

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

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

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

回答by saetch_g

This question has been thoroughly answered already, but I want to add for the less experienced python developers that you might find the *operator helpful in conjunction with view().

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

For example if you have a particular tensor size that you want a different tensor of data to conform to, you might try:

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

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)

This works with numpy shapetoo:

这也适用于 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)

回答by stackoverflowuser2010

There are multiple ways of reshaping a PyTorch tensor. You can apply these methods on a tensor of any dimensionality.

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

Let's start with a 2-dimensional 2 x 3tensor:

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

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

To add some robustness to this problem, let's reshape the 2 x 3tensor by adding a new dimension at the front and another dimension in the middle, producing a 1 x 2 x 1 x 3tensor.

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

Approach 1: add dimension with None

方法 1:添加维度 None

Use NumPy-style insertion of None(aka np.newaxis) to add dimensionsanywhere you want. See here.

使用 NumPy 样式None(aka np.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])

Approach 2: unsqueeze

方法二:解压

Use torch.Tensor.unsqueeze(i)(a.k.a. torch.unsqueeze(tensor, i)or the in-place version unsqueeze_()) to add a new dimension at the i'th dimension. The returned tensor shares the same data as the original tensor. In this example, we can use unqueeze()twice to add the two new dimensions.

使用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])

In practice with PyTorch, adding an extra dimension for the batchmay be important, so you may often see unsqueeze(0).

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

Approach 3: view

方法三:查看

Use torch.Tensor.view(*shape)to specify all the dimensions. The returned tensor shares the same data as the original tensor.

使用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])

Approach 4: reshape

方法四:重塑

Use torch.Tensor.reshape(*shape)(aka torch.reshape(tensor, shapetuple)) to specify all the dimensions. If the original data is contiguous and has the same stride, the returned tensor will be a view of input (sharing the same data), otherwise it will be a copy. This function is similar to the NumPy reshape()function in that it lets you define all the dimensions and can return either a view or a copy.

使用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])

Furthermore, from the O'Reilly 2019 book Programming PyTorch for Deep Learning, the author writes:

此外,作者在 O'Reilly 2019 年的《Programming PyTorch for Deep Learning》一书中写道:

Now you might wonder what the difference is between view()and reshape(). The answer is that view()operates as a view on the original tensor, so if the underlying data is changed, the view will change too (and vice versa). However, view()can throw errors if the required view is not contiguous; that is, it doesn't share the same block of memory it would occupy if a new tensor of the required shape was created from scratch. If this happens, you have to call tensor.contiguous()before you can use view(). However, reshape()does all that behind the scenes, so in general, I recommend using reshape()rather than view().

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

Approach 5: resize_

方法五:调整大小_

Use the in-place function torch.Tensor.resize_(*sizes)to modify the original tensor. The documentation states:

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

WARNING. This is a low-level method. The storage is reinterpreted as C-contiguous, ignoring the current strides (unless the target size equals the current size, in which case the tensor is left unchanged). For most purposes, you will instead want to use view(), which checks for contiguity, or reshape(), which copies data if needed. To change the size in-place with custom strides, see set_().

警告。这是一种低级方法。存储被重新解释为 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])

My observations

我的观察

If you want to add just one dimension (e.g. to add a 0th dimension for the batch), then use unsqueeze(0). If you want to totally change the dimensionality, use reshape().

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

See also:

也可以看看:

What's the difference between reshape and view in pytorch?

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

What is the difference between view() and unsqueeze()?

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

In PyTorch 0.4, is it recommended to use reshapethan viewwhen it is possible?

在 PyTorch 0.4 中,是否推荐使用reshapeview可能的时候?

回答by hindamosh

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'

回答by Jadiel de Armas

Assume the following code:

假设以下代码:

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

The following three calls have the exact same effect:

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

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

Notice that for any of the resulting tensors, if you modify the data in them, you are also modifying the data in a, because they don't have a copy of the data, but reference the original data in a.

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

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

The other way of doing it would be using the resize_in place operation:

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

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

Be careful of using resize_or other in-place operation with autograd. See the following discussion: https://pytorch.org/docs/stable/notes/autograd.html#in-place-operations-with-autograd

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

回答by Kamran Abdi

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])