在numpy中优化内存使用

时间:2010-06-29 07:25:47

标签: python memory-management numpy pygame

以下程序使用PyGame加载两个图像,将它们转换为Numpy数组,然后执行一些其他Numpy操作(例如FFT)以发出最终结果(少数几个)。输入可能很大,但在任何时候只应有一个或两个大对象。

测试图像大约为10M像素,一旦灰度化就会转换为10MB。它被转换为dtype uint8的Numpy数组,经过一些处理(应用汉明窗口)后,是一个dtype float64数组。以这种方式将两个图像加载到阵列中;稍后的FFT步骤会产生一个dtype complex128数组。在添加过多的gc.collect调用之前,程序内存大小往往随着每一步而增加。此外,似乎大多数Numpy操作都会以最高的精度给出结果。

在我的1GB Linux机器上运行测试(没有gc.collect调用)会导致长时间的颠簸,我还没有等待。我还没有详细的内存使用统计信息 - 我尝试了一些Python模块和time命令无济于事;现在我正在研究valgrind。观看PS(以及在测试的后期阶段处理机器无响应)表明最大内存使用量约为800 MB。

一个1000万个complex128的单元阵列应该占用160 MB。 (理想情况下)其中至多有两个同时存在,加上非实质性的Python和Numpy库以及其他随身用品,可能意味着允许500 MB。

我可以想出解决这个问题的两个角度:

  • 尽快丢弃中间阵列。这就是gc.collect调用的内容 - 它们似乎改善了情况,因为它现在只需几分钟的捶打就可以完成;-)。我认为可以预期像Python这样的语言中的内存密集型编程需要一些人工干预。

  • 在每一步使用不太精确的Numpy数组。遗憾的是,返回数组的操作(如fft2)似乎不允许指定类型。

所以我的主要问题是:有没有办法在Numpy数组操作中指定输出精度?

更一般地说,使用Numpy时还有其他常见的内存保存技术吗?

另外,Numpy有更多惯用的释放数组内存的方法吗? (我想这会让数组对象在Python中生效,但处于无法使用的状态。)显式删除后立即GC会感觉很乱。

import sys
import numpy
import pygame
import gc


def get_image_data(filename):
    im = pygame.image.load(filename)
    im2 = im.convert(8)
    a = pygame.surfarray.array2d(im2)
    hw1 = numpy.hamming(a.shape[0])
    hw2 = numpy.hamming(a.shape[1])
    a = a.transpose()
    a = a*hw1
    a = a.transpose()
    a = a*hw2
    return a


def check():
    gc.collect()
    print 'check'


def main(args):
    pygame.init()

    pygame.sndarray.use_arraytype('numpy')

    filename1 = args[1]
    filename2 = args[2]
    im1 = get_image_data(filename1)
    im2 = get_image_data(filename2)
    check()
    out1 = numpy.fft.fft2(im1)
    del im1
    check()
    out2 = numpy.fft.fft2(im2)
    del im2
    check()
    out3 = out1.conjugate() * out2
    del out1, out2
    check()
    correl = numpy.fft.ifft2(out3)
    del out3
    check()
    maxs = correl.argmax()
    maxpt = maxs % correl.shape[0], maxs / correl.shape[0]
    print correl[maxpt], maxpt, (correl.shape[0] - maxpt[0], correl.shape[1] - maxpt[1])


if __name__ == '__main__':
    args = sys.argv
    exit(main(args))

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你正在计算两个图像之间的卷积。 Scipy包中包含一个专用模块(ndimage),它可能比通过傅里叶变换的“手动”方法更高效。尝试使用它而不是通过Numpy会很好。

答案 1 :(得分:1)

This 在SO上说“Scipy 0.8将为几乎所有的fft代码提供单精度支持”, 而SciPy 0.8.0 beta 1刚出局 (自己没有尝试过,懦弱。)