CUDA小内核2d卷积 - 怎么做

时间:2012-04-13 17:26:00

标签: c++ image image-processing cuda convolution

我一直在尝试使用CUDA内核几天来在500x500图像之间执行快速2D卷积(但我也可以改变尺寸)和一个非常小的2D内核(laplacian 2d内核,所以它是一个3x3内核。太小,不能用所有的cuda线程占据巨大的优势。)

我创建了一个CPU经典实现(两个for循环,就像你想象的那样简单),然后我开始创建CUDA内核。

经过一些令人失望的尝试来执行更快的卷积后,我最终得到了这段代码: http://www.evl.uic.edu/sjames/cs525/final.html(参见共享内存部分),它基本上允许16x16线程阻塞加载共享内存中所需的所有卷积数据,然后执行卷积。

没什么,CPU仍然快得多。我没有尝试使用FFT方法,因为CUDA SDK声明它对于大内核大小是有效的。

无论你是否阅读了我写的所有内容,我的问题是:

如何使用CUDA在相对较大的图像和非常小的内核(3x3)之间执行快速2D卷积?

1 个答案:

答案 0 :(得分:9)

你说得对,3x3内核不适合基于FFT的方法。处理这个问题的最好方法是将内核推入恒定内存(或者如果你使用的是fermi +卡,这应该不会太重要)。

由于你知道内核大小,最快的方法是将输入图像/信号的块读入共享内存并执行展开的乘法和加法操作。

-

如果您愿意使用库来执行此操作ArrayFireOpenCV 拥有高度优化的卷积例程,可以为您节省大量的开发时间。

我对OpenCV不太熟悉,但在ArrayFire中你可以做类似以下的事情。

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

修改

使用ArrayFire的额外好处是它的批处理操作允许您并行执行卷积。您可以阅读有关convolvutions如何支持here

上的批处理操作的信息

例如,如果您想要使用相同的内核进行卷积的10个图像,则可以执行以下操作:

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

-

完全披露:我在AccelerEyes工作并积极参与ArrayFire。