简而言之,torch.Tensor.view()
受numpy.ndarray.reshape()
或启发numpy.reshape()
,创建了一个新视图,只要新形状与原始张量的形状兼容张量。
让我们通过一个具体的例子来详细了解这一点。
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
的形状(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
在每个形状元组的一个位置中使用了a 。通过使用a -1
,我们懒于自己进行计算,而是将任务委托给PyTorch来在形状创建新视图时对该形状进行该值的计算。需要注意的重要一件事是,我们只能-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()
功能的魔力。它只是改变(原始)张量的步幅为每个新的观点,只要新的形状视图是与原来的形状相容。
从跨步元组可能会观察到的另一件有趣的事情是,在形状元组的第0 个位置的元素的值等于在形状元组的第一个位置的元素的值。
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]])
步幅(6, 1)
说,从一个元素到下一个元素沿0 个维度,我们要跳或采取6个步骤。(即从去0
到6
,人们必须采取6个步骤。)但是,从一个元素去的1个一个元素ST层面,我们只需要只差一步(例如,用于从去2
到3
)。
因此,步幅信息是如何从存储器访问元素以执行计算的核心。
此函数将返回一个视图,并且与使用完全相同torch.Tensor.view()
只要新形状与原始张量的形状兼容,与之。否则,它将返回一个副本。
但是,注意事项torch.reshape()
警告:
连续的输入和具有兼容步幅的输入可以在不复制的情况下进行重塑,但其中一个不应依赖于复制与查看行为。
reshape
在PyTorch中调用它呢?