scipy.fftpack.fft2和cufft之间的结果差异

时间:2014-07-20 13:32:20

标签: python numpy cuda fft

现在,我将我的python脚本移植到CUDA程序。 在我的python脚本中,使用了scipy.fftpack.fft2。 为了验证袖口的结果,我使用cufft编写了示例程序。 但是,似乎scipy.fftpack.fft2和cufft之间存在差异。

有什么建议吗?

python脚本:

def test2():
   g = [18,19,19,23,24,24,23,24,24]
   g = numpy.array(g)
   g.shape = [3,3]
   G = fft2(g)

   print "---------------"
   print g
   print G
   return 

python脚本的结果:

   ---------------
    [[18 19 19]
     [23 24 24]
     [23 24 24]]
    [[ 198.+0.j   -3.+0.j   -3.+0.j]
     [ -15.+0.j    0.+0.j    0.+0.j]
     [ -15.+0.j    0.+0.j    0.+0.j]]

cuda计划:

        cufftHandle plan;
        int nRows = 3;
        int nCols = 3;
        cufftPlan2d(&plan, nRows, nCols, CUFFT_R2C);
        float h_in[9] = {18,19,19,23,24,24,23,24,24};
        float* d_in;
        cudaMalloc(&d_in, sizeof(cufftComplex)*9); 
        cufftComplex* d_freq;
        cudaMalloc(&d_freq, sizeof(cufftComplex)*9); 
        cudaMemcpy(d_in,h_in,sizeof( cufftComplex)*9,cudaMemcpyHostToDevice);
        cufftExecR2C(inverse_plan, d_in, d_freq);
        cufftComplex* h_freq = (float2*)malloc(sizeof( cufftComplex)*9);    
        cudaMemcpy(h_freq,d_freq,sizeof( cufftComplex)*9,cudaMemcpyDeviceToHost);
        for(int i=0; i<9; i++) {
        printf("%i %f %f\n", i, h_freq[i].x, h_freq[i].y);
        }

cuda计划的结果:

0 198.000000 -0.000001
1 -2.999996 -0.000001
2 -15.000000 0.000000
3 -0.000000 0.000000
4 -15.000000 0.000000
5 -0.000000 0.000000
6 497922732955248410000000000000.000000 8589934592.000000
7 572199135312371230000000000000.000000 8589934592.000000
8 -0.000000 0.000000

1 个答案:

答案 0 :(得分:2)

我不是袖手专家,但是这种命名方式可以解释所发生的事情:

  • 在numpy中,您正在运行完整的2D FFT。因为您的输入是真实的,所以输出是对称的,如您所见:每行(或列)中的最后一项等于前一项。

  • 您可以利用此功能更快地运行FFT,并且在numpy中使用rfft2函数实现:

    >>> np.fft.rfft2(g)
    array([[ 198.+0.j,   -3.+0.j],
           [ -15.+0.j,    0.+0.j],
           [ -15.+0.j,    0.+0.j]])
    
  • 我的猜测是R2C计划名称中的CUFFT_R2C表示“真实到复杂”,因此您要求等同于np.rfft2 。如果你放弃数组中未使用的最后3项,结果几乎完全相同,除了舍入错误,以及你的CUDA实现使用32位浮点数,而不是numpy将默认使用的64

  • 快速谷歌搜索显示CUFFT_C2CcufftExecR2C是有效的袖带标识符。使用它们应该会产生正确的结果。要进行更加精确的再现,请重构代码并使用Z2Z版本,这些版本适用于double,而不是float