运行一些操作可能会导致为新结果分配内存。 例如,如果我们用Y = X + Y,我们将取消引用Y指向的张量,而是指向新分配的内存处的张量。
在下面的例子中,我们用Python的id()函数演示了这一点, 它给我们提供了内存中引用对象的确切地址。 运行Y = Y + X后,我们会发现id(Y)指向另一个位置。 这是因为Python首先计算Y + X,为结果分配新的内存,然后使Y指向内存中的这个新位置。
before = id(Y)
Y = Y + X
id(Y) == before
False
这可能是不可取的,原因有两个:
首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;
如果我们不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。
幸运的是,执行原地操作非常简单。 我们可以使用切片表示法将操作的结果分配给先前分配的数组,例如Y[:] = 。 为了说明这一点,我们首先创建一个新的矩阵Z,其形状与另一个Y相同, 使用zeros_like来分配一个全0的块。
Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))
id(Z): 139931132035296
id(Z): 139931132035296
如果在后续计算中没有重复使用X, 我们也可以使用X[:] = X + Y或X += Y来减少操作的内存开销。
before = id(X)
X += Y
id(X) == before
True
将深度学习框架定义的张量转换为NumPy张量(ndarray)很容易,反之也同样容易。
numpy()函数处理后torch张量和numpy数组将共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量。 torch.tensor()会创建一个新的tensor
X = torch.arange(12)
A = X.numpy()
B = torch.tensor(A)
X, A, B
type(A), type(B)
A[1] = 12
B[3] = 12
X[5] = 12
X, A, B
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
[ 0 1 2 3 4 5 6 7 8 9 10 11]
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
<class ‘numpy.ndarray’> <class ‘torch.Tensor’>
tensor([ 0, 12, 2, 3, 4, 12, 6, 7, 8, 9, 10, 11])
[ 0 12 2 3 4 12 6 7 8 9 10 11]
tensor([ 0, 1, 2, 12, 4, 5, 6, 7, 8, 9, 10, 11])
要将大小为1的张量转换为Python标量,我们可以调用item函数或Python的内置函数。
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3)