Pergunta sobre cuda, convolution, image-processing, c++, image – Convolução CUDA de kernel pequeno 2d - como fazer

13

Eu tenho experimentado com kernels CUDA por dias para realizar uma rápida convolução 2D entre uma imagem de 500x500 (mas eu também poderia variar as dimensões) e um kernel 2D muito pequeno (um kernel 2d laplaciano, então é um kernel 3x3 .. muito pequeno para tirar uma vantagem enorme com todos os segmentos cuda).

Eu criei uma implementação clássica da CPU (dois loops foros, tão fácil quanto você imagina) e então comecei a criar kernels CUDA.

Depois de algumas tentativas frustrantes de realizar uma convolução mais rápida, acabei com este código:http://www.evl.uic.edu/sjames/cs525/final.html (veja a seção Memória Compartilhada), basicamente permite que um bloco de threads 16x16 carregue todos os dados de convolução necessários na memória compartilhada e, em seguida, execute a convolução.

Nada, a CPU ainda é muito mais rápida. Eu não tentei a abordagem FFT porque o SDK CUDA afirma que é eficiente com grandes tamanhos de kernel.

Se você leu ou não tudo o que escrevi, minha pergunta é:

Como posso executar uma rápida convolução 2D entre uma imagem relativamente grande e um kernel muito pequeno (3x3) com CUDA?

Eu não preciso de tempo por enquanto, eu posso ver que o programa com a CPU termina muito mais rápido :( paulAl
O que você quer dizer com "a CPU ainda é muito mais rápida"? Você está cronometrando o programa completo, incluindo a cópia de memória para e da GPU, ou apenas o tempo que leva para o kernel ser iniciado e concluído? Brendan Wood

Sua resposta

1   a resposta
9

pois o kernel 3x3 não é adequado para a abordagem baseada em FFT. A melhor maneira de lidar com isso seria empurrar o kernel para a memória constante (ou se você estiver usando uma placa fermi +, isso não deve importar muito).

Como você sabe o tamanho do kernel, a maneira mais rápida de fazer isso seria ler trechos da imagem / sinal de entrada na memória compartilhada e executar uma operação de multiplicação e adição desenrolada.

-

Se você estiver disposto a usar bibliotecas para executar esta operaçãoArrayFire eOpenCV tenha rotinas Convolution altamente otimizadas que podem economizar muito tempo de desenvolvimento.

Eu não estou muito familiarizado com o OpenCV, mas no ArrayFire você pode fazer algo como o seguinte.

<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

O benefício adicional do uso do ArrayFire é que sua operação em lote permite que você execute a convolução em paralelo. Você pode ler sobre como as convoluções suportam operações em loteAqui

Por exemplo, se você tivesse 10 imagens que você quer envolver usando o mesmo kernel, você poderia fazer algo como o seguinte:

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

-

Divulgação Completa: Eu trabalho no AccelerEyes e trabalho ativamente no ArrayFire.

Me desculpe se eu pareci irritado, obrigado. O link OpenCV ainda está quebrado. Hjulle
@Hjulle Nós fomos renomeados de accelereyes para arrayfire. Os links foram redirecionados para a nossa documentação atual para mim. Me desculpe se você estava tendo problemas. Eu atualizei o código e os links para refletir a versão mais recente do arrayfire. Pavan Yalamanchili
@Hjulle Eu não consigo encontrar o link direto para gpu :: Convolve, mas eu ligado à página de processamento de imagem que fala sobre a convolução. Pavan Yalamanchili
Os links estão mortos. Para adicionar insulto à injúria, o arquivo de Wayback Machine deles foi explicitamente removido:accelereyes.com/robots.txt Hjulle

Perguntas relacionadas