Есть ли способ уменьшить точность scipy/numpy, чтобы уменьшить потребление памяти?

В моей 64-битной системе Debian/Lenny (4 ГБ ОЗУ + 4 ГБ раздел подкачки) я могу успешно выполнить:

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

но с f, являющимся np.complex128, потребление памяти шокирует, и я не могу сделать гораздо больше с результатом (например, модулировать коэффициенты, а затем f=ifftn(f) ) без трассировки MemoryError.

Вместо того, чтобы устанавливать больше оперативной памяти и/или расширять мои разделы подкачки, есть ли какой-то способ контролировать «точность по умолчанию» scipy/numpy и вместо этого вычислять массив complex64?

Я знаю, что потом могу просто уменьшить его с помощью f=array(f,dtype=np.complex64); Я хочу, чтобы он действительно выполнял работу БПФ с 32-битной точностью и вдвое меньше памяти.


person timday    schedule 06.03.2009    source источник


Ответы (2)


Не похоже, что в функциях fft scipy есть какая-либо функция для этого (см. http://www.astro.rug.nl/efidad/scipy.fftpack.basic.html).

Если вы не можете найти библиотеку FFT с фиксированной точкой для python, маловероятно, что нужная вам функция существует, поскольку ваш собственный аппаратный формат с плавающей запятой составляет 128 бит. Похоже, что вы могли бы использовать метод rfft, чтобы получить только компоненты с действительными значениями (без фазы) БПФ, и это сэкономило бы половину вашей оперативной памяти.

Я выполнил следующее в интерактивном питоне:

>>> 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'>

На данный момент RSS (размер резидентного набора) Python составлял 265 МБ.

f = fft.fft(v)

И на данный момент RSS python 2.3GB.

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

И в этот момент RSS уменьшается до 2,0 ГБ, так как я освободил v.

Использование "fft.rfft(v)" для вычисления действительных значений приводит только к RSS размером 1,3 ГБ. (почти половина, как и ожидалось)

Делает:

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

Является худшим из обоих миров, поскольку сначала вычисляет версию complex128 (2,3 ГБ), а затем копирует ее в версию complex64 (1,3 ГБ), что означает, что пиковый RSS на моей машине составлял 3,6 ГБ, а затем он снизился до 1,3 ГБ. снова.

Я думаю, что если у вас 4 ГБ ОЗУ, все должно работать нормально (как у меня). В чем проблема?

person slacy    schedule 06.03.2009
comment
Спасибо за указание на функции rfftn; да, они хорошо справляются со своей задачей. Пиковое использование для f=rfftn(v), f=array(f,dtype=np.complex64), f=irfftn(f) составляет 6224 МБ в обратном порядке. (Без промежуточного приведения к комплексу 64 он использует 7754 МБ... немного тесновато). - person timday; 07.03.2009
comment
Действительно ли размер вашего производственного массива больше 512 ^ 3? Я не уверен, почему вы видите что-то вроде 4-кратного увеличения использования ОЗУ, которое я вижу в моем примере кода выше... - person slacy; 09.03.2009
comment
Пожалуйста, измените часть, где вы говорите, что «одинарной точности не существует, поскольку ваше собственное оборудование 128-битное» - собственное оборудование не более 128-битное, чем 64-битное, и FFTW очень гибок в поддержке обоих. Как показывает ответ Дэвида, scipy.fftpack.rfft поддерживает это: scipy.fftpack.rfft(v.astype(np.float32)).dtype возвращает float32. К сожалению, поддержка Numpy отстает от поддержки Scipy даже в 2015 году: github.com/numpy/numpy/issues. /6012 - person Ahmed Fasih; 20.08.2015

Scipy 0.8 будет иметь поддержку одинарной точности почти для всего кода fft (код уже находится в стволе, поэтому вы можете установить scipy из svn, если вам нужна эта функция сейчас).

person David Cournapeau    schedule 21.03.2009