2012-08-22 11 views
8

Estoy usando opencv242 + VS2010 con una notebook.
Intenté hacer una prueba simple del bloque de la GPU en OpenCV, pero mostró que la GPU es 100 veces más lenta que los códigos de la CPU. En este código, sólo girar la imagen en color a escala de grises, utilice la función de cvtColor¿Por qué el código de Opencv GPU es más lento que la CPU?

Aquí está mi código, PARTE 1 es el código de la CPU (prueba de CPU RGB2GRAY), PART2 es de carga de imágenes a la GPU, PART3 es GPU RGB2GRAY, PART4 es CPU RGB2GRAY nuevamente. Hay 3 cosas que me preguntan:

1 En mi código, part1 es 0.3ms, mientras que part4 (que es exactamente lo mismo con part1) es 40ms !!!
2 ¡La part2 que sube la imagen a la GPU es 6000ms!
3 Parte 3 (códigos GPU) es 11ms, ¡es tan lento para esta imagen simple!

#include "StdAfx.h" 
    #include <iostream> 
    #include "opencv2/opencv.hpp" 
    #include "opencv2/gpu/gpu.hpp" 
    #include "opencv2/gpu/gpumat.hpp" 
    #include "opencv2/core/core.hpp" 
    #include "opencv2/highgui/highgui.hpp" 
    #include <cuda.h> 
    #include <cuda_runtime_api.h> 
    #include <ctime> 
    #include <windows.h> 

    using namespace std; 
    using namespace cv; 
    using namespace cv::gpu; 

    int main() 
    { 
     LARGE_INTEGER freq; 
     LONGLONG QPart1,QPart6; 
     double dfMinus, dfFreq, dfTim; 
     QueryPerformanceFrequency(&freq); 
     dfFreq = (double)freq.QuadPart; 

     cout<<getCudaEnabledDeviceCount()<<endl; 
     Mat img_src = imread("d:\\CUDA\\train.png", 1); 

     // PART1 CPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     // From color image to grayscale image. 
     QueryPerformanceCounter(&freq); 
     QPart1 = freq.QuadPart; 
     Mat img_gray; 
     cvtColor(img_src,img_gray,CV_BGR2GRAY); 
     QueryPerformanceCounter(&freq); 
     QPart6 = freq.QuadPart; 
     dfMinus = (double)(QPart6 - QPart1); 
     dfTim = 1000 * dfMinus/dfFreq; 
     printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim); 

     // PART2 GPU upload image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     GpuMat gimg_src; 
     QueryPerformanceCounter(&freq); 
     QPart1 = freq.QuadPart; 
     gimg_src.upload(img_src); 
     QueryPerformanceCounter(&freq); 
     QPart6 = freq.QuadPart; 
     dfMinus = (double)(QPart6 - QPart1); 
     dfTim = 1000 * dfMinus/dfFreq; 
     printf("Read image running time is %.2f ms\n\n",dfTim); 

     GpuMat dst1; 
     QueryPerformanceCounter(&freq); 
     QPart1 = freq.QuadPart; 

     /*dst.upload(src_host);*/ 
     dst1.upload(imread("d:\\CUDA\\train.png", 1)); 

     QueryPerformanceCounter(&freq); 
     QPart6 = freq.QuadPart; 
     dfMinus = (double)(QPart6 - QPart1); 
     dfTim = 1000 * dfMinus/dfFreq; 
     printf("Read image running time 2 is %.2f ms\n\n",dfTim); 

     // PART3~ GPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     // gpuimage From color image to grayscale image. 
     QueryPerformanceCounter(&freq); 
     QPart1 = freq.QuadPart; 

     GpuMat gimg_gray; 
     gpu::cvtColor(gimg_src,gimg_gray,CV_BGR2GRAY); 

     QueryPerformanceCounter(&freq); 
     QPart6 = freq.QuadPart; 
     dfMinus = (double)(QPart6 - QPart1); 
     dfTim = 1000 * dfMinus/dfFreq; 
     printf("GPU RGB2GRAY running time is %.2f ms\n\n",dfTim); 

     // PART4~CPU code(again)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

     // gpuimage From color image to grayscale image. 
     QueryPerformanceCounter(&freq); 
     QPart1 = freq.QuadPart; 
     Mat img_gray2; 
     cvtColor(img_src,img_gray2,CV_BGR2GRAY); 
     BOOL i_test=QueryPerformanceCounter(&freq); 
     printf("%d \n",i_test); 
     QPart6 = freq.QuadPart; 
     dfMinus = (double)(QPart6 - QPart1); 
     dfTim = 1000 * dfMinus/dfFreq; 
     printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim); 

     cvWaitKey(); 
     getchar(); 
     return 0; 
    } 
+12

No es que la GPU sea generalmente "lenta". Sin embargo, la transferencia de memoria entre el host y el dispositivo es * extremadamente * lenta. El cálculo de la GPU solo tiene sentido si puede descargar un cálculo muy grande y altamente paralelo al dispositivo. –

+0

También debería marcar http://answers.opencv.org/question/1670/huge-time-to-upload-data-to-gpu/#1676 – Sam

+0

Luego pasa GpuMat no asignado, tiene asignación de memoria GPU dentro de GPU optimizado funciones. Para evitarlo, debe preasignar su memoria con el tamaño adecuado antes de usar la función. – geek

Respuesta

22

cvtColor no está haciendo mucho trabajo, para hacer que todo lo que tiene gris es un promedio de tres números.

El código cvColor en la CPU utiliza instrucciones SSE2 para procesar hasta 8 píxeles a la vez y si tiene TBB está utilizando todos los núcleos/hyperthreads, la CPU funciona a 10 veces la velocidad de la GPU y finalmente se pone no tiene que copiar datos en la GPU y volver.

+0

¡Gracias por responder! En este código, utilicé la CPU para RGB2GRAY dos veces (el mismo código, uno antes del código GPU, y el otro después de la GPU). Muestra que la segunda vez es mucho más lenta que la primera. ¡Pero son los mismos códigos! ¿Podría darme algunas indicaciones? –

+2

Esto también puede provenir del hecho de que crear un contexto CUDA lleva tiempo. No sé cómo evalúas el tiempo de tu código. –

3

tratan de ejecutar más de una vez ....

----------- extracto de http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQ Perfomance

Por primera llamada de función es lenta?

Esto se debe a la inicialización de los gastos generales. En la primera función de la GPU, la API Cuda Runtime se inicializa implícitamente. También se compila un código de GPU (compilación Just In Time) para su tarjeta de video en el primer uso. Entonces, para medir el rendimiento, es necesario hacer una llamada de función ficticia y solo entonces realizar pruebas de tiempo.

Si es fundamental para una aplicación ejecutar el código de GPU solo una vez, es posible usar una memoria caché de compilación que es persistente en varias ejecuciones. Lea la documentación de nvcc para obtener más información (variable de entorno CUDA_DEVCODE_CACHE).

0

¿Qué GPU tienes?

Compruebe la compatibilidad de cálculo, tal vez sea la razón.

https://developer.nvidia.com/cuda-gpus

Esto significa que para los dispositivos con CC 1.3 y 2.0 imágenes binarias son listo para funcionar. Para todas las plataformas más nuevas, el código PTX para 1.3 está JIT'ed en una imagen binaria. Para dispositivos con CC 1.1 y 1.2, el PTX para 1.1 es JIT'ed. Para dispositivos con CC 1.0, no hay código disponible y las funciones lanzan Excepción. Para plataformas donde la compilación JIT es realizada primero, la ejecución es lenta.

http://docs.opencv.org/modules/gpu/doc/introduction.html

1

cvtColour es una pequeña operación, y cualquier aumento de rendimiento que se obtiene de hacerlo en la GPU es inmensamente superados por los tiempos de transferencia de memoria entre el anfitrión (CPU) y el dispositivo (GPU).Minimizar la latencia de esta transferencia de memoria es un desafío principal de cualquier computación GPU.

16

La mayoría de las respuestas anteriores son en realidad incorrectas. La razón por la que es lenta en un factor de 20.000 no es, por supuesto, debido a que 'la velocidad del reloj de la CPU es más rápida' y 'tiene que copiarla a la GPU' (respuestas aceptadas). Estos son factores, pero al decir que omite el hecho de que tiene mucho más poder de cálculo para un problema que es desagradablemente paralelo. Decir que la diferencia en el rendimiento es de 20,000x se debe a que el último es simplemente ridículo. El autor aquí sabía que algo estaba mal que no es directo. Solución:

¡Su problema es que CUDA debe inicializarse! Siempre se inicializará para la primera imagen y generalmente tarda entre 1 y 10 segundos, dependiendo de la alineación de Júpiter y Marte. Ahora intenta esto. Haz el cálculo dos veces y luego mide ambos. Probablemente verá en este caso que las velocidades están dentro del mismo orden de Magnutide, no 20,000x, eso es ridículo. ¿Puedes hacer algo con esta inicialización? No, no es que yo sepa. Es un problema.

corregir: Acabo de volver a leer la publicación. Dices que estás corriendo en una libreta. Aquellos a menudo tienen GPU en mal estado y CPU con un turbo justo.

Cuestiones relacionadas