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