Следующая программа загружает два изображения в PyGame, преобразует их в массивы Numpy, а затем выполняет некоторые другие операции Numpy (например, FFT) для получения окончательного результата (из нескольких чисел). Входные данные могут быть большими, но в любой момент должны быть активны только один или два больших объекта.
Тестовое изображение имеет размер около 10M пикселей, что после серой шкалы соответствует 10MB. Он преобразуется в массив Numpy dtype uint8
, который после некоторой обработки (с применением окон Хэмминга) представляет собой массив dtype float64
. Таким образом, два изображения загружаются в массивы; последующие шаги FFT приводят к массиву dtype complex128
. Перед добавлением избыточных вызовов gc.collect
объем памяти программы увеличивался с каждым шагом. Кроме того, кажется, что большинство операций Numpy дадут результат с максимально возможной точностью.
Выполнение теста (без вызовов gc.collect
) на моем Linux-компьютере объемом 1 ГБ приводит к длительной перебивке, чего я не ожидал. У меня пока нет подробной статистики использования памяти - я пробовал некоторые модули Python и команду time
безрезультатно; теперь я смотрю в Вальгринд. Наблюдение за PS (и работа с машинным безответством на более поздних этапах теста) предполагает максимальное использование памяти около 800 МБ.
10 миллионов ячеек массива complex128 должны занимать 160 МБ. Наличие (в идеале) не более двух из них живет одновременно, плюс нематериальные библиотеки Python и Numpy и другие атрибуты, вероятно, означает наличие 500 МБ.
Я могу представить себе два угла, с которых можно атаковать проблему:
Отмена промежуточных массивов как можно скорее. Вот для чего нужны gc.collect
звонки - похоже, они улучшили ситуацию, поскольку теперь она завершается всего лишь несколькими минутами разгрома ;-). Я думаю, можно ожидать, что интенсивное программирование памяти на языке, подобном Python, потребует некоторого ручного вмешательства.
Использование менее точных массивов Numpy на каждом шаге. К сожалению, операции, которые возвращают массивы, такие как fft2
, не позволяют указать тип.
Итак, мой главный вопрос: есть ли способ указать точность вывода в операциях с массивами Numpy?
В целом, существуют ли другие распространенные методы сохранения памяти при использовании Numpy?
Кроме того, есть ли у Numpy более идиоматический способ освобождения памяти массива? (Я предполагаю, что это оставит объект массива живым в Python, но в непригодном для использования состоянии.) Явное удаление, за которым следует немедленный GC, кажется хакерским.
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))