优化numpy中的内存使用
下面这个程序使用PyGame加载了两张图片,把它们转换成Numpy数组,然后进行一些其他的Numpy操作(比如快速傅里叶变换FFT),最后输出一些结果(就是几个数字)。输入的图片可以很大,但在任何时候,程序中只会有一到两个大对象在运行。
测试用的图片大约有1000万像素,转换成灰度图后大约是10MB。它被转换成一种叫做uint8
的数据类型的Numpy数组,经过一些处理(比如应用汉明窗),变成了float64
类型的数组。这样加载的两张图片,后面的FFT步骤会得到一种叫做complex128
的数据类型的数组。在添加了过多的gc.collect
调用之前,程序的内存使用量在每一步都会增加。此外,大多数Numpy操作的结果会以最高精度返回。
在我的1GB的Linux机器上运行测试(不包括gc.collect
调用)时,出现了长时间的内存抖动,我没有等到最后。我还没有详细的内存使用统计——我尝试了一些Python模块和time
命令,但都没用;现在我在研究valgrind。观察进程状态(PS)并处理测试后期机器无响应的情况,显示最大内存使用量大约是800MB。
一个包含1000万个单元的complex128
数组应该占用160MB的内存。理想情况下,最多同时有两个这样的数组,加上不小的Python和Numpy库以及其他一些东西,可能需要预留500MB的内存。
我想到了解决这个问题的两个方向:
尽快丢弃中间数组。这就是
gc.collect
调用的目的——它们似乎改善了情况,现在程序只需几分钟的内存抖动就能完成;-)。我认为在像Python这样的语言中进行内存密集型编程,可能需要一些手动干预。在每一步使用精度较低的Numpy数组。不幸的是,返回数组的操作,比如
fft2
,似乎不允许指定数据类型。
所以我主要想问的是:在Numpy数组操作中,有没有办法指定输出的精度?
更一般来说,使用Numpy时还有其他常见的节省内存的技巧吗?
另外,Numpy有没有更符合习惯的方式来释放数组内存?(我想这可能会让数组对象在Python中仍然存在,但处于不可用状态。)显式删除后立即进行垃圾回收感觉有点不太好。
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))