.view()对x张量有什么作用?负值是什么意思?
x = x.view(-1, 16 * 5 * 5)
.view()对x张量有什么作用?负值是什么意思?
x = x.view(-1, 16 * 5 * 5)
当前回答
参数-1是什么意思?
您可以将-1读取为动态参数数或“任何东西”。因此,在view()中只能有一个参数-1。
如果你问x.view(-1,1),这将输出张量形状[任何东西,1]取决于x中的元素数量。例如:
import torch
x = torch.tensor([1, 2, 3, 4])
print(x,x.shape)
print("...")
print(x.view(-1,1), x.view(-1,1).shape)
print(x.view(1,-1), x.view(1,-1).shape)
将输出:
tensor([1, 2, 3, 4]) torch.Size([4])
...
tensor([[1],
[2],
[3],
[4]]) torch.Size([4, 1])
tensor([[1, 2, 3, 4]]) torch.Size([1, 4])
其他回答
让我们通过下面的例子来理解view:
a=torch.range(1,16)
print(a)
tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14.,
15., 16.])
print(a.view(-1,2))
tensor([[ 1., 2.],
[ 3., 4.],
[ 5., 6.],
[ 7., 8.],
[ 9., 10.],
[11., 12.],
[13., 14.],
[15., 16.]])
print(a.view(2,-1,4)) #3d tensor
tensor([[[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.]],
[[ 9., 10., 11., 12.],
[13., 14., 15., 16.]]])
print(a.view(2,-1,2))
tensor([[[ 1., 2.],
[ 3., 4.],
[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.],
[13., 14.],
[15., 16.]]])
print(a.view(4,-1,2))
tensor([[[ 1., 2.],
[ 3., 4.]],
[[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.]],
[[13., 14.],
[15., 16.]]])
-1作为参数值是计算x值的一种简单方法,前提是我们知道y和z的值,反之亦然,对于3d和2d,同样是计算x值的一种简单方法,前提是我们知道y的值,反之亦然。
torch.Tensor.view ()
简单地说,torch.Tensor.view()受到numpy.ndarray.重塑()或numpy.重塑()的启发,只要新形状与原始张量的形状兼容,就会创建一个新的张量视图。
让我们通过一个具体的例子来详细理解这一点。
In [43]: t = torch.arange(18)
In [44]: t
Out[44]:
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
使用这个张量t of shape(18,),只能为以下形状创建新的视图:
(1,18)或等效的(1,1)或(- 1,18) (2,9)或等效的(2,1)或(1,9) (3,6)或等效的(3,1)或(1,6) (6,3)或等效的(6,1)或(1,3) (9,2)或等效的(9,1)或(1,2) (18,1)或等效的(18,-1)或(- 1,1)
正如我们已经从上面的形状元组中观察到的,形状元组元素的乘法(例如2* 9,3 *6等)必须总是等于原始张量中元素的总数(在我们的例子中是18)。
另一件需要注意的事情是,我们在每个形状元组的其中一个地方使用了-1。通过使用-1,我们在自己进行计算时显得懒惰,而是将任务委托给PyTorch,在它创建新视图时为形状计算该值。需要注意的一件重要的事情是,我们只能在形状tuple中使用一个-1。其余的值应该由我们显式提供。否则PyTorch将通过抛出RuntimeError来投诉:
RuntimeError:只能推断一个维度
因此,对于上面提到的所有形状,PyTorch总是会返回原始张量t的一个新视图。这基本上意味着它只是为每个被请求的新视图改变张量的步幅信息。
下面是一些例子,说明张量的步幅是如何随着每个新视图而改变的。
# stride of our original tensor `t`
In [53]: t.stride()
Out[53]: (1,)
现在,我们将看到新观点的进展:
# shape (1, 18)
In [54]: t1 = t.view(1, -1)
# stride tensor `t1` with shape (1, 18)
In [55]: t1.stride()
Out[55]: (18, 1)
# shape (2, 9)
In [56]: t2 = t.view(2, -1)
# stride of tensor `t2` with shape (2, 9)
In [57]: t2.stride()
Out[57]: (9, 1)
# shape (3, 6)
In [59]: t3 = t.view(3, -1)
# stride of tensor `t3` with shape (3, 6)
In [60]: t3.stride()
Out[60]: (6, 1)
# shape (6, 3)
In [62]: t4 = t.view(6,-1)
# stride of tensor `t4` with shape (6, 3)
In [63]: t4.stride()
Out[63]: (3, 1)
# shape (9, 2)
In [65]: t5 = t.view(9, -1)
# stride of tensor `t5` with shape (9, 2)
In [66]: t5.stride()
Out[66]: (2, 1)
# shape (18, 1)
In [68]: t6 = t.view(18, -1)
# stride of tensor `t6` with shape (18, 1)
In [69]: t6.stride()
Out[69]: (1, 1)
这就是view()函数的神奇之处。它只是改变了每个新视图的(原始)张量的步幅,只要新视图的形状与原始形状兼容。
从strides元组可以观察到的另一件有趣的事情是,第0个位置的元素的值等于shape元组第1个位置的元素的值。
In [74]: t3.shape
Out[74]: torch.Size([3, 6])
|
In [75]: t3.stride() |
Out[75]: (6, 1) |
|_____________|
这是因为:
In [76]: t3
Out[76]:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
stride(6,1)表示沿着第0维从一个元素到下一个元素,我们必须跳跃或走6步。(即从0到6,要走6步。)但是在第一维中,从一个元素到下一个元素,我们只需要一步(例如从2到3)。
因此,步长信息是如何从内存中访问元素以执行计算的核心。
torch.reshape ()
这个函数将返回一个视图,并且与使用torch.Tensor.view()完全相同,只要新形状与原始张量的形状兼容。否则,它将返回一个副本。
然而,torch.重塑()的注释警告:
连续的输入和具有兼容步长的输入可以在不复制的情况下进行重塑,但是不应该依赖于复制与查看行为。
我真的很喜欢@Jadiel de Armas的例子。
我想添加一个关于.view(…)元素如何排序的小见解。
对于形状为(a,b,c)的张量,其元素的顺序为 由编号系统确定:其中第一个数字有 数字,第二个数字是b,第三个数字是c。 由.view(…)返回的新张量中元素的映射 保持原始张量的阶数。
参数-1是什么意思?
您可以将-1读取为动态参数数或“任何东西”。因此,在view()中只能有一个参数-1。
如果你问x.view(-1,1),这将输出张量形状[任何东西,1]取决于x中的元素数量。例如:
import torch
x = torch.tensor([1, 2, 3, 4])
print(x,x.shape)
print("...")
print(x.view(-1,1), x.view(-1,1).shape)
print(x.view(1,-1), x.view(1,-1).shape)
将输出:
tensor([1, 2, 3, 4]) torch.Size([4])
...
tensor([[1],
[2],
[3],
[4]]) torch.Size([4, 1])
tensor([[1, 2, 3, 4]]) torch.Size([1, 4])
View()通过“拉伸”或“挤压”张量的元素来重新塑造你指定的形状:
view()如何工作?
首先让我们看看什么是张量:
Tensor and its underlying storage |
e.g. the right-hand tensor (shape (3,2)) can be computed from the left-hand one with t2 = t1.view(3,2) |
在这里你可以看到PyTorch通过添加shape和stride属性将底层的连续内存块转换为类似矩阵的对象来创建一个张量:
形状表示每个维度的长度 Stride表示在到达每个维度的下一个元素之前需要在内存中执行多少步
View (dim1,dim2,…)返回相同底层信息的视图,但被重新塑造为形状为dim1 x dim2 x…(通过修改形状和stride属性)。
注意,这隐含地假设新维和旧维有相同的乘积(即旧张量和新张量有相同的体积)。
PyTorch -1
-1是PyTorch的别名,表示“在其他维度都已指定的情况下推断该维度”(即原产品与新产品的商)。这是一个来自numpy.重塑()的约定。
因此,本例中的t1.view(3,2)将等效于t1.view(3,-1)或t1.view(-1,2)。