Оптимизация использования памяти в NumPy - PullRequest
8 голосов
/ 29 июня 2010

Следующая программа загружает два изображения в 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))

Ответы [ 2 ]

1 голос
/ 29 июня 2010

Это в SO говорится: «Scipy 0.8 будет иметь поддержку одинарной точности почти для всего кода FFT», и SciPy 0.8.0 beta 1 только что вышел.
(Сам не пробовал, трусливый.)

1 голос
/ 29 июня 2010

если я правильно понимаю, вы рассчитываете свертку между двумя изображениями. Пакет Scipy содержит специальный модуль для этого ( ndimage ), который может быть более эффективным с точки зрения памяти, чем "ручной" подход с помощью преобразований Фурье. Было бы неплохо попробовать использовать его вместо прохождения через Numpy.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...