2010-06-29 9 views
8

Poniższy program ładuje dwa obrazy za pomocą PyGame, konwertuje je na tablice Numpy, a następnie wykonuje inne operacje Numpy (takie jak FFT), aby emitować końcowy wynik (z kilku liczb). Wejścia mogą być duże, ale w każdej chwili powinien być włączony tylko jeden lub dwa duże obiekty.Optymalizacja wykorzystania pamięci w numpy

Obraz testowy ma około 10 milionów pikseli, co przekłada się na 10 MB po skalowaniu za pomocą skali szarości. Jest konwertowany na tablicę Numpy z dtype uint8, która po pewnym przetworzeniu (z zastosowaniem okien Hamminga), jest tablicą dtype float64. Dwa obrazy są ładowane do tablic w ten sposób; później kroki FFT dają w wyniku tablicę dtype complex128. Przed dodaniem nadmiernych wywołań gc.collect rozmiar pamięci programu zwykle wzrastał z każdym krokiem. Dodatkowo wydaje się, że większość operacji Numpy da wynik w najwyższej dostępnej precyzji.

Przeprowadzenie testu (bez wywołań gc.collect) na moim komputerze z 1GB Linuksa powoduje przedłużone rzucanie, na które nie czekałem. Nie mam jeszcze szczegółowych statystyk użycia pamięci - próbowałem niektórych modułów Pythona i polecenia time bezskutecznie; teraz patrzę na valgrind. Oglądanie PS (i radzenie sobie z niewydolnością maszyny na późniejszych etapach testu) sugeruje maksymalne wykorzystanie pamięci około 800 MB.

10 milionów macierzy komórek złożonych128 powinno zajmować 160 MB. Posiadanie (najlepiej) co najwyżej dwóch z nich jednocześnie oraz nieistotnych bibliotek Pythona i Numpy i innych akcesoriów, prawdopodobnie oznacza dopuszczenie 500 MB.

mogę myśleć o dwóch kątów, z których do ataku na problem:

  • odrzucając tablice pośrednich jak najszybciej. Do tego służą wywołania gc.collect - wydaje się, że poprawiły sytuację, ponieważ teraz kończy się zaledwie kilka minutami thrashingu ;-). Myślę, że można się spodziewać, że intensywnie wykorzystujące pamięć programowanie w języku takim jak Python będzie wymagało ręcznej interwencji.

  • Użycie mniej precyzyjnych tablic Numpy na każdym etapie. Niestety operacje zwracające tablice, takie jak fft2, nie pozwalają na podanie typu.

Więc moje główne pytanie brzmi: jest jakiś sposób określania precyzji wyjściowe w operacjach tablicy numpy?

Bardziej ogólnie, czy istnieją inne popularne techniki oszczędzania pamięci podczas korzystania z Numpy?

Dodatkowo, czy Numpy ma bardziej idiomatyczny sposób uwalniania pamięci tablicy? (Wyobrażam sobie, że zostawiłoby to obiekt tablicy w Pythonie, ale w stanie bezużytecznym.) Jawne usunięcie, a następnie natychmiastowa GC, wydaje się być hackowata.

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

Odpowiedz

1

This na SO mówi "scipy 0.8 będzie mieć pojedynczą precyzję wsparcie dla niemal wszystkich kodu FFT", i scipy 0.8.0 beta 1 jest tylko na zewnątrz.
(Nie próbowałem sam, tchórzliwy.)

1

Jeśli dobrze rozumiem, obliczasz splot między dwoma obrazami. Pakiet Scipy zawiera specjalny moduł do tego (ndimage), który może być bardziej wydajny pod względem pamięci niż podejście "ręczne" za pomocą transformacji Fouriera. Dobrze byłoby spróbować go użyć zamiast przechodzić przez Numpy.

+1

Na pewno zbadam to dla większego projektu (jednym z celów jest * załatwianie spraw *), chociaż jest też cel * próbowania nowych rzeczy *). Ale wyobrażam sobie, że będę dużo używać Numpy'ego, więc nadal jestem zainteresowany technikami, które mogą pomóc w tym problemie. – Edmund