2

簡単なシリアル 1D 畳み込み関数を作成しました (以下)。GPU 畳み込みの実装も試しています。これは主に私自身の好奇心によるものです。さまざまな非FFT実装戦略間のパフォーマンスのトレードオフを学ぼうとしています。

Nvidia GPU では分岐はコストがかかるため、GPU 畳み込みの実験では分岐を回避することが重要です。私の友人の 1 人が、以下のコードをif/elseステートメントなしで実装する方法があると言いましたが、彼はそれがどのように機能するか思い出せませんでした。

if/elseステートメントを使用せずに正しい 1D 畳み込みを実装するにはどうすればよいですか?

C++ での基本的な 1D シリアル コードは次のとおりです。

vector<int> myConv1d(vector<int> vec, vector<int> kernel)
{
    int paddedLength = vec.size() + kernel.size() - 1;
    vector<int> convolved(paddedLength); //zeros
    reverse(kernel.begin(), kernel.end()); //flip the kernel (if we don't flip it, then we have correlation instead of convolution)
    for(int outputIdx=0; outputIdx<paddedLength; outputIdx++) //index into 'convolved' vector
    {
        int vecIdx = outputIdx - kernel.size() + 1; //aligns with leftmost element of kernel
        for(int kernelIdx=0; kernelIdx<kernel.size(); kernelIdx++)
        {
            if( (vecIdx+kernelIdx) >= 0  &&  (vecIdx+kernelIdx) < vec.size() ) //TODO: FIND A WAY TO REMOVE THIS
            {
                convolved[outputIdx] += kernel[kernelIdx]*vec[vecIdx+kernelIdx];
            }
        }
    }
    return convolved;
}

いくつかの簡単なメモ:

  • 関連する投稿をいくつか 見つけましたが、条件ステートメントを回避する戦略がよくわかりませんでした。
  • 私は 2D 畳み込みの実装も作成しました。この SO 投稿の結果を 2D バージョンにも適用したいと考えています。
  • これは宿題ではありません。これは私たちの研究プロジェクトの 1 つとわずかに関連していますが、ほとんどは学習のためです。
4

2 に答える 2

3

こんなことしてみませんか?

int lowerBound = std::max( 0, -vecIdx );
int upperBound = std::min( kernel.size(), vec.size() - vecIdx );
for( int kernelIdx = lowerBound; kernelIdx < upperBound; kernelIdx++ )

質問がわからなかったらごめんなさい。

于 2012-09-25T06:14:50.263 に答える
1

チェックを回避するには、ソース ベクターをゼロ拡張または境界拡張します。ソース ベクトル V のサイズが L でカーネルのサイズが K の場合、K-1 個の要素を先頭および末尾に追加してパディングします。

L = 5 および K = 3 とすると、パディングされたベクトルになるはずです。

ppvvvvvqq

ここで、vs はベクトル要素、ps と qs はパディングです。GPU ツールキットでは、ソース ベクターの外側の要素を 0 または境界値にクランプできるようにする必要があることに注意してください。これにより、上記のパディングが実質的に役に立たなくなります。

于 2012-09-25T10:45:54.450 に答える