Как избежать огромного дополнительного потребления памяти при использовании numpy vectorize?
этот код ниже лучше всего иллюстрирует мою проблему:
вывод на консоль (NB требуется ~8 минут для запуска даже первого теста) показывает, что 512x512x512x16-битные распределения массива потребляют не больше, чем ожидалось (256MByte для каждого), и, глядя На "сверху", процесс обычно остается суб-600MByte, как ожидалось.
, в то время как вызывается векторизованная версия функции, процесс расширяется до огромный размер (по 7GByte!). Даже самое очевидное объяснение, которое я могу придумать, чтобы объяснить это - что vectorize преобразует входы и выходы в float64 внутри - может учитывать только пару гигабайт, хотя векторизованная функция возвращает int16, а возвращаемый массив, безусловно, является int16. Есть ли способ избежать этого ? Я неправильно использую / понимаю аргумент otypes vectorize?
import numpy as np
import subprocess
def logmem():
subprocess.call('cat /proc/meminfo | grep MemFree',shell=True)
def fn(x):
return np.int16(x*x)
def test_plain(v):
print "Explicit looping:"
logmem()
r=np.zeros(v.shape,dtype=np.int16)
for z in xrange(v.shape[0]):
for y in xrange(v.shape[1]):
for x in xrange(v.shape[2]):
r[z,y,x]=fn(x)
print type(r[0,0,0])
logmem()
return r
vecfn=np.vectorize(fn,otypes=[np.int16])
def test_vectorize(v):
print "Vectorize:"
logmem()
r=vecfn(v)
print type(r[0,0,0])
logmem()
return r
logmem()
s=(512,512,512)
v=np.ones(s,dtype=np.int16)
logmem()
test_plain(v)
test_vectorize(v)
v=None
logmem()
Я использую любые версии Python / numpy, текущие на система сжатия Debian amd64 (Python 2.6.6, numpy 1.4.1).
2 ответов
вы можете прочитать исходный код vectorize (). Он преобразует dtype массива в object и вызывает np.frompyfunc() чтобы создать ufunc из вашей функции python, ufunc возвращает массив объектов и, наконец, vectorize () преобразует массив объектов в массив int16.
Он будет использовать много памяти, когда dtype массива объекта.
использование функции python для вычисления элементов медленно, даже преобразуется в ufunc с помощью frompyfunc ().
основной проблемой векторизации является то, что все промежуточные значения также являются векторами. Хотя это удобный способ получить приличное повышение скорости, он может быть очень неэффективным с использованием памяти и будет постоянно бить кэш процессора. Чтобы преодолеть эту проблему, вам нужно использовать подход, который имеет явные циклы, работающие со скоростью компиляции, а не со скоростью python. Лучшие способы сделать это-использовать на Cython, код fortran, завернутый в f2py или numexpr. Вы можете найти сравнение этих подходов здесь, хотя это больше фокусируется на скорости, чем на использовании памяти.