Вопрос по c++, image – CUDA маленькое ядро 2d свертка - как это сделать

13

Я несколько дней экспериментировал с ядрами CUDA, чтобы выполнить быструю двумерную свертку между изображением 500x500 (но я также мог бы варьировать размеры) и очень маленьким двумерным ядром (ядром лапласиана 2d, так что это тоже ядро 3x3). маленький, чтобы получить огромное преимущество со всеми нитями куда).

Я создал классическую реализацию CPU (две для циклов, так легко, как вы думаете), а затем я начал создавать ядра CUDA.

После нескольких разочаровывающих попыток выполнить более быструю свертку я получил следующий код: http://www.evl.uic.edu/sjames/cs525/final.html (см. раздел «Общая память»), он в основном позволяет блоку потоков 16x16 загружать все необходимые данные свертки в общую память и затем выполняет свертку.

Ничего, процессор все еще намного быстрее. Я не пробовал подход FFT, потому что CUDA SDK утверждает, что он эффективен при больших размерах ядра.

Читаете ли вы все, что я написал, мой вопрос:

how can I perform a fast 2D convolution between a relatively large image and a very small kernel (3x3) with CUDA?

Сейчас мне не нужно время, я вижу, что программа с процессором завершает ОЧЕНЬ быстрее :( paulAl
Что вы подразумеваете под "процессор все еще намного быстрее"? Вы рассчитываете полную программу, включая копирование памяти в и из графического процессора, или просто время, необходимое для запуска и завершения ядра? Brendan Wood

Ваш Ответ

1   ответ
9

что ядро 3x3 не подходит для подхода, основанного на FFT. Лучший способ справиться с этим - вставить ядро в постоянную память (или, если вы используете карту Fermi +, это не должно иметь большого значения).

Поскольку вы знаете размер ядра, самый быстрый способ сделать это - прочитать куски входного изображения / сигнала в общую память и выполнить развернутую операцию умножения и сложения.

--

Если вы готовы использовать библиотеки для выполнения этой операцииArrayFire а такжеOpenCV имеют высоко оптимизированные процедуры Convolution, которые могут сэкономить вам много времени на разработку.

Я не слишком знаком с 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

EDIT

Дополнительным преимуществом использования ArrayFire является его пакетная операция, позволяющая выполнять свертку параллельно. Вы можете прочитать о том, как свертки поддерживают пакетные операции надВот

Например, если у вас было 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.

@Hjulle Мы переименовали из акселераторов в огонь. Ссылки были перенаправлены на нашу текущую документацию для меня. Извините, если у вас возникли проблемы. Я обновил код и ссылки, чтобы отразить последнюю версию arrayfire.
Ссылки мертвы. Чтобы добавить оскорбление ране, архив Wayback Machine из них был явно очищен:accelereyes.com/robots.txt
@Hjulle Я не могу найти прямую ссылку для gpu :: Convolve, но я ссылаюсь на страницу обработки изображений, которая говорит о свертке.
Мне жаль, если я звучал раздраженно, спасибо. Ссылка OpenCV все еще не работает.

Похожие вопросы