Эффективная память Python пакетной обработки
вопрос
Я написал небольшой пакетный процессор Python, который загружает двоичные данные, выполняет множество операций и сохраняет результаты. Он потребляет гораздо больше памяти, чем должен. Я посмотрел на подобные обсуждения переполнения стека и хотел бы попросить дальнейшие рекомендации.
фон
Я конвертирую спектральные данные в rgb. Спектральные данные хранятся в файле изображения с чередованием полос (BIL). Вот почему я читаю и обрабатываю данные построчно. Я читаю данные, используя Spectral Python Library, которая возвращает пустые массивы. hyp - дескриптор большого спектрального файла: hyp.ncols=1600, hyp.nrows=3430, hyp.nbands=160
код
import spectral
import numpy as np
import scipy
class CIE_converter (object):
def __init__(self, cie):
self.cie = cie
def interpolateBand_to_cie_range(self, hyp, hyp_line):
interp = scipy.interpolate.interp1d(hyp.bands.centers,hyp_line, kind='cubic',bounds_error=False, fill_value=0)
return interp(self.cie[:,0])
#@profile
def spectrum2xyz(self, hyp):
out = np.zeros((hyp.ncols,hyp.nrows,3))
spec_line = hyp.read_subregion((0,1), (0,hyp.ncols)).squeeze()
spec_line_int = self.interpolateBand_to_cie_range(hyp, spec_line)
for ii in xrange(hyp.nrows):
spec_line = hyp.read_subregion((ii,ii+1), (0,hyp.ncols)).squeeze()
spec_line_int = self.interpolateBand_to_cie_range(hyp,spec_line)
out[:,ii,:] = np.dot(spec_line_int,self.cie[:,1:4])
return out
потребление памяти
Все большие данные инициализируются вне цикла. Моя наивная интерпретация заключалась в том, что потребление памяти не должно увеличиваться (Я использовал слишком много Matlab?) Может кто-нибудь объяснить мне фактор увеличения 10? Это не линейно, так как hyp.nrows = 3430. Есть ли рекомендации по улучшению управления памятью?
Line # Mem usage Increment Line Contents
================================================
76 @profile
77 60.53 MB 0.00 MB def spectrum2xyz(self, hyp):
78 186.14 MB 125.61 MB out = np.zeros((hyp.ncols,hyp.nrows,3))
79 186.64 MB 0.50 MB spec_line = hyp.read_subregion((0,1), (0,hyp.ncols)).squeeze()
80 199.50 MB 12.86 MB spec_line_int = self.interpolateBand_to_cie_range(hyp, spec_line)
81
82 2253.93 MB 2054.43 MB for ii in xrange(hyp.nrows):
83 2254.41 MB 0.49 MB spec_line = hyp.read_subregion((ii,ii+1), (0,hyp.ncols)).squeeze()
84 2255.64 MB 1.22 MB spec_line_int = self.interpolateBand_to_cie_range(hyp, spec_line)
85 2235.08 MB -20.55 MB out[:,ii,:] = np.dot(spec_line_int,self.cie[:,1:4])
86 2235.08 MB 0.00 MB return out
заметки
Я заменил диапазон на xrange без радикальных улучшений. Я знаю, что кубическая интерполяция не самая быстрая, но речь идет не о загрузке процессора.
1 ответ
Спасибо за комментарии. Все они помогли мне немного улучшить потребление памяти. Но в конце концов я выяснил, что является основной причиной потребления памяти:
SpectralPython Изображения содержат объект Numpy Memmap. Он имеет тот же формат, что и структура данных куба гиперспектральных данных. (в случае формата BIL (nrows, nbands, ncols)) При вызове:
spec_line = hyp.read_subregion((ii,ii+1), (0,hyp.ncols)).squeeze()
изображение не только возвращается как возвращаемое значение массива, но также кэшируется в hyp.memmap. Второй вызов будет быстрее, но в моем случае память просто увеличивается, пока ОС не жалуется. Поскольку memmap на самом деле является отличной реализацией, я воспользуюсь ее преимуществами в будущей работе.