Pregunta sobre cuda, convolution, image-processing, c++, image – CUDA small kernel 2d convolution - cómo hacerlo

13

He estado experimentando con los 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 kernel 2D muy pequeño (un kernel laplaciano 2d, por lo que es un kernel de 3x3 ... demasiado pequeño tomar una gran ventaja con todos los hilos de cuda).

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

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

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

Si lees o no todo lo que escribí, mi pregunta es:

¿Cómo puedo realizar una rápida convolución 2D entre una imagen relativamente grande y un kernel muy pequeño (3x3) con CUDA?

No necesito tiempo por ahora, puedo ver que el programa con la CPU termina MUCHO más rápido :( paulAl
¿Qué quiere decir con "la CPU todavía es mucho más rápida"? ¿Está sincronizando el programa completo, incluida la copia de memoria hacia y desde la GPU, o solo el tiempo que tarda el kernel en iniciarse y completarse? Brendan Wood

Tu respuesta

1   la respuesta
9

en FFT. La mejor manera de lidiar con esto sería empujar el kernel a la memoria constante (o si está usando una tarjeta fermi +, esto no debería importar demasiado).

Como sabe el tamaño del kernel, la forma más rápida de hacerlo sería leer fragmentos de la imagen / señal de entrada en la memoria compartida y realizar una operación de multiplicación y adición desenrollada.

-

Si está dispuesto a utilizar bibliotecas para realizar esta operación.ArrayFire yOpenCV tenga rutinas de convolución altamente optimizadas que le pueden ahorrar mucho tiempo de desarrollo.

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

<code>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
</code>

EDITAR

El beneficio adicional de usar ArrayFire es que su operación por lotes le permite realizar la convolución en paralelo. Puede leer acerca de cómo las convolvencias soportan las operaciones por lotes sobreaquí

Por ejemplo, si tenía 10 imágenes que desea convertir usando el mismo kernel, podría hacer algo como lo siguiente:

<code>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
</code>

-

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

@Hjulle Hemos cambiado la marca de accelereyes a arrayfire. Los enlaces estaban redirigiendo a nuestra documentación actual para mí. Lo siento si tuvieras problemas. Actualicé el código y los enlaces para reflejar la última versión de arrayfire. Pavan Yalamanchili
Los enlaces están muertos. Para agregar insulto a la lesión, el archivo de Wayback Machine de ellos se ha eliminado de forma explícita:accelereyes.com/robots.txt Hjulle
@Hjulle Parece que no puedo encontrar el enlace directo de gpu :: Convolve, pero lo vinculé a la página de procesamiento de imágenes que habla de convolución. Pavan Yalamanchili
Lo siento si soné molesto, gracias. El enlace de OpenCV todavía está roto. Hjulle

Preguntas relacionadas