je suis un tutoriel sur l'utilisation de la bibliothèque cuFFT
ici: http://gpgpu.org/static/sc2007/SC07_CUDA_3_Libraries.pdfRésoudre l'équation de Poisson en utilisant FFT avec CUDA
Après avoir suivi la ligne par ligne de son code, je suis vraiment obtenir des résultats étranges.
J'ai des données d'entrée qui est un tableau NxN
de float
s. Le programme effectue une transformée directe FFT
, résout l'équation de Poisson, puis fait un inverse FFT
. Les données d'entrée (et les données de sortie) sont appelées une image carrée avec une longueur latérale N
. Lorsque je commente solve_poisson <<<dimGrid, dimBlock>>> (r_complex_d, kx_d, ky_d, N);
, il transfère correctement les données vers l'avant puis effectue une transformation inverse, ce qui entraîne les données de sortie à être les mêmes que les données d'entrée. C'est censé arriver.
Voici la sortie sans appeler la méthode solve_poisson
.
0 r_initial: 0.00125126 r: 0.00125132
1 r_initial: 0.563585 r: 0.563585
2 r_initial: 0.193304 r: 0.193304
3 r_initial: 0.80874 r: 0.80874
4 r_initial: 0.585009 r: 0.585009
5 r_initial: 0.479873 r: 0.479873
6 r_initial: 0.350291 r: 0.350291
7 r_initial: 0.895962 r: 0.895962
8 r_initial: 0.82284 r: 0.82284
9 r_initial: 0.746605 r: 0.746605
10 r_initial: 0.174108 r: 0.174108
11 r_initial: 0.858943 r: 0.858943
12 r_initial: 0.710501 r: 0.710502
13 r_initial: 0.513535 r: 0.513535
14 r_initial: 0.303995 r: 0.303995
15 r_initial: 0.0149846 r: 0.0149846
Press any key to continue . . .
Cependant, quand je décommentez la méthode solve_poisson
, les données de sortie est inf
ou nan
, ce qui me porte à croire que la variable d'échelle était en quelque sorte proche de zéro dans la méthode solve_poisson
. J'ai donc changé float scale = -(kx[idx] * kx[idx] + ky[idy] * ky[idy]);
en float scale = -(kx[idx] * kx[idx] + ky[idy] * ky[idy]) + 0.00001f
. Cette modification ne figure pas dans le didacticiel d'origine. Les résultats calculés ici ne sont pas supposés avoir des valeurs extrêmes positives ou négatives.
0 r_initial: 0.00125126 r: -11448.1
1 r_initial: 0.563585 r: 11449.3
2 r_initial: 0.193304 r: -11448.3
3 r_initial: 0.80874 r: 11449.2
4 r_initial: 0.585009 r: 11449.4
5 r_initial: 0.479873 r: -11448.4
6 r_initial: 0.350291 r: 11449.5
7 r_initial: 0.895962 r: -11448.6
8 r_initial: 0.82284 r: -11448.5
9 r_initial: 0.746605 r: 11449.4
10 r_initial: 0.174108 r: -11448.3
11 r_initial: 0.858943 r: 11449.3
12 r_initial: 0.710501 r: 11449.2
13 r_initial: 0.513535 r: -11448.4
14 r_initial: 0.303995 r: 11449.3
15 r_initial: 0.0149846 r: -11448.1
Press any key to continue . . .
Dans le didacticiel, un exemple de calcul sur la diapositive 43
à la page 22
est computed=0.975879 reference=0.975882
, mais mes résultats sont complètement différents et vraiment grand.
Le code suivant est ce que j'ai utilisé.
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <cufft.h>
#include <stdlib.h>
#include <iostream>
#define N 4 //4 X 4 // N is the sidelength of the image -> 16 pixels in entire image
#define block_size_x 2
#define block_size_y 2
__global__ void real2complex(cufftComplex *c, float *a, int n);
__global__ void complex2real_scaled(float *a, cufftComplex *c, float scale, int n);
__global__ void solve_poisson(cufftComplex *c, float *kx, float *ky, int n);
int main()
{
float *kx, *ky, *r;
kx = (float *)malloc(sizeof(float) * N);
ky = (float *)malloc(sizeof(float) * N);
r = (float *)malloc(sizeof(float) * N * N);
float *kx_d, *ky_d, *r_d;
cufftComplex *r_complex_d;
cudaMalloc((void **)&kx_d, sizeof(float) * N);
cudaMalloc((void **)&ky_d, sizeof(float) * N);
cudaMalloc((void **)&r_d, sizeof(float) * N * N);
cudaMalloc((void **)&r_complex_d, sizeof(cufftComplex) * N * N);
for (int y = 0; y < N; y++)
for (int x = 0; x < N; x++)
r[x + y * N] = rand()/(float)RAND_MAX;
//r[x + y * N] = sin(exp(-((x - N/2.0f) * (x - N/2.0f) + (N/2.0f - y) * (N/2.0f - y))/(20 * 20))) * 255/sin(1); //Here is sample data that will high values at the center of the image and low values as you go farther and farther away from the center.
float* r_inital = (float *)malloc(sizeof(float) * N * N);
for (int i = 0; i < N * N; i++)
r_inital[i] = r[i];
for (int i = 0; i < N; i++)
{
kx[i] = i - N/2.0f; //centers kx values to be at center of image
ky[i] = N/2.0f - i; //centers ky values to be at center of image
}
cudaMemcpy(kx_d, kx, sizeof(float) * N, cudaMemcpyHostToDevice);
cudaMemcpy(ky_d, ky, sizeof(float) * N, cudaMemcpyHostToDevice);
cudaMemcpy(r_d, r, sizeof(float) * N * N, cudaMemcpyHostToDevice);
cufftHandle plan;
cufftPlan2d(&plan, N, N, CUFFT_C2C);
/* Compute the execution configuration, block_size_x*block_size_y = number of threads */
dim3 dimBlock(block_size_x, block_size_y);
dim3 dimGrid(N/dimBlock.x, N/dimBlock.y);
/* Handle N not multiple of block_size_x or block_size_y */
if (N % block_size_x != 0) dimGrid.x += 1;
if (N % block_size_y != 0) dimGrid.y += 1;
real2complex << < dimGrid, dimBlock >> > (r_complex_d, r_d, N);
cufftExecC2C(plan, r_complex_d, r_complex_d, CUFFT_FORWARD);
solve_poisson << <dimGrid, dimBlock >> > (r_complex_d, kx_d, ky_d, N);
cufftExecC2C(plan, r_complex_d, r_complex_d, CUFFT_INVERSE);
float scale = 1.0f/(N * N);
complex2real_scaled << <dimGrid, dimBlock >> > (r_d, r_complex_d, scale, N);
cudaMemcpy(r, r_d, sizeof(float) * N * N, cudaMemcpyDeviceToHost);
for (int i = 0; i < N * N; i++)
std::cout << i << "\tr_initial: " << r_inital[i] << "\tr: " << r[i] << std::endl;
system("pause");
/* Destroy plan and clean up memory on device*/
free(kx);
free(ky);
free(r);
free(r_inital);
cufftDestroy(plan);
cudaFree(r_complex_d);
cudaFree(kx_d);
}
__global__ void real2complex(cufftComplex *c, float *a, int n)
{
/* compute idx and idy, the location of the element in the original NxN array */
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int idy = blockIdx.y * blockDim.y + threadIdx.y;
if (idx < n && idy < n)
{
int index = idx + idy * n;
c[index].x = a[index];
c[index].y = 0.0f;
}
}
__global__ void complex2real_scaled(float *a, cufftComplex *c, float scale, int n)
{
/* compute idx and idy, the location of the element in the original NxN array */
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int idy = blockIdx.y * blockDim.y + threadIdx.y;
if (idx < n && idy < n)
{
int index = idx + idy * n;
a[index] = scale * c[index].x;
}
}
__global__ void solve_poisson(cufftComplex *c, float *kx, float *ky, int n)
{
/* compute idx and idy, the location of the element in the original NxN array */
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int idy = blockIdx.y * blockDim.y + threadIdx.y;
if (idx < n && idy < n)
{
int index = idx + idy * n;
float scale = -(kx[idx] * kx[idx] + ky[idy] * ky[idy]) + 0.00001f;
if (idx == 0 && idy == 0) scale = 1.0f;
scale = 1.0f/scale;
c[index].x *= scale;
c[index].y *= scale;
}
}
Y a-t-il quelque chose que j'ai raté? J'apprécierais vraiment que quelqu'un puisse m'aider.
Yo Vos choix pour 'kx' et' ky' me semblent cassés. Le code matlab d'origine dans la présentation que vous avez liée crée un meshgrid pour ceux-ci, pas la chose «centrée» que vous avez créée. Le code solve_poisson s'attend à ce que le "meshgrid" basé sur C++ équivalent ait une entrée 0,0 à 'kx [0]' et 'ky [0]', et il a une ligne de code spécifique pour adresser ce cas particulier. Vous avez déplacé cette entrée 0,0 ailleurs dans la grille, de sorte que le code original de solve_poisson "explose" à ce moment, en raison de la division par zéro. Votre "solution" d'ajouter une petite valeur n'est pas une solution. Vous devez trouver le point zéro et ajouter 1 là. –
Revenez à la version originale de 'solve_poisson', sans votre ajout. Dans ce 'solve_poisson', changez cette ligne:' if (idx == 0 && idy == 0) scale = 1.0f; 'à ceci:' if (idx == 2 && idy == 2) scale = 1.0f; 'pour tenir compte de votre mouvement du point zéro, et réexécutez votre test. Si vous changez «N», ou faites d'autres changements, ceci sera immédiatement cassé encore, ainsi vous devrez y penser soigneusement. –
Ah merci beaucoup! Oui, faire cela correctement centré pour le tableau 4x4. Dans la méthode 'solve_poisson', j'ai remplacé' if (idx == 2 && idy == 2) échelle = 1.0f; 'avec' if (idx == n/2 && idy == n/2) échelle = 1.0f ; 'donc il généraliserait pour tous les tableaux NxN. Vous êtes un sauveur! – sciencelord