2012-06-21 19 views
12

Ho un'applicazione che richiede l'elaborazione di più immagini in parallelo per mantenere la velocità in tempo reale.Calcolo GPU parallelo usando OpenCV

È a mia conoscenza che non posso chiamare le funzioni GPU di OpenCV in modo multithread su un singolo dispositivo CUDA. Ho provato un costrutto di codice OpenMP come la seguente:

#pragma omp parallel for 
for(int i=0; i<numImages; i++){ 
    for(int j=0; j<numChannels; j++){ 
     for(int k=0; k<pyramidDepth; k++){ 
      cv::gpu::multiply(pyramid[i][j][k], weightmap[i][k], pyramid[i][j][k]); 
     } 
    } 
} 

Questo sembra compilare ed eseguire correttamente, ma purtroppo sembra eseguire i fili numImages in serie sul medesimo dispositivo CUDA.

Dovrei essere in grado di eseguire più thread in parallelo se ho più dispositivi CUDA, corretto? Per ottenere più dispositivi CUDA, ho bisogno di più schede video?

Qualcuno sa se la scheda dual-chip nVidia GTX 690 funziona come due dispositivi CUDA indipendenti con OpenCV 2.4 o successivo? Ho trovato conferma che può funzionare come tale con OpenCL, ma nessuna conferma riguardo a OpenCV.

+0

Forse la risposta è nel codice sorgente per OpenCV? –

risposta

5

Basta moltiplicare il passaggio di immagini intere alla funzione cv::gpu::multiply().

OpenCV e CUDA gestiranno la divisione e la divisione nel modo migliore. Generalmente ogni unità di computer (ad esempio il core) in una GPU può eseguire più thread (in genere> = 16 in CUDA). Questo è oltre ad avere carte che possono apparire come più GPU o mettere più carte collegate in una macchina.

L'intero punto di cv::gpu è quello di evitare di dover sapere qualcosa su come funzionano le parti interne.

+0

Sì, vero. La funzione multiply() è scritta per sfruttare il threading CUDA all'interno della funzione stessa. Tuttavia, ciò di cui ho bisogno è più di una funzione multiply() che opera in thread paralleli. Questo non sembra possibile senza più gpus. Quindi è possibile eseguire una funzione multiplo() su ciascuno in parallelo e per immagini diverse contemporaneamente. – mmccullo

+0

@mmccullo - sì cv :: gpu usa il threading di basso livello, è possibile chiamarlo in più thread utente, ma ognuno utilizzerà completamente la gpu fino a quando l'altro non avrà finito. Se hai una scheda con cuda2 userà gli stream per fare questo async in modo che i tuoi thread non blocchino –

+0

Sto usando CUDA v4.2. Non sono sicuro di quale sia esattamente il tuo riferimento a "cuda2". Non sembra che blocchi necessariamente i miei thread OpenMP, ma il tempo di esecuzione del mio codice sopra è leggermente migliore rispetto all'esecuzione in un singolo thread. Sembra che l'esecuzione dei thread multipli avvenga in serie sul singolo dispositivo CUDA, altrimenti il ​​tempo di esecuzione dovrebbe essere molto inferiore al singolo thread sullo stesso dispositivo. La mia GPU di test è una Quadro2000M con core da 2 GB e 192 CUDA. Le immagini sono 1280x960 RGB. – mmccullo

0

Non so nulla delle funzioni GPU di OpenCV, ma se sono completamente autonome (cioè creano contesto GPU, trasferiscono dati in GPU, calcolano risultati, trasferiscono i risultati alla CPU), quindi non sorprende che queste funzioni appaiono serializzate quando si utilizza una singola GPU.

Se si dispone di più GPU, ci dovrebbe essere un modo per dire alla funzione OpenCV di indirizzare una GPU specifica. Se disponi di più GPU e le puoi indirizzare in modo efficace, non vedo alcun motivo per cui le chiamate alla funzione GPU non sarebbero state parallelizzate. Secondo la wiki di OpenCV, le funzioni della GPU hanno come target solo una singola GPU, ma puoi dividere manualmente il lavoro da te: http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQ#Can_I_use_two_or_more_GPUs.3F

Le GPU doppie come la GTX 690 appariranno come due dispositivi distinti con la propria memoria fino alla GPU programma è interessato. Vedi qui: http://forums.nvidia.com/index.php?showtopic=231726

Inoltre, se si sta andando un percorso a doppia GPU per applicazioni di calcolo, mi sento di raccomandare contro la GTX 690, perché le sue prestazioni di calcolo è un po 'paralizzato rispetto alla GTX 590.

+0

Commento interessante sulla prestazione 690 rispetto a 590. Questa [pagina nVidia] (http://developer.nvidia.com/cuda-gpus) indica una capacità del computer più elevata per il 690. Avete delle specifiche su come il 690 è azzoppato? – mmccullo

+0

"Secondo la wiki di OpenCV, le funzioni della GPU sono rivolte solo a una singola GPU, ma è possibile suddividere manualmente il lavoro da soli" purtroppo il collegamento non è più attivo. Cosa significa separarlo manualmente? Devi impostare l'ID del dispositivo prima di ogni chiamata a gpu opencv? C'è qualche esempio ufficiale a supporto della dichiarazione. – alap

+0

Significa anche che in modalità SLI/CrossFire si dovrebbe fare l'interruttore manuale? – alap

0

la GTX 290 si comporta come 2 dispositivi CUDA separati, indipendentemente dalla versione di OpenCV che si utilizza. Non hai bisogno di più schede GPU per ottenere più GPU, che hai 2 su una scheda come nella GTX 290. Ma, dal punto di vista della programmazione CUDA, non c'è molta differenza tra l'utilizzo delle due GPU sul 290 e l'uso 2 GPU su schede GPU collegate separatamente. Molti utenti OpenCV utilizzano la libreria ArrayFire CUDA per integrare con più funzioni di elaborazione delle immagini e il facile ridimensionamento multi-GPU. Naturalmente, il mio disclaimer è che lavoro su ArrayFire, ma penso davvero che ti sarà d'aiuto in questo caso.

4

La risposta di Martin ha funzionato per me. La chiave è fare uso della classe gpu :: Stream se il tuo dispositivo CUDA è elencato come capacità di calcolo 2 o superiore. Lo rifarò qui perché non ho potuto inserire correttamente il codice nel mini editor dei commenti.

cv::gpu::Stream stream[3]; 

for(int i=0; i<numImages; i++){ 
    for(int j=0; j<numChannels; j++){ 
     for(int k=0; k<pyramidDepth; k++){ 
      cv::gpu::multiply(pyramid[i][j][k], weightmap[i][k], pyramid[i][j][k], stream[i]); 
     } 
    } 
} 

Il codice di cui sopra sembra per eseguire la moltiplicazione in parallelo (numImages = 3 per la mia app). Esistono anche i metodi Stream per facilitare il caricamento/il download di immagini da e verso la memoria della GPU e metodi per controllare lo stato di un flusso al fine di facilitare la sincronizzazione con altri codici.

Quindi ... a quanto pare non richiede più dispositivi CUDA (ad esempio schede GPU) per eseguire il codice GPU OpenCV in parallelo!