节省内存
运行一些操作可能会导致为新结果分配内存。 例如,如果我们用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[:] = <expression>
。 为了说明这一点,我们首先创建一个新的矩阵Z
,其形状与另一个Y
相同, 使用zeros_like
来分配一个全\(0\)的块。
Z = np.zeros_like(Y) print('id(Z):', id(Z)) Z[:] = X + Y print('id(Z):', id(Z))
id(Z): 139652460377600 id(Z): 139652460377600
如果在后续计算中没有重复使用X
, 我们也可以使用X[:] = X + Y
或X += Y
来减少操作的内存开销。
before = id(X) X += Y id(X) == before
True
转换为其他Python对象
将深度学习框架定义的张量转换为NumPy张量(ndarray
)很容易,反之也同样容易。 转换后的结果不共享内存。 这个小的不便实际上是非常重要的:当你在CPU或GPU上执行操作的时候, 如果Python的NumPy包也希望使用相同的内存块执行其他操作,你不希望停下计算来等它。
A = X.asnumpy() B = np.array(A) type(A), type(B)
(numpy.ndarray, mxnet.numpy.ndarray)
要将大小为1的张量转换为Python标量,我们可以调用item
函数或Python的内置函数。
a = np.array([3.5]) a, a.item(), float(a), int(a)
(array([3.5]), 3.5, 3.5, 3)