2012-04-13 22 views
10

He estado experimentando con núcleos CUDA durante días para realizar una rápida convolución 2D entre una imagen de 500x500 (pero también podría variar las dimensiones) y un núcleo 2D muy pequeño (un laplacian kernel 2d, por lo que es un kernel 3x3 ... demasiado pequeño para tomar una gran ventaja con todos los hilos cuda).CUDA núcleo pequeño 2d convolución - cómo hacerlo

Creé una implementación clásica de CPU (dos loops, tan fácil como se podría pensar) y luego comencé a crear núcleos CUDA.

Después de algunos intentos decepcionantes para realizar una convolución más rápido que terminó con este código: http://www.evl.uic.edu/sjames/cs525/final.html (ver la sección de memoria compartida), que básicamente permite a los hilos 16x16 bloque de carga todos los datos de convolución que necesita en la memoria compartida y luego realiza la convolución.

Nada, la CPU es aún mucho más rápida. No probé el enfoque de FFT porque el SDK de CUDA indica que es eficiente con tamaños de kernel grandes.

Independientemente de si usted lee todo lo que escribí, mi pregunta es:

cómo puedo realizar una convolución 2D rápido entre una imagen relativamente grande y un pequeño núcleo (3x3) con CUDA?

+4

¿Qué quiere decir con "la CPU es aún mucho más rápida"? ¿Está sincronizando el programa completo, incluida la copia de memoria hacia y desde la GPU, o simplemente el tiempo que demora el kernel en iniciarse y completarse? –

+0

No necesito tiempo por ahora, puedo ver que el programa con la CPU termina MUCHO más rápido :( – paulAl

Respuesta

7

Tiene razón en que el kernel 3x3 no es adecuado para el enfoque basado en FFT. La mejor manera de lidiar con esto sería presionar el núcleo en la memoria constante (o si está usando una tarjeta fermi +, esto no debería importar demasiado).

Dado que conoce el tamaño del kernel, la manera más rápida de hacer esto sería leer los trozos de la imagen/señal de entrada en la memoria compartida y realizar una operación de multiplicar y agregar desenrollada.

-

Si usted está dispuesto a utilizar las bibliotecas para realizar esta operación ArrayFire y OpenCV han rutinas de convolución que le puede ahorrar una gran cantidad de tiempo de desarrollo altamente optimizado.

No estoy muy familiarizado con OpenCV, pero en ArrayFire puedes hacer algo como lo siguiente.

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 

EDITAR

El beneficio adicional del uso de ArrayFire es su operación por lotes le permite realizar la convolución en paralelo. Usted puede leer acerca de cómo convolvutions apoyan las operaciones por lotes sobre here

Por ejemplo, si tiene 10 imágenes que desea convolución utilizando el mismo núcleo, que podría hacer somehting como la siguiente:

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 

-

Divulgación completa: Trabajo en AccelerEyes y trabajo activamente en ArrayFire.

+0

Los enlaces están muertos.Para colmo de males, el archivo Wayback Machine de ellos ha sido purgado explícitamente: http://www.accelereyes.com/robots.txt – Hjulle

+0

@Hjulle Hemos cambiado la marca de los ojos acelerados a arrayfire. Los enlaces estaban redirigiendo a nuestra documentación actual para mí. Lo siento si tuviste problemas. Actualicé el código y los enlaces para reflejar la última versión de arrayfire. –

+0

Lo siento si sonaba molesto, gracias. El enlace de OpenCV aún está roto. – Hjulle

Cuestiones relacionadas