2016-04-27 73 views
2

我目前正在研究一个必须实现2D-FFT(用于交叉关联)的程序。我用CUDA做了一次FFT,它给了我正确的结果,我现在正在试图实现一个2D版本。在线上很少的例子和文档,我发现很难找出错误是什么。CUDA套箍2D示例

到目前为止,我一直只使用cuFFT手册。

无论如何,我已经创建了两个5x5阵列,并填充1。我已经将它们复制到GPU存储器中,并完成了前向FFT,将它们相乘,然后对结果进行ifft处理。这给了我一个值为650的5x5阵列。我期望在5x5阵列中的一个插槽中得到值为25的DC信号。相反,我在整个阵列中获得了650个。

此外,我不允许在将信号复制到GPU内存后打印出信号的值。写作

cout << d_signal[1].x << endl; 

给我一个acces侵犯。我在其他cuda程序中也做了同样的事情,但这不是问题。它与复杂变量的工作方式有关,还是人为错误?

如果任何人有任何问题的指针,我将不胜感激。下面是代码

#include "cuda_runtime.h" 
#include "device_launch_parameters.h" 
#include <helper_functions.h> 
#include <helper_cuda.h> 

#include <ctime> 
#include <time.h> 
#include <stdio.h> 
#include <iostream> 
#include <math.h> 
#include <cufft.h> 
#include <fstream> 

using namespace std; 
typedef float2 Complex; 





__global__ void ComplexMUL(Complex *a, Complex *b) 
{ 
    int i = threadIdx.x; 
    a[i].x = a[i].x * b[i].x - a[i].y*b[i].y; 
    a[i].y = a[i].x * b[i].y + a[i].y*b[i].x; 
} 


int main() 
{ 


    int N = 5; 
    int SIZE = N*N; 


    Complex *fg = new Complex[SIZE]; 
    for (int i = 0; i < SIZE; i++){ 
     fg[i].x = 1; 
     fg[i].y = 0; 
    } 
    Complex *fig = new Complex[SIZE]; 
    for (int i = 0; i < SIZE; i++){ 
     fig[i].x = 1; // 
     fig[i].y = 0; 
    } 
    for (int i = 0; i < 24; i=i+5) 
    { 
     cout << fg[i].x << " " << fg[i + 1].x << " " << fg[i + 2].x << " " << fg[i + 3].x << " " << fg[i + 4].x << endl; 
    } 
    cout << "----------------" << endl; 
    for (int i = 0; i < 24; i = i + 5) 
    { 
     cout << fig[i].x << " " << fig[i + 1].x << " " << fig[i + 2].x << " " << fig[i + 3].x << " " << fig[i + 4].x << endl; 
    } 
    cout << "----------------" << endl; 

    int mem_size = sizeof(Complex)* SIZE; 


    cufftComplex *d_signal; 
    checkCudaErrors(cudaMalloc((void **) &d_signal, mem_size)); 
    checkCudaErrors(cudaMemcpy(d_signal, fg, mem_size, cudaMemcpyHostToDevice)); 

    cufftComplex *d_filter_kernel; 
    checkCudaErrors(cudaMalloc((void **)&d_filter_kernel, mem_size)); 
    checkCudaErrors(cudaMemcpy(d_filter_kernel, fig, mem_size, cudaMemcpyHostToDevice)); 

    // cout << d_signal[1].x << endl; 
    // CUFFT plan 
    cufftHandle plan; 
    cufftPlan2d(&plan, N, N, CUFFT_C2C); 

    // Transform signal and filter 
    printf("Transforming signal cufftExecR2C\n"); 
    cufftExecC2C(plan, (cufftComplex *)d_signal, (cufftComplex *)d_signal, CUFFT_FORWARD); 
    cufftExecC2C(plan, (cufftComplex *)d_filter_kernel, (cufftComplex *)d_filter_kernel, CUFFT_FORWARD); 

    printf("Launching Complex multiplication<<< >>>\n"); 
    ComplexMUL <<< 32, 256 >> >(d_signal, d_filter_kernel); 

    // Transform signal back 
    printf("Transforming signal back cufftExecC2C\n"); 
    cufftExecC2C(plan, (cufftComplex *)d_signal, (cufftComplex *)d_signal, CUFFT_INVERSE); 

    Complex *result = new Complex[SIZE]; 
    cudaMemcpy(result, d_signal, sizeof(Complex)*SIZE, cudaMemcpyDeviceToHost); 

    for (int i = 0; i < SIZE; i=i+5) 
    { 
     cout << result[i].x << " " << result[i + 1].x << " " << result[i + 2].x << " " << result[i + 3].x << " " << result[i + 4].x << endl; 
    } 

    delete result, fg, fig; 
    cufftDestroy(plan); 
    //cufftDestroy(plan2); 
    cudaFree(d_signal); 
    cudaFree(d_filter_kernel); 

} 

上面的代码给出以下端子输出:

1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
---------------- 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
---------------- 
Transforming signal cufftExecR2C 
Launching Complex multiplication<<< >>> 
Transforming signal back cufftExecC2C 

625 625 625 625 625 
625 625 625 625 625 
625 625 625 625 625 
625 625 625 625 625 
625 625 625 625 625 
+0

您发布的代码是不完整的,无法编译。你能解决这个问题吗?如果不编译和运行代码很难告诉你什么可能是错误的,我现在不能这么做 - – talonmies

+0

当然,我有一些我不想包括的未注释的部分。我已经删除它,并将所有内容编辑到我的帖子中。 – LukaK

回答

0

这使我与值的5×5阵列650:它读取625即5 * 5 * 5 * 5。您正在使用的卷积算法需要N * N的补充除法。事实上,在cufft中,正向变换中没有归一化系数。因此,你的卷积不能是频域中两个场的简单乘法。 (有些人会称之为数学家DFT而不是医生DFT)。

此外我不允许打印出来的信号的值已经被复制到GPU存储器后:这是标准的CUDA行为。在设备上分配内存时,数据存在于设备内存地址空间中,无需额外努力就无法由CPU访问。搜索托管内存或zerocopy可以从PCI Express的两端访问数据(这在许多其他帖子中讨论过)。

+0

感谢您对Florenti的回复。这帮助了我很多! – LukaK

2

有几个问题在这里:

  1. 您正在启动太多线程的内核乘法输入数组的大小,因此应与出界外内存错误地失败。我很惊讶你没有收到任何类型的运行时错误。
  2. 您的fft/fft - dot产品 - ifft序列的预期解决方案我相信是错误的。正确的解决方案将是一个5x5矩阵,每个条目中有25个矩阵。
  3. 作为CUFFT文档中描述清楚,库执行unnormalised的FFT:

    CUFFT执行未归一化的FFT;也就是说,对输入数据组执行正向FFT,然后对所得到的组进行逆FFT,得到等于输入的数据,按照元素的数量进行缩放。通过数据集尺寸的倒数来缩放变换,留给用户以适合的方式执行。

所以,据我估计,你的代码正确的输出解决方案应该是5x5矩阵,在每个条目,这将在每个条目,即进行标准化,以5x5矩阵有25 625。预期的结果。我不明白(1)中的问题不会产生不同的结果,因为乘法内核应该失败。

TLDR;没有什么可以在这里看到,移动...

+0

访问GPU上的有效内存区域,即使未分配,也不一定在cuda mem检查测试之外发出错误。内核不一定会因为小的溢出而失败。你的所有观点仍然有效。 –

+0

@FlorentDUGUET:输入数组是25个双字。内核启动每块使用256个线程。当我运行它(并且是的,我运行它)时,它在cuda-memcheck中产生了数百个无效的内存访问错误。 – talonmies

+0

谢谢你的回复talonmies我欣赏它。这帮助了我很多! – LukaK