2

我写了一个简单的串行一维卷积函数(如下)。我也在试验 GPU 卷积实现。这主要是出于我自己的好奇心;我正在尝试学习各种非 FFT 实施策略之间的性能权衡。

避免分支对于我的 GPU 卷积实验很重要,因为在 Nvidia GPU 上分支很昂贵。我的一个朋友提到有一种方法可以在没有if/else语句的情况下实现下面的代码,但他不记得它是如何工作的。

如何在不使用任何if/else语句的情况下进行正确的一维卷积实现?

这是我在 C++ 中的基本一维串行代码:

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 版本中。
  • 这不是家庭作业。它与我们的一项研究项目略有关联,但主要是为了学习。
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 回答