我目前正在开发一个必须实现2D-FFT的程序(用于交叉相关)。我用CUDA进行了1D FFT,这给了我正确的结果,我现在正在尝试实现2D版本。在线的例子和文档很少,我发现很难找出错误是什么。
到目前为止,我一直只使用cuFFT手册。
无论如何,我创建了两个5x5阵列并用1填充它们。我已将它们复制到GPU内存并完成正向FFT,然后将它们相乘,然后对结果进行ifft。这给了我一个值为650的5x5阵列。我希望在5x5阵列的一个插槽中得到一个值为25的DC信号。相反,我在整个阵列中得到650。
此外,我不允许在将信号复制到GPU内存后打印出信号的值。写作
cout << d_signal[1].x << endl;
给我一个访问权限违规。我在其他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 :(得分:2)
这里有几个问题:
cuFFT执行非标准化FFT;也就是说,对输入数据集执行前向FFT,然后对得到的集合进行逆FFT,产生等于输入的数据,按元素数量进行缩放。通过数据集大小的倒数来缩放变换,留给用户按照适合的方式执行。
因此,通过我的计算,代码的正确输出解决方案应该是5x5矩阵,每个条目中有625个,这将被标准化为5x5矩阵,每个条目25个,即。预期的结果。我不明白(1)的问题是如何产生不同的结果,因为乘法内核应该失败。
TLDR;没什么可看的,继续前进......
答案 1 :(得分:0)
这给了我一个5x5数组,其值为650 :它读取625,即5 * 5 * 5 * 5。您使用的卷积算法需要N * N的补充除法。实际上,在cufft中,正向变换中没有归一化系数。因此,您的卷积不能是频域中两个场的简单乘法。 (有些人称之为数学家DFT,而不是医生DFT)。
此外,我不允许在将信号复制到GPU内存后打印出信号值 :这是标准的CUDA行为。在设备上分配内存时,数据存在于设备内存地址空间中,如果没有额外的努力,CPU无法访问。搜索托管内存或 zerocopy 以便从PCI Express的两端访问数据(这在许多其他帖子中都有讨论)。