CUDA small kernel 2d свертка - как это сделать
я экспериментировал с ядрами CUDA в течение нескольких дней, чтобы выполнить быструю 2D-свертку между изображением 500x500 (но я также мог изменять размеры) и очень маленьким 2D-ядром (2d-ядром Лапласа, поэтому это ядро 3x3.. слишком мало, чтобы воспользоваться огромным преимуществом со всеми потоками cuda).
Я создал классическую реализацию CPU (два для циклов, как легко, как вы думаете), а затем я начал создавать ядра CUDA.
после нескольких неудачных попыток, чтобы выполните более быструю свертку, я закончил с этим кодом: http://www.evl.uic.edu/sjames/cs525/final.html (см. раздел Общая память), он в основном позволяет потокам 16x16 загружать все данные свертки, которые ему нужны в общей памяти, а затем выполняет свертку.
ничего, процессор по-прежнему намного быстрее. Я не пробовал подход FFT, потому что CUDA SDK утверждает, что он эффективен с большими размерами ядра.
читаете вы или нет все, что я написал, мой вопрос:
как я могу выполнить быструю 2D-свертку между относительно большим изображением и очень маленьким ядром (3x3) с помощью CUDA?
1 ответов
вы правы в том, что ядро 3x3 не подходит для подхода на основе FFT. Лучший способ справиться с этим-поместить ядро в постоянную память (или, если вы используете карту fermi+, это не должно иметь большого значения).
поскольку вы знаете размер ядра, самый быстрый способ сделать это-прочитать куски входного изображения / сигнала в общую память и выполнить развернутую операцию умножения и добавления.
--
Если вы готовы использовать библиотеки для выполнения этой операции ArrayFire и OpenCV имеют высоко оптимизированные процедуры свертки, которые могут сэкономить вам много времени на разработку.
Я не слишком хорошо знаком с 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 поддерживает пакетные операции над здесь
например, если у вас было 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.