2010-06-29 7 views
8

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

risposta

1

This su SO dice "SciPy 0,8 avrà il supporto di precisione unico per quasi tutto il codice FFT", e SciPy 0.8.0 beta 1 è appena fuori.
(non l'ho provato io stesso, codardo.)

1

se ho capito bene, stai calcolando una convoluzione tra due immagini. Il pacchetto Scipy contiene un modulo dedicato per quello (ndimage), che potrebbe essere più efficiente della memoria rispetto all'approccio "manuale" tramite trasformate di Fourier. Sarebbe bello provare a usarlo invece di passare attraverso Numpy.

+1

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

Problemi correlati