有没有一种方法可以降低scipy/numpy的精度以减少内存消耗?

9

在我的64位Debian/Lenny系统上(4GByte RAM + 4GByte交换分区),我可以成功地执行以下操作:

v=array(10000*random([512,512,512]),dtype=np.int16)
f=fftn(v)

但是,如果f是np.complex128类型,内存消耗太大了,我不能在结果上做更多的事情(例如调制系数然后使用f = ifftn(f)),否则会出现MemoryError错误。

与其安装更多的RAM和/或扩展我的swap分区,不如控制scipy/numpy的“默认精度”,使其计算一个complex64数组吧?

我知道我可以用f = array(f, dtype=np.complex64)后来将其减小;我希望它实际上可以在32位精度下执行FFT工作并减少一半的内存。

2个回答

6

在scipy的fft函数中似乎没有做这件事情的任何函数(请参见http://www.astro.rug.nl/efidad/scipy.fftpack.basic.html)。除非你能够找到一个固定点FFT库用于Python,否则你想要的功能可能不存在,因为本地硬件浮点格式是128位。看起来你可以使用rfft方法来获取FFT的实值组件(无相位),这将节省一半的RAM。

我在交互式Python中运行了以下内容:

>>> from numpy import *
>>>  v = array(10000*random.random([512,512,512]),dtype=int16)
>>> shape(v)
(512, 512, 512)
>>> type(v[0,0,0])
<type 'numpy.int16'>

此时 Python 的 RSS(常驻集大小)为 265MB。

f = fft.fft(v)

此时 Python 的 RSS 为 2.3GB。

>>> type(f)
<type 'numpy.ndarray'>
>>> type(f[0,0,0]) 
<type 'numpy.complex128'>
>>> v = []

在这一点上,由于我已经释放了v,RSS降至2.0GB。

使用“fft.rfft(v)”仅计算实值会导致1.3GB的RSS。(几乎是预期的一半)

执行:

>>> f = complex64(fft.fft(v))

这是两全其美的最糟糕情况,因为它首先计算complex128版本(2.3GB),然后将其复制到complex64版本(1.3GB),这意味着我的机器上峰值RSS为3.6GB,然后又降至1.3GB。
我认为如果你有4GB RAM,这一切都应该很好地运行(就像对我一样)。问题在哪里?

1
感谢指向rfftn函数的指针;是的,它们很好地完成了工作。 对于f = rfftn(v),f = array(f,dtype = np.complex64),f = irfftn(f)的峰值使用率在反演中为6224MByte。(如果没有中间转换为complex64,则使用7754MByte……有点紧张)。 - timday
你的生产数组大小是否真的大于512^3?我不确定为什么你看到的内存使用量会比我上面示例代码中看到的多4倍... - slacy
1
请修改你说“单精度不存在,因为本地硬件是128位”的那一部分——本地硬件不仅仅是64位而已,而且FFTW非常灵活,支持两者。正如David的回答所示,scipy.fftpack.rfft支持这种操作:scipy.fftpack.rfft(v.astype(np.float32)).dtype返回float32。不幸的是,即使在2015年,Numpy的支持也远远落后于Scipy:https://github.com/numpy/numpy/issues/6012 - Ahmed Fasih

5

Scipy 0.8将为几乎所有fft代码提供单精度支持(该代码已经在主干中,因此如果您现在需要该功能,则可以从svn安装scipy)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接