2012-04-13 2 views
10

Ho sperimentato con i kernel CUDA per giorni per eseguire una convoluzione 2D veloce tra un'immagine 500x500 (ma potrei anche variare le dimensioni) e un kernel 2D molto piccolo (un il kernel 2pl di laplacian, quindi è un kernel 3x3 .. troppo piccolo per avere un enorme vantaggio con tutti i thread di cuda).CUDA kernel piccolo 2d convoluzione - come farlo

Ho creato un'implementazione CPU classica (due per cicli, semplice come si penserebbe) e quindi ho iniziato a creare i kernel CUDA.

Dopo alcuni tentativi deludenti per effettuare una spira più veloce ho finito con questo codice: http://www.evl.uic.edu/sjames/cs525/final.html (vedere la sezione Shared Memory), consente fondamentalmente un thread 16x16 bloccano carico di tutto i dati convoluzione ha bisogno nella memoria condivisa e quindi esegue la convoluzione.

Niente, la CPU è ancora molto più veloce. Non ho provato l'approccio FFT perché l'SDK CUDA afferma che è efficiente con grandi dimensioni del kernel.

O se non avete letto tutto quello che ho scritto, la mia domanda è:

come posso eseguire un convoluzione 2D veloce tra una percentuale relativamente alta di immagine e un kernel molto piccolo (3x3) con CUDA?

+4

Cosa intendi con "la CPU è ancora molto più veloce"? Stai cronometrando il programma completo inclusa la copia della memoria da e verso la GPU, o solo il tempo necessario per il lancio e il completamento del kernel? –

+0

Per ora non ho bisogno di tempistiche, posso vedere che il programma con la CPU termina molto più velocemente :( – paulAl

risposta

7

Hai ragione nel fatto che il kernel 3x3 non è adatto per l'approccio basato su FFT. Il modo migliore per affrontarlo sarebbe quello di spingere il kernel in memoria costante (o se si sta usando una scheda fermi +, questo non dovrebbe importare troppo).

Poiché si conosce la dimensione del kernel, il modo più veloce per farlo sarebbe quello di leggere blocchi di immagine/segnale in ingresso nella memoria condivisa ed eseguire un'operazione di moltiplicazione e aggiunta srotolata.

-

Se siete disposti ad utilizzare le librerie per eseguire questa operazione ArrayFire e OpenCV hanno routine di convoluzione che possono risparmiare un sacco di tempo di sviluppo altamente ottimizzato.

Non ho molta familiarità con OpenCV, ma in ArrayFire puoi fare qualcosa di simile al seguente.

array kernel = array(3, 3, h_kernel, afHost); // Transfer the kernel to gpu 
array image = array(w, h, h_image , afHost); // Transfer the image to gpu 
array result = convolve2(image, kernel);  // Performs 2D convolution 

EDIT

Il vantaggio di utilizzare ArrayFire è il suo funzionamento in batch consente di eseguire convoluzione in parallelo. Si può leggere su come convolvutions supportano le operazioni batch su here

Per esempio se si ha 10 immagini che si desidera convolvere usando lo stesso kernel, si potrebbe fare somehting simile al seguente:

array kernel = array(3, 3, h_kernel, afHost);  // Transfer the kernel to gpu 
array images = array(w, h, 10, h_images, afHost); // Transfer the images to gpu 
array res = convolve2(images, kernel); // Perform all operations simultaneously 

-

Full Disclosure: Lavoro in AccelerEyes e lavoro attivamente su ArrayFire.

+0

I collegamenti sono morti.Per aggiungere la beffa al danno, l'archivio Wayback Machine di loro è stato esplicitamente eliminato: http://www.accelereyes.com/robots.txt – Hjulle

+0

@Hjulle Abbiamo rimarchiato da accelereyes a arrayfire. I collegamenti stavano reindirizzando alla nostra documentazione corrente per me. Mi dispiace se hai avuto problemi. Ho aggiornato il codice e i collegamenti per riflettere l'ultima versione di arrayfire. –

+0

Mi dispiace se ho suonato annoiato, grazie. Il collegamento OpenCV è ancora rotto però. – Hjulle