【问题标题】:CUFFT - padding/initializing questionCUFFT - 填充/初始化问题
【发布时间】:2011-07-27 12:36:16
【问题描述】:

我正在查看用于卷积 FFT 示例(用于大型内核)的 Nvidia SDK,我知道傅立叶变换背后的理论及其 FFT 实现(至少是基础知识),但我不知道下面的代码是什么确实:

const int    fftH = snapTransformSize(dataH + kernelH - 1);
const int    fftW = snapTransformSize(dataW + kernelW - 1);

....//gpu initialization code

printf("...creating R2C & C2R FFT plans for %i x %i\n", fftH, fftW);
        cuf ftSafeCall( cufftPlan2d(&fftPlanFwd, fftH, fftW, CUFFT_R2C) );
        cufftSafeCall( cufftPlan2d(&fftPlanInv, fftH, fftW, CUFFT_C2R) );

    printf("...uploading to GPU and padding convolution kernel and input data\n");
        cutilSafeCall( cudaMemcpy(d_Kernel, h_Kernel, kernelH * kernelW * sizeof(float), cudaMemcpyHostToDevice) );
        cutilSafeCall( cudaMemcpy(d_Data,   h_Data,   dataH   * dataW *   sizeof(float), cudaMemcpyHostToDevice) );
        cutilSafeCall( cudaMemset(d_PaddedKernel, 0, fftH * fftW * sizeof(float)) );
        cutilSafeCall( cudaMemset(d_PaddedData,   0, fftH * fftW * sizeof(float)) );

        padKernel(
            d_PaddedKernel,
            d_Kernel,
            fftH,
            fftW,
            kernelH,
            kernelW,
            kernelY,
            kernelX
        );

        padDataClampToBorder(
            d_PaddedData,
            d_Data,
            fftH,
            fftW,
            dataH,
            dataW,
            kernelH,
            kernelW,
            kernelY,
            kernelX
        );

我之前从未使用过 CUFFT 库,所以我不知道 snapTransformSize 是做什么的

(这里是代码)

int snapTransformSize(int dataSize){
    int hiBit;
    unsigned int lowPOT, hiPOT;

    dataSize = iAlignUp(dataSize, 16);

    for(hiBit = 31; hiBit >= 0; hiBit--)
        if(dataSize & (1U << hiBit)) break;

    lowPOT = 1U << hiBit;
    if(lowPOT == dataSize)
        return dataSize;

    hiPOT = 1U << (hiBit + 1);
    if(hiPOT <= 1024)
        return hiPOT;
    else 
        return iAlignUp(dataSize, 512);
}

也不知道为什么复平面会这样初始化。

你能给我解释链接或答案吗?

【问题讨论】:

    标签: visual-c++ cuda fft cufft


    【解决方案1】:

    它似乎将 FFT 维度四舍五入到 2 的下一个幂,除非维度超过 1024,在这种情况下它会四舍五入到 512 的下一个倍数。

    在四舍五入 FFT 大小之后,您当然需要用零填充数据,以使其成为 FFT 的正确大小。

    请注意,我们通常需要四舍五入和填充卷积的原因是因为每个 FFT 维度都需要为image_dimension + kernel_dimension - 1,这通常不是一个方便的数字,例如 2 的幂。

    【讨论】:

      【解决方案2】:

      @Paul R 说的是正确的。为什么这样做是因为快速傅里叶变换操作 需要以最快的速度执行 2 的倍数。见Cooley-Tukey algorithm

      只需确保您声明的矩阵是 2 的幂次方,并且您不需要该通用安全实现。

      【讨论】:

      • 2 的幂对于所有 FFT 实现来说不是必要的,而且对于更大的 FFT 大小,CUFFT 似乎可以处理非 2 的幂,它使用 512 的倍数反而。对于卷积,通常不能将 FFT 大小设为 2 的幂,因为尺寸需要为 image_dimension + kernel_dimension - 1,因此需要向上舍入和填充。
      • @farbrizioM:2 的倍数和 2 的幂都不是必需的。 FFT 可以用于任何可以分解为小素数的大小,例如FFTW 适用于 2、3、5、7 的因数。
      • 是的,可以为非二的幂实现 FFT,但您错过了重点:二的幂可以计算一个 很多 更快,因此代码试图通过将 500 点 FFT 转换为 512 点 FFT 来提供更好的性能。
      • 感谢大家的回答,我会研究如何更好地实现这一点,但现在我有了一个开始学习的起点。阅读您的答案,我想 CUFFT 代码可能适用于每个内核/矩阵大小。如果这个假设是真的,我一定会很高兴!
      【解决方案3】:

      它将 FFT 维度向上取整为 2 的幂,直到维度超过 1024,它向上取整为 512 的倍数。您应该用零填充数据以使其成为 FFT 的正确大小。 `

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-25
      • 2021-10-13
      • 2013-02-28
      • 1970-01-01
      相关资源
      最近更新 更多