Пример CUDA cufft 2D

В настоящее время я работаю над программой, которая должна реализовать 2D-FFT (для взаимной корреляции). Я сделал 1D FFT с CUDA, который дал мне правильные результаты, сейчас я пытаюсь реализовать 2D версию. С несколькими примерами и документацией в Интернете мне трудно понять, в чем заключается ошибка.

До сих пор я использовал только руководство cuFFT.

В любом случае, я создал два массива 5х5 и заполнил их единицами. Я скопировал их в память графического процессора и сделал FFT вперед, умножил их, а затем сделал результат на результат. Это дает мне массив 5×5 со значениями 650. Я ожидаю получить сигнал постоянного тока со значением 25 только в одном слоте в массиве 5×5. Вместо этого я получаю 650 во всем массиве.

Кроме того, мне не разрешается распечатывать значение сигнала после его копирования в память графического процессора. Пишу

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

2

Решение

Это дает мне массив 5×5 со значениями 650 : На нем написано 625, что составляет 5 * 5 * 5 * 5. Используемый вами алгоритм свертки требует дополнительного деления на N * N. Действительно, в CUFFT, в прямом преобразовании нет коэффициента нормализации. Следовательно, ваша свертка не может быть простым умножением двух полей в частотной области. (некоторые назвали бы это математиками DFT, а не врачами DFT).

Кроме того, мне не разрешается распечатывать значение сигнала после его копирования в память графического процессора.Это стандартное поведение CUDA. При распределении памяти на устройстве данные существуют в адресном пространстве памяти устройства и не могут быть доступны ЦП без дополнительных усилий. Ищи удалось память или zerocopy чтобы данные были доступны с обеих сторон PCI Express (это обсуждается во многих других публикациях).

0

Другие решения

Здесь есть несколько проблем:

  1. Вы запускаете слишком много потоков для размера входных массивов в ядре умножения, так что это должно привести к сбою из-за ошибок памяти за пределами допустимого диапазона. Я удивлен, что вы не получаете никаких ошибок во время выполнения.
  2. Я полагаю, что ваше ожидаемое решение для последовательности fft / fft — dot неверно. Правильным решением будет матрица 5х5 с 25 в каждой записи.
  3. Как четко описано в документации cuFFT, библиотека выполняет unnormalised FFTs:

    cuFFT выполняет ненормализованные FFT; то есть выполнение прямого БПФ для набора входных данных, за которым следует обратное БПФ для результирующего набора, дает данные, равные вводу, масштабированные по количеству элементов. Масштабирование любого преобразования на величину, обратную размеру набора данных, остается для пользователя, чтобы он выполнял его по своему усмотрению.

Итак, по моим расчетам, правильное решение для вывода вашего кода должно быть матрицей 5×5 с 625 в каждой записи, что было бы нормализовано к матрице 5×5 с 25 в каждой записи, т.е. ожидаемый результат. Я не понимаю, как проблема в (1) не дает других результатов, так как ядро ​​умножения должно давать сбой.

TLDR; здесь нечего видеть, двигайся …

2

По вопросам рекламы [email protected]