正如问题所说,
-1
的view()
在PyTorch中做什么?
>>> a = torch.arange(1, 17)
>>> a
tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
11., 12., 13., 14., 15., 16.])
>>> a.view(1,-1)
tensor([[ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
11., 12., 13., 14., 15., 16.]])
>>> a.view(-1,1)
tensor([[ 1.],
[ 2.],
[ 3.],
[ 4.],
[ 5.],
[ 6.],
[ 7.],
[ 8.],
[ 9.],
[ 10.],
[ 11.],
[ 12.],
[ 13.],
[ 14.],
[ 15.],
[ 16.]])
PyTorch 中
-1
的 view()
是否会生成额外维度?
PyTorch 中 -1
的 view()
与 NumPy 中 -1
的 reshape()
的行为是否相同?
是的,它的行为确实类似于
-1
中的 numpy.reshape()
,即,将推断该维度的实际值,以便视图中的元素数量与原始元素数量相匹配。
例如:
import torch
x = torch.arange(6)
print(x.view(3, -1)) # inferred size will be 2 as 6 / 3 = 2
# tensor([[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]])
print(x.view(-1, 6)) # inferred size will be 1 as 6 / 6 = 1
# tensor([[ 0., 1., 2., 3., 4., 5.]])
print(x.view(1, -1, 2)) # inferred size will be 3 as 6 / (1 * 2) = 3
# tensor([[[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]]])
# print(x.view(-1, 5)) # throw error as there's no int N so that 5 * N = 6
# RuntimeError: invalid argument 2: size '[-1 x 5]' is invalid for input with 6 elements
print(x.view(-1, -1, 3)) # throw error as only one dimension can be inferred
# RuntimeError: invalid argument 1: only one dimension can be inferred
我喜欢本杰明给出的答案https://stackoverflow.com/a/50793899/1601580
是的,它的行为确实类似于 numpy.reshape() 中的 -1,即将推断该维度的实际值,以便视图中的元素数量与原始元素数量相匹配。
但我认为奇怪的边缘情况对你来说可能不直观(或者至少对我来说不是),那就是用单个 -1 来调用它,即
tensor.view(-1)
。
我的猜测是,它的工作方式与往常完全相同,只是因为您给出一个数字来查看,所以它假设您想要一个维度。如果您有tensor.view(-1, Dnew)
,它将产生一个二维/索引的张量,但是将根据张量的原始尺寸确保第一个尺寸具有正确的尺寸。假设您有 (D1, D2)
您有 Dnew=D1*D2
那么新维度将为 1。
对于带有代码的实际示例,您可以运行:
import torch
x = torch.randn(1, 5)
x = x.view(-1)
print(x.size())
x = torch.randn(2, 4)
x = x.view(-1, 8)
print(x.size())
x = torch.randn(2, 4)
x = x.view(-1)
print(x.size())
x = torch.randn(2, 4, 3)
x = x.view(-1)
print(x.size())
输出:
torch.Size([5])
torch.Size([1, 8])
torch.Size([8])
torch.Size([24])
我觉得这是一个很好的例子(早期在pytorch中常见的情况扁平化层是官方添加的就是这个常见的代码):
class Flatten(nn.Module):
def forward(self, input):
# input.size(0) usually denotes the batch size so we want to keep that
return input.view(input.size(0), -1)
用于顺序。在此视图中,
x.view(-1)
是一个奇怪的扁平层,但缺少挤压(即添加维度 1)。添加或删除此挤压通常对于代码的实际运行很重要。
如果您想知道
x.view(-1)
是什么,它会使向量变平。为什么?因为它必须构造一个只有 1 维的新视图并推断维数 - 所以它会将其展平。此外,此操作似乎避免了 .resize()
带来的非常讨厌的错误,因为元素的顺序似乎受到尊重。仅供参考,pytorch 现在有这个扁平化操作:https://pytorch.org/docs/stable/ generated/torch.flatten.html
#%%
"""
Summary: view(-1, ...) keeps the remaining dimensions as give and infers the -1 location such that it respects the
original view of the tensor. If it's only .view(-1) then it only has 1 dimension given all the previous ones so it ends
up flattening the tensor.
ref: my answer https://stackoverflow.com/a/66500823/1601580
"""
import torch
x = torch.arange(6)
print(x)
x = x.reshape(3, 2)
print(x)
print(x.view(-1))
输出
tensor([0, 1, 2, 3, 4, 5])
tensor([[0, 1],
[2, 3],
[4, 5]])
tensor([0, 1, 2, 3, 4, 5])
看到原始张量被返回了!
np.reshape
类似:
新形状应与原始形状兼容。如果是整数,则结果将是该长度的一维数组。一种形状尺寸可以是-1。在这种情况下,该值是根据数组的长度和剩余维度推断出来的。
如果您有
a = torch.arange(1, 18)
,您可以通过多种方式查看它,例如a.view(-1,6)
,a.view(-1,9)
,a.view(3,-1)
等
>>> x = torch.randn(4, 4)
>>> x.size()
torch.Size([4, 4])
>>> y = x.view(16)
>>> y.size()
torch.Size([16])
>>> z = x.view(-1, 8) # the size -1 is inferred from other dimensions
>>> z.size()
torch.Size([2, 8])
-1 推断为 2,例如,如果您有
>>> a = torch.rand(4,4)
>>> a.size()
torch.size([4,4])
>>> y = x.view(16)
>>> y.size()
torch.size([16])
>>> z = x.view(-1,8) # -1 is generally inferred as 2 i.e (2,8)
>>> z.size()
torch.size([2,8])
-1
是 PyTorch 的别名,表示“在其他维度均已指定的情况下推断此维度”(即原始乘积除以新乘积的商)。这是取自numpy.reshape()
的约定。
因此,示例中的
t.view(1,17)
相当于 t.view(1,-1)
或 t.view(-1,17)
。
将
-1
设置为view()的第一个数字可以自动调整形状,因此您无需将12
、2
、3
或6
设置为第一个数字,如下所示。 *-1 仅可用作第一个数字:
import torch
my_tensor = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
# The size is [4, 3].
my_tensor.view((12,))
my_tensor.view((-1,))
my_tensor.view(12)
my_tensor.view(-1)
# tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
# The size is [12].
my_tensor.view((2, 6))
my_tensor.view((-1, 6))
my_tensor.view(2, 6)
my_tensor.view(-1, 6)
# tensor([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]])
# The size is [2, 6].
my_tensor.view((3, 4))
my_tensor.view((-1, 4))
my_tensor.view(3, 4)
my_tensor.view(-1, 4)
# tensor([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]])
# The size is [3, 4].
my_tensor.view((6, 2))
my_tensor.view((-1, 2))
my_tensor.view(6, 2)
my_tensor.view(-1, 2)
# tensor([[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]])
# The size is [6, 2].