Was*_*mad 144 python memory torch pytorch tensor
我view()对以下代码片段中的方法感到困惑.
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2,2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16*5*5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
Run Code Online (Sandbox Code Playgroud)
我的困惑在于以下几行.
x = x.view(-1, 16*5*5)
Run Code Online (Sandbox Code Playgroud)
tensor.view()功能有什么作用?我已经在许多地方看到了它的用法,但我无法理解它如何解释它的参数.
如果我将负值作为参数给view()函数会发生什么?例如,如果我打电话会发生什么tensor_variable.view(1, 1, -1)?
任何人都可以view()通过一些例子解释功能的主要原理吗?
Kas*_*yap 208
视图函数旨在重塑张量.
说你有一个张量
import torch
a = torch.range(1, 16)
Run Code Online (Sandbox Code Playgroud)
a是一个张量,有16个元素从1到16(包括).如果你想重塑这个张量使其成为一个4 x 4张量,那么你可以使用
a = a.view(4, 4)
Run Code Online (Sandbox Code Playgroud)
现在a将是一个4 x 4张量.请注意,在重新整形后,元素的总数需要保持不变.重塑张a到3 x 5张量是不恰当的.
如果有任何情况你不知道你想要多少行,但确定列数,那么你可以用-1指定它.(请注意,您可以将其扩展到具有更多尺寸的张量.只有一个轴值可以为-1).这是告诉库的一种方式:"给我一个具有这么多列的张量,并计算实现这一点所需的适当行数".
这可以在您上面给出的神经网络代码中看到.x = self.pool(F.relu(self.conv2(x)))在前向功能中的行之后,您将拥有一个16深度的特征映射.您必须将其展平以将其提供给完全连接的图层.因此,您告诉pytorch重新构造您获得的具有特定列数的张量,并告诉它自己决定行数.
在numpy和pytorch之间绘制相似性,view类似于numpy的重塑功能.
Jad*_*mas 26
让我们举一些例子,从简单到更难.
该view方法返回张量与张量具有相同数据的self张量(这意味着返回的张量具有相同数量的元素),但具有不同的形状.例如:
a = torch.arange(1, 17) # a's shape is (16,)
a.view(4, 4) # output below
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
[torch.FloatTensor of size 4x4]
a.view(2, 2, 4) # output below
(0 ,.,.) =
1 2 3 4
5 6 7 8
(1 ,.,.) =
9 10 11 12
13 14 15 16
[torch.FloatTensor of size 2x2x4]
Run Code Online (Sandbox Code Playgroud)假设这-1不是其中一个参数,当您将它们相乘时,结果必须等于张量中的元素数.如果你这样做:a.view(3, 3),它将引发一个RuntimeError因为形状(3 x 3)对于16个元素的输入无效.换句话说:3 x 3不等于16但是9.
您可以将其-1作为传递给函数的参数之一,但只能使用一次.所有发生的事情是该方法将为您填写关于如何填充该维度的数学.例如a.view(2, -1, 4)相当于a.view(2, 2, 4).[16 /(2 x 4)= 2]
请注意,返回的张量共享相同的数据.如果您在"视图"中进行更改,则会更改原始张量的数据:
b = a.view(4, 4)
b[0, 2] = 2
a[2] == 3.0
False
Run Code Online (Sandbox Code Playgroud)现在,对于更复杂的用例.文档说每个新的视图维度必须是原始维度的子空间,或者只是跨越d,d + 1,...,d + k,它们满足以下所有i = 0的类似条件的条件. ..,k - 1,stride [i] = stride [i + 1] x size [i + 1].否则,contiguous()需要在可以查看张量之前调用.例如:
a = torch.rand(5, 4, 3, 2) # size (5, 4, 3, 2)
a_t = a.permute(0, 2, 3, 1) # size (5, 3, 2, 4)
# The commented line below will raise a RuntimeError, because one dimension
# spans across two contiguous subspaces
# a_t.view(-1, 4)
# instead do:
a_t.contiguous().view(-1, 4)
# To see why the first one does not work and the second does,
# compare a.stride() and a_t.stride()
a.stride() # (24, 6, 2, 1)
a_t.stride() # (24, 2, 1, 6)
Run Code Online (Sandbox Code Playgroud)
请注意,对于a_t,stride [0]!= stride [1] x size [1],因为24!= 2 x 3
uke*_*emi 21
view() 通过“拉伸”或“挤压”张量的元素到你指定的形状来重塑张量:
view()工作?首先让我们看看引擎盖下的张量是什么:
在这里,您可以看到 PyTorch 通过添加 ashape和stride属性将底层连续内存块转换为类似矩阵的对象来生成张量:
shape 说明每个维度的长度stride 说明在到达每个维度中的下一个元素之前您需要在内存中采取多少步骤
view(dim1,dim2,...)返回相同基础信息的视图,但重新整形为形状张量dim1 x dim2 x ...(通过修改shape和stride属性)。
请注意,这隐含地假设新旧维度具有相同的乘积(即旧张量和新张量具有相同的体积)。
-1是 PyTorch 的别名,用于“在其他都已指定的情况下推断此维度”(即原始产品与新产品的商)。它是从numpy.reshape().
因此,t1.view(3,2)在我们的示例中将等价于t1.view(3,-1)or t1.view(-1,2)。
kma*_*o23 14
torch.Tensor.view()简单地说,torch.Tensor.view()受numpy.ndarray.reshape()or 的启发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])
Run Code Online (Sandbox Code Playgroud)
有了这个张量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:
运行时错误:只能推断一维
因此,对于上述所有形状,PyTorch 将始终返回原始张量的新视图t。这基本上意味着它只是为请求的每个新视图更改张量的步幅信息。
下面是一些示例,说明每个新视图如何更改张量的步幅。
# stride of our original tensor `t`
In [53]: t.stride()
Out[53]: (1,)
Run Code Online (Sandbox Code Playgroud)
现在,我们将看到新视图的进展:
# 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)
Run Code Online (Sandbox Code Playgroud)
这就是view()函数的神奇之处。它只是改变(原始)张量为每个新的进步的观点,只要新的形状视图是与原来的形状相容。
另一个有趣的事情一个可能会从步幅元组观察的是,在0的元素的值个位置是等于1个的元素的值ST形状元组位置。
In [74]: t3.shape
Out[74]: torch.Size([3, 6])
|
In [75]: t3.stride() |
Out[75]: (6, 1) |
|_____________|
Run Code Online (Sandbox Code Playgroud)
这是因为:
In [76]: t3
Out[76]:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
Run Code Online (Sandbox Code Playgroud)
步幅(6, 1)说,从一个元素到下一个元素沿0个维度,我们要跳或采取6个步骤。(即从去0到6,人们必须采取6个步骤。)但是,从一个元素去的1个一个元素ST层面,我们只需要只差一步(例如,用于从去2到3)。
因此,步幅信息是如何从内存访问元素以执行计算的核心。
只要新形状与原始张量的形状兼容,此函数将返回一个视图,并且与 using 完全相同torch.Tensor.view()。否则,它将返回一个副本。
但是,注释torch.reshape()警告说:
连续输入和具有兼容步幅的输入可以在不复制的情况下进行重塑,但不应依赖于复制与查看行为。
小智 5
让我们尝试通过以下示例来理解视图:
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.]]])
Run Code Online (Sandbox Code Playgroud)
-1 作为参数值是计算 x 的值的简单方法,前提是我们知道 y、z 的值,或者在 3d 的情况下反之亦然,对于 2d 来说,也是计算 x 的值的简单方法,前提是我们知道知道 y 的值,反之亦然。
| 归档时间: |
|
| 查看次数: |
93652 次 |
| 最近记录: |