Il seguente programma carica due immagini con PyGame, le converte in array Numpy e quindi esegue alcune altre operazioni di Numpy (come FFT) per emettere un risultato finale (di pochi numeri). Gli input possono essere grandi, ma in qualsiasi momento devono essere attivi solo uno o due oggetti di grandi dimensioni.Ottimizzazione dell'uso della memoria in numpy
Un'immagine di prova è di circa 10 milioni di pixel, che si traduce in 10 MB una volta convertita in grigio. Viene convertito in un array Numpy di dtype uint8
, che dopo alcune elaborazioni (applicando le finestre di Hamming), è un array di dtype float64
. Due immagini vengono caricate in array in questo modo; le fasi successive di FFT determinano una matrice di dtype complex128
. Prima di aggiungere le chiamate eccessive gc.collect
, le dimensioni della memoria del programma tendevano ad aumentare ad ogni passaggio. Inoltre, sembra che la maggior parte delle operazioni di Numpy diano un risultato nella massima precisione disponibile.
L'esecuzione del test (senza le chiamate gc.collect
) sul mio computer Linux da 1 GB comporta un thrashing prolungato, che non ho atteso. Non ho ancora statistiche dettagliate sull'utilizzo della memoria: ho provato alcuni moduli Python e il comando time
senza alcun risultato; ora sto guardando in valgrind. Guardare PS (e affrontare la mancanza di controllo della macchina nelle ultime fasi del test) suggerisce un utilizzo massimo della memoria di circa 800 MB.
Un array di 10 milioni di celle complesse128 dovrebbe occupare 160 MB. Avere (idealmente) al massimo due di questi live contemporaneamente, più le librerie Python e Numpy non-inconsistenti e altri armamentari, probabilmente significa consentire 500 MB.
posso pensare due angoli da cui attaccare il problema:
rigetti array intermedi appena possibile. Ecco a cosa servono le chiamate
gc.collect
- sembra che abbiano migliorato la situazione, dato che ora si completa con pochi minuti di thrashing ;-). Penso che ci si possa aspettare che la programmazione intensiva della memoria in un linguaggio come Python richiederà un intervento manuale.Utilizzo di array Numpy meno precisi in ogni fase. Sfortunatamente le operazioni che restituiscono array, come
fft2
, non sembrano permettere che il tipo sia specificato.
Quindi la mia domanda principale è: c'è un modo di specificare la precisione di uscita nelle operazioni di matrice numpy?
Più in generale, ci sono altre tecniche comuni di conservazione della memoria quando si utilizza Numpy?
Inoltre, Numpy ha un modo più idiomatico di liberare memoria di array? (Immagino che questo lascerebbe l'oggetto dell'array live in Python, ma in uno stato inutilizzabile.) L'eliminazione esplicita seguita da GC immediato sembra hacky.
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))
Lo esaminerò sicuramente per il progetto più ampio (un obiettivo del quale è * ottenere risultati), anche se c'è anche l'obiettivo di * provare nuove cose *). Ma immagino che userò Numpy molto, quindi sono ancora interessato alle tecniche che possono aiutare con questo problema. – Edmund