14

500x500 の画像 (ただし、サイズを変更することもできます) と非常に小さな 2D カーネル (ラプラシアン 2D カーネルなので、3x3 カーネルです。小さすぎる) の間で高速な 2D 畳み込みを実行するために、CUDA カーネルを数日間試してきました。すべての cuda スレッドで大きなアドバンテージを得るために)。

CPU の従来の実装 (2 つの for ループ、ご想像のとおり簡単です) を作成してから、CUDA カーネルの作成を開始しました。

より高速な畳み込みを実行するためのいくつかの残念な試みの後、私はこのコードに行き着きました: http://www.evl.uic.edu/sjames/cs525/final.html (共有メモリのセクションを参照)。共有メモリに必要なすべての畳み込みデータをブロックロードし、畳み込みを実行します。

何もありません、CPUはまだずっと高速です。CUDA SDK は、大きなカーネル サイズで効率的であると述べているため、FFT アプローチは試しませんでした。

私が書いたものをすべて読んだかどうかにかかわらず、私の質問は次のとおりです。

CUDA を使用して、比較的大きな画像と非常に小さなカーネル (3x3) の間で高速な 2D 畳み込みを実行するにはどうすればよいですか?

4

1 に答える 1

9

3x3 カーネルは FFT ベースのアプローチには適していないという点で正しいです。これに対処する最善の方法は、カーネルをコンスタント メモリにプッシュすることです (または、fermi+ カードを使用している場合、これはあまり重要ではありません)。

カーネル サイズがわかっているので、これを行う最も速い方法は、入力画像/信号のチャンクを共有メモリに読み込み、アンロールされた乗算および加算操作を実行することです。

--

ライブラリを使用してこの操作を実行する場合、ArrayFireOpenCV には高度に最適化された 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

編集

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 に取り組んでいます。

于 2012-04-13T19:26:59.983 に答える