NaN проблемы с cuFFT

Я пишу приложение частотной фильтрации для школьного задания на C ++ и Cuda, используя cuFFT, и я не могу заставить его работать. Вы можете найти все решение Visual Studio 2010 Вот. (потребности перенасыщение.)

Вот та часть, которая, на мой взгляд, актуальна: (fourierUtils.cu/194)

//////////////////////////////////////////////////////////////////////////////
// Function to help invoking the kernel, creates the parameters and gets
// the result
__host__
void Process(
BitmapStruct& in_img, // these contain an image in an rgba byte array
BitmapStruct& out_img,
MaskGenerator maskGenerator, // this is a pointer to a device function
float param1, // mask parameters
float param2)
{
// Declare and allocate variables
cufftHandle plan;

cufftReal* img;
cufftReal* dev_img;
cufftComplex* dev_freq_img;

int imgsize = in_img.image_size();
int pixelcount = imgsize / 4;

img = new float[pixelcount];
checkResult(
cudaMalloc(&dev_img, sizeof(cufftReal) * pixelcount));
checkResult(
cudaMalloc(&dev_freq_img, sizeof(cufftComplex) * pixelcount));

// Optimize execution
cudaFuncAttributes attrs;
checkResult(
cudaFuncGetAttributes(&attrs, &Filter));
std::pair<dim3, dim3> params
= Optimizer::GetOptimalParameters(pixelcount, attrs);

// Process r, g, b channels
for(int chan = 0; chan <= 2; chan++)
{
// Init
for(int i = 0; i < pixelcount; i++)
{
img[i] = in_img.pixels[4 * i + chan];
}

checkResult(
cudaMemcpy(dev_img, img, pixelcount, cudaMemcpyHostToDevice));

// Create frequency image
checkResult(
cufftPlan1d(&plan, pixelcount, CUFFT_R2C, 1));
checkResult(
cufftExecR2C(plan, dev_img, dev_freq_img));
checkResult(
cudaThreadSynchronize());
checkResult(
cufftDestroy(plan));

// Mask frequency image
Filter<<<params.first, params.second>>>(
dev_freq_img, in_img.x, in_img.y, maskGenerator, param1, param2);
getLastCudaError("Filtering the image failed.");

// Get result
checkResult(
cufftPlan1d(&plan, pixelcount, CUFFT_C2R, 1));
checkResult(
cufftExecC2R(plan, dev_freq_img, dev_img));
checkResult(
cudaThreadSynchronize());
checkResult(
cufftDestroy(plan));
checkResult(
cudaMemcpy(img, dev_img, pixelcount, cudaMemcpyDeviceToHost));

for(int i = 0; i < pixelcount; i++)
{
out_img.pixels[4 * i + chan] = img[i];
}
}

// Copy alpha channel
for(int i = 0; i < pixelcount; i++)
{
out_img.pixels[4 * i + 3] = in_img.pixels[4 * i + 3];
}

// Free memory
checkResult(
cudaFree(dev_freq_img));
checkResult(
cudaFree(dev_img));
delete img;

getLastCudaError("An error occured during processing the image.");
}

Я не вижу никаких практических различий по сравнению с официальными примерами, которые я видел, но когда я отлаживаю в нем с помощью Nsight, все значения cufftComplex, полученные моим ядром, являются NaN, и единственная разница между вход и результат изображения таковы, что результат имеет черную полосу внизу, независимо от того, какую маску фильтрации и какие параметры я использую. Все вызовы Cuda и cuFFT возвращаются успешно, и после вызова ядра также не сообщается об ошибке.

Что я делаю не так?

Я пытался заменить img и dev_img на сложные массивы и использовать преобразования C2C, а также делать их на месте, но это только изменило размер черной полосы на результирующем изображении.

Спасибо за помощь.

Редактировать: Вот является сокращенной версией, которая не требует перенасыщения и должна также компилироваться в Linux.

0

Решение

Я не скомпилировал и не запустил вашу уменьшенную версию, но я думаю, что проблема в размере dev_img а также dev_freq_imag,

Рассмотрим пример из Раздела 4.2 Руководства пользователя библиотеки CUFFT. Он выполняет преобразование реального объекта в сложное, то есть тот же шаг, который вы выполняете первым.

#define NX 256

cufftHandle plan;
cufftComplex *data;
cudaMalloc((void**)&data, sizeof(cufftComplex)*(NX/2+1)*BATCH);

cufftPlan1d(&plan, NX, CUFFT_R2C, BATCH);
cufftExecR2C(plan, (cufftReal*)data, data);

Из-за свойств симметрии преобразования, cufftExecR2C только заполняет NX/2+1 выходные элементы, где NX размер входного массива

В вашем случае вы делаете следующее:

cufftHandle plan;

cufftReal* dev_img;
cufftComplex* dev_freq_img;

cudaMalloc(&dev_img, sizeof(cufftReal) * pixelcount);
cudaMalloc(&dev_freq_img, sizeof(cufftComplex) * pixelcount);

так что вы выделяете cufftReal массив и cufftComplex массив одинакового размера. Когда вы используете

cufftPlan1d(&plan, pixelcount, CUFFT_R2C, 1);
cufftExecR2C(plan, dev_img, dev_freq_img);

тогда только половина dev_freq_img заполнен cufftExecR2CОстальная часть содержит мусор. Если вы используете в полной мере dev_freq_img в Filter __global__ функции, то это, вероятно, будет причиной вашего NaNs.

2

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

Моя ошибка заключалась в том, что я забыл умножить количество предметов на их размер в некоторых cudaMemcpy вызовы, таким образом, конец векторов, подаваемых в cuFFT, был составлен из NaN. Исправление этих проблем решило проблему.

Я также заменил массивы cufftReal на cufftComplex, так как преобразования C2C кажутся более предсказуемыми и добавили нормализацию для значений.

Итак, последний метод работы:

///////////////////////////////////////////////////////////////////////////////
// Function to help invoking the kernel, creates the parameters and gets
// the result
__host__
void Process(
BitmapStruct& in_img,
BitmapStruct& out_img,
MaskGenerator maskGenerator,
float param1,
float param2)
{
// Declare and allocate variables
cufftHandle plan;

cufftComplex* img;
cufftComplex* dev_img;
cufftComplex* dev_freq_img;

int imgsize = in_img.image_size();
int pixelcount = imgsize / 4;

img = new cufftComplex[pixelcount];
checkResult(
cudaMalloc(&dev_img, sizeof(cufftComplex) * pixelcount));
checkResult(
cudaMalloc(&dev_freq_img, sizeof(cufftComplex) * pixelcount));

// Optimize execution
cudaFuncAttributes attrs;
checkResult(
cudaFuncGetAttributes(&attrs, &Filter));
std::pair<dim3, dim3> params =
Optimizer::GetOptimalParameters(pixelcount, attrs);

// Process r, g, b channels
for(int chan = 0; chan <= 2; chan++)
{
// Init
for(int i = 0; i < pixelcount; i++)
{
img[i].x = in_img.pixels[4 * i + chan];
img[i].y = 0;
}

checkResult(
cudaMemcpy(
dev_img,
img,
pixelcount * sizeof(cufftComplex),
cudaMemcpyHostToDevice));

// Create frequency image
checkResult(
cufftPlan1d(&plan, pixelcount, CUFFT_C2C, 1));
checkResult(
cufftExecC2C(plan, dev_img, dev_freq_img, CUFFT_FORWARD));
checkResult(
cudaThreadSynchronize());
checkResult(
cufftDestroy(plan));

// Mask frequency image
Filter<<<params.first, params.second>>>(
dev_freq_img,
in_img.x,
in_img.y,
maskGenerator,
param1,
param2);
getLastCudaError("Filtering the image failed.");

// Get result
checkResult(
cufftPlan1d(&plan, pixelcount, CUFFT_C2C, 1));
checkResult(
cufftExecC2C(plan, dev_freq_img, dev_img, CUFFT_INVERSE));
checkResult(
cudaThreadSynchronize());
checkResult(
cufftDestroy(plan));
checkResult(
cudaMemcpy(
img,
dev_img,
pixelcount * sizeof(cufftComplex),
cudaMemcpyDeviceToHost));

for(int i = 0; i < pixelcount; i++)
{
out_img.pixels[4 * i + chan] = img[i].x / pixelcount;
}
}

// Copy alpha channel
for(int i = 0; i < pixelcount; i++)
{
out_img.pixels[4 * i + 3] = in_img.pixels[4 * i + 3];
}

// Free memory
checkResult(
cudaFree(dev_freq_img));
checkResult(
cudaFree(dev_img));
delete img;

getLastCudaError("An error occured during processing the image.");
}

Спасибо вам за помощь.

1

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