使用大型Numpy阵列的技术?

Noo*_*bot 20 python arrays optimization memory-management numpy

有时您必须在一个或多个大型Numpy阵列上执行许多中间操作.这很快就会导致MemoryErrors.在我迄今为止的研究中,你发现Pickling(Pickle,CPickle,Pytables等)并且gc.collect()是减轻这种情况的方法.我想知道在处理大量数据时是否还有其他有经验的程序员使用的技术(当然,除了删除策略/代码中的冗余).

另外,如果有一点我确定没有什么是免费的.使用其中一些技术,有什么权衡(即速度,稳健性等)?

Jai*_*ime 22

我感觉到你的痛苦...你有时最终会以你后来丢弃的值存储数组大小的几倍.在一次处理数组中的一个项目时,这是无关紧要的,但在向量化时会杀死你.

我将使用工作中的示例进行说明.我最近用numpy 编写了这里描述的算法.它是一种彩色图算法,它采用RGB图像,并将其转换为CMYK图像.对每个像素重复的过程如下:

  1. 使用每个RGB值的最重要的4位作为三维查找表的索引.这确定了LUT内立方体的8个顶点的CMYK值.
  2. 根据前一步骤的顶点值,使用每个RGB值的最低4位在该多维数据集内插值.最有效的方法是计算16个uint8数组,其大小与正在处理的图像大小相同.对于24位RGB图像,相当于需要存储x6倍的图像来处理它.

你可以做几件事来处理这件事:

1.分而治之

也许你不能在一次通过中处理1,000x1,000阵列.但是如果你可以用python for循环迭代10个100x1,000的数组,那么它仍然会超过1,000,000个项目的python迭代器!它会变慢,是的,但不是那么多.

2.缓存昂贵的计算

这与我上面的插值示例直接相关,并且更难以遇到,尽管值得关注它.因为我在每个维度上有4位的三维立方体进行插值,所以只有16x16x16可能的结果,可以存储在16个16x16x16字节的数组中.所以我可以预先计算它们并使用64KB的内存来存储它们,并逐个查找整个图像的值,而不是以巨大的内存成本为每个像素重做相同的操作.这已经为小到64x64像素的图像付出了代价,并且基本上允许处理图像数量为x6倍的图像而无需细分数组.

3. dtypes明智地使用你

如果您的中间值可以适合单个uint8,请不要使用int32s 数组!由于无声溢出,这可能会变成神秘错误的噩梦,但如果你小心,它可以节省大量资源.


Ste*_*o M 9

第一个最重要的技巧:分配几个大数组,并使用和回收它们的一部分,而不是带来生命和丢弃/垃圾收集大量的临时数组.听起来有点过时,但仔细编程加速可能会令人印象深刻.(您可以更好地控制对齐和数据位置,因此可以提高数字代码的效率.)

第二:使用numpy.memmap并希望操作系统对磁盘的访问缓存足够高效.

第三:正如@Jaime所指出的那样,如果整个矩阵是大的,则工作un块子矩阵.

编辑:

如SE 中的答案所指出的那样,避免不必要的列表理解.


MRo*_*lin 5

所述dask.array库提供了使用阻断算法来处理具有多个核比存储器大阵列一个numpy的接口.

你也可以看看Spartan,DistarrayBiggus.