使用大型 Numpy 数组的技术?

新手上路,请多包涵

有时您必须对一个或多个大型 Numpy 阵列执行许多中间操作。这会很快导致 MemoryError s。到目前为止,在我的研究中,我发现 Pickling(Pickle、CPickle、Pytables 等)和 gc.collect() 是缓解这种情况的方法。我想知道在处理大量数据时是否还有经验丰富的程序员使用的任何其他技术(当然除了删除策略/代码中的冗余之外)。

此外,如果有一件事我可以肯定,那就是没有什么是免费的。对于其中一些技术,有哪些权衡取舍(即速度、稳健性等)?

原文由 Noob Saibot 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 508
2 个回答

我感觉到你的痛苦……你有时最终会存储数倍于数组大小的值,这些值稍后会被丢弃。当一次处理数组中的一项时,这是无关紧要的,但在矢量化时可能会杀死你。

我将使用工作中的示例进行说明。我最近使用 numpy 对 这里 描述的算法进行了编码。它是一种颜色映射算法,它获取 RGB 图像并将其转换为 CMYK 图像。对每个像素重复该过程,如下所示:

  1. 使用每个 RGB 值的最高 4 位作为三维查找表的索引。这决定了 LUT 中立方体的 8 个顶点的 CMYK 值。
  2. 根据上一步的顶点值,使用每个 RGB 值的最低 4 位在该立方体中进行插值。执行此操作的最有效方法需要计算 16 个 uint8 数组,这些数组的大小与正在处理的图像的大小相同。对于一个24bit的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 中,请不要使用 int32 的数组!由于静默溢出,这可能会变成神秘错误的噩梦,但如果你小心的话,它可以节省大量资源。

原文由 Jaime 发布,翻译遵循 CC BY-SA 3.0 许可协议

第一个最重要的技巧:分配一些大数组,并使用和回收其中的一部分,而不是将大量 临时 数组带入生活并丢弃/垃圾收集。听起来有点过时,但通过仔细的编程加速可以令人印象深刻。 (您可以更好地控制对齐方式和数据局部性,因此可以使数字代码更有效率。)

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

第三:正如@Jaime 所指出的,如果整个矩阵太大,请取消分块子矩阵。

编辑:

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

原文由 Stefano M 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题