lyn*_*ynn 6 python memory numpy
我想在Python中创建一个空的Numpy数组,以便稍后用值填充它.下面的代码生成一个1024 x 1024 x 1024的数组,其中包含2个字节的整数,这意味着它至少需要2 GB的RAM.
>>> import numpy as np; from sys import getsizeof
>>> A = np.zeros((1024,1024,1024), dtype=np.int16)
>>> getsizeof(A)
2147483776
从中getsizeof(A),我们看到数组需要2 ^ 31 + 128个字节(大概是头信息.)然而,使用我的任务管理器,我可以看到Python只占用了18.7 MiB的内存.
假设阵列被压缩,我将随机值分配给每个内存插槽,以便它不能.
>>> for i in range(1024):
...   for j in range(1024):
...     for k in range(1024):
...         A[i,j,k] = np.random.randint(32767, dtype = np.int16)
循环仍在运行,我的RAM正在缓慢增加(大概是由于组成A的数组充满了无法压缩的噪声.)我假设它会使我的代码更快,迫使numpy从头开始扩展这个数组.奇怪的是,我没有在任何地方看到这个记录!
所以,1.为什么numpy这样做?2.如何强制numpy分配内存?
让我们看一下较小案例的一些时序:
\n\nIn [107]: A = np.zeros(10000,int)\nIn [108]: for i in range(A.shape[0]): A[i]=np.random.randint(327676)\n我们不需要制作A3d来获得同样的效果;总大小相同的 1d 也同样好。
In [109]: timeit for i in range(A.shape[0]): A[i]=np.random.randint(327676)\n37 ms \xc2\xb1 133 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n现在将该时间与通过一次调用生成随机数的替代方法进行比较:
\n\nIn [110]: timeit np.random.randint(327676, size=A.shape)\n185 \xc2\xb5s \xc2\xb1 905 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000 loops each)\n快得多。
\n\n如果我们执行相同的循环,但只是将随机数分配给一个变量(然后将其丢弃):
\n\nIn [111]: timeit for i in range(A.shape[0]): x=np.random.randint(327676)\n32.3 ms \xc2\xb1 171 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n时间几乎与原始情况相同。将值分配给zeros数组并不需要花费大量时间。
我没有像你一样测试一个非常大的案例,并且我的案例A已经完全初始化。因此,欢迎您重复与您的尺寸进行比较。但我认为该模式仍然成立 - 迭代 1024x1024x1024 次(比我的示例大 100,000 次)是大量时间消耗,而不是内存分配任务。
您可能会尝试其他方法:只需迭代 的第一个维度A,并randomint像其他两个维度一样分配形状。例如,将 my 扩展A为 10 维:
In [112]: A = np.zeros((10,10000),int)\nIn [113]: timeit for i in range(A.shape[0]): A[i]=np.random.randint(327676,size=A.shape[1])\n1.95 ms \xc2\xb1 31.7 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\nA比[107]大10倍,但填充时间减少16倍,因为它只迭代10倍。如果numpy必须迭代,请尝试在更复杂的任务上重复几次。
(timeit多次重复测试(例如 7*10),因此它不会捕获任何初始内存分配步骤,即使我使用足够大的数组来实现这一点)。