2012-06-21 17 views
12

Tengo una aplicación que requiere procesar varias imágenes en paralelo para mantener la velocidad en tiempo real.Computación en paralelo de GPU con OpenCV

Tengo entendido que no puedo llamar a las funciones de la GPU de OpenCV de forma multiproceso en un solo dispositivo CUDA. He tratado de un código de construcción OpenMP tales como los siguientes:

#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]); 
     } 
    } 
} 

Esto parece compilar y ejecutar correctamente, pero por desgracia, aparece para ejecutar los hilos numImages en serie en el mismo dispositivo CUDA.

Debería poder ejecutar varios hilos en paralelo si tengo múltiples dispositivos CUDA, ¿correcto? Para obtener varios dispositivos CUDA, ¿necesito varias tarjetas de video?

¿Alguien sabe si la tarjeta nVidia GTX 690 de doble chip funciona como dos dispositivos CUDA independientes con OpenCV 2.4 o posterior? Encontré la confirmación de que puede funcionar como tal con OpenCL, pero no hay confirmación con respecto a OpenCV.

+0

¿Quizás la respuesta está en el código fuente de OpenCV? –

Respuesta

5

Simplemente haga la multiplicación de pasar imágenes completas a la función cv::gpu::multiply().

OpenCV y CUDA se encargarán de dividirlo y dividir la tarea de la mejor manera. Generalmente, cada unidad de computadora (es decir, núcleo) en una GPU puede ejecutar múltiples hilos (típicamente> = 16 en CUDA). Esto se suma a tener tarjetas que pueden aparecer como múltiples GPU o poner varias tarjetas vinculadas en una sola máquina.

El objetivo de cv::gpu es evitar que tenga que saber nada sobre cómo funcionan las piezas internas.

+0

Sí, cierto. La función de multiplicar() está escrita para aprovechar el enhebrado de CUDA dentro de la función misma. Sin embargo, lo que necesito es más de una función de multiplicación() que funcione en hilos paralelos. Eso no parece posible sin múltiples gpus. Luego puede ejecutar una función de multiplicación() en cada uno en paralelo y para diferentes imágenes simultáneamente. – mmccullo

+0

@mmccullo - si cv :: gpu usa subprocesamiento cuda de bajo nivel, puede invocarlo en varios subprocesos de usuario, pero cada uno utilizará completamente el gpu hasta que el otro haya terminado. Si tiene una tarjeta con cuda2, utilizará streams para hacer esto de manera asíncrona, por lo que sus hilos no bloquean –

+0

Estoy usando CUDA v4.2. No estoy seguro de lo que su referencia a "cuda2" significa exactamente. No parece bloquear necesariamente mis hilos OpenMP, pero el tiempo de ejecución de mi código anterior es solo un poco mejor que ejecutarlo en un solo hilo. Parece que la ejecución de los múltiples hilos ocurre en serie en el único dispositivo CUDA; de lo contrario, el tiempo de ejecución debería ser mucho menor que el único hilo en el mismo dispositivo. Mi GPU de prueba es un Quadro2000M con núcleos de 2GB y 192 CUDA. Las imágenes son 1280x960 RGB. – mmccullo

0

No conozco nada acerca de las funciones GPU de OpenCV, pero si son completamente independientes (es decir, crean contexto GPU, transfieren datos a GPU, calculan resultados, transfieren resultados a la CPU), entonces no es sorprendente estas funciones aparecen serializadas cuando se usa una sola GPU.

Si tiene varias GPU, entonces debería haber alguna manera de decirle a la función OpenCV que se dirija a una GPU específica. Si tiene varias GPU y puede orientarlas eficazmente, entonces no veo ninguna razón por la cual las llamadas a la función GPU no se paralelizarán. Según el wiki de OpenCV, las funciones de la GPU apuntan a una sola GPU, pero puede dividir manualmente el trabajo usted mismo: http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQ#Can_I_use_two_or_more_GPUs.3F

GPU duales como la GTX 690 aparecerán como dos dispositivos distintos con su propia memoria en cuanto a su GPU programa se refiere. Ver aquí: http://forums.nvidia.com/index.php?showtopic=231726

Además, si usted va una ruta de doble GPU para aplicaciones de cómputo, recomendaría contra la GTX 690, ya que su rendimiento informático es un poco lisiado en comparación con la GTX 590.

+0

Comentario interesante sobre el rendimiento de 690 vs. 590. Esta [página nVidia] (http://developer.nvidia.com/cuda-gpus) indica una mayor capacidad de la computadora para el 690. ¿Tiene alguna información específica sobre cómo el 690 está paralizado? – mmccullo

+0

"Según el wiki de OpenCV, las funciones de la GPU apuntan a una sola GPU, pero puedes dividir manualmente el trabajo por ti mismo" lamentablemente el enlace ya no está activo. ¿Qué significa dividirlo manualmente? ¿Tienes que configurar el ID del dispositivo antes de cada llamada a gpu opencv? ¿Hay algún ejemplo oficial que respalde la declaración? – alap

+0

¿Significa también que en el modo SLI/CrossFire uno debe hacer el cambio manual? – alap

0

la GTX 290 se comporta como 2 dispositivos CUDA separados, independientemente de la versión de OpenCV que use. No necesita múltiples tarjetas GPU para obtener múltiples GPU, que tiene 2 en una tarjeta, como en la GTX 290. Pero, desde la perspectiva de programación CUDA, no hay mucha diferencia entre el uso de las dos GPU en el 290 y el uso 2 GPU en tarjetas GPU conectadas por separado. Muchos usuarios de OpenCV usan la biblioteca ArrayFire CUDA para complementar con más funciones de procesamiento de imágenes y la escala fácil de múltiples GPU. Por supuesto, mi descargo de responsabilidad es que trabajo en ArrayFire, pero realmente creo que te ayudará en este caso.

4

La respuesta de Martin funcionó para mí. La clave es hacer uso de la clase gpu :: Stream si su dispositivo CUDA figura en la lista como capacidad de cálculo 2 o superior. Lo volveré a presentar aquí porque no pude publicar el clip de código correctamente en el mini editor de comentarios.

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]); 
     } 
    } 
} 

El código anterior parece ejecutar la multiplicación en paralelo (numImages = 3 para mi aplicación). También hay métodos Stream para ayudar a cargar/descargar imágenes hacia y desde la memoria GPU, así como también métodos para verificar el estado de una transmisión para ayudar a la sincronización con otro código.

Entonces ... aparentemente no requiere múltiples dispositivos CUDA (es decir, tarjetas GPU) para ejecutar el código GPU OpenCV en paralelo.

Cuestiones relacionadas