CUDA公式ライブラリ:フーリエ変換(CUFFT)関連ライブラリ関数の使用例

はじめに

本稿では、CUDA環境におけるFFT(高速フーリエ変換)処理のために用いられるcuFFTライブラリの 주요関数について、その使用方法を具体的なコード例とともに解説する。

cufftExecC2C()使用例

実装手順:

  1. 入力データと出力用配列を確保し、GPUメモリ上に配置する;
  2. 入力データを初期化し、ホストメモリからGPUメモリへ転送する;
  3. cuFFTプランを生成し、cufftExecC2C()関数を用いてFFT変換を実行する;
  4. cuFFTプランを解放する;
  5. 計算結果をGPUメモリからホストメモリへ転送し、値を出力する;
  6. 確保したメモリを解放する;

一次元フーリエ変換(FFT)の実装:

#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>

int main() {
   // 配列の次元数を設定
   const int arraySize = 8;
   const int bufferSize = sizeof(cufftComplex) * arraySize;

   // 入力・出力用ポインタを宣言
   cufftComplex *inputBuffer;
   cufftComplex *outputBuffer;

   // GPUメモリを確保
   cudaMalloc((void**)&inputBuffer, bufferSize);
   cudaMalloc((void**)&outputBuffer, bufferSize);

   // ホスト側の一時配列を初期化
   cufftComplex *tempArray = (cufftComplex*)malloc(bufferSize);
   for (int idx = 0; idx < arraySize; ++idx) {
       tempArray[idx].x = static_cast<float>(idx);
       tempArray[idx].y = 0.0f;
   }

   // ホストからデバイスへデータをコピー
   cudaMemcpy(inputBuffer, tempArray, bufferSize, cudaMemcpyHostToDevice);

   // cuFFTプランを生成(一次元変換)
   cufftHandle fftPlan;
   cufftPlan1d(&fftPlan, arraySize, CUFFT_C2C, 1);

   // 順変換を実行
   cufftExecC2C(fftPlan, inputBuffer, outputBuffer, CUFFT_FORWARD);

   // プランを破棄
   cufftDestroy(fftPlan);

   // 計算結果をデバイスからホストへコピー
   cudaMemcpy(tempArray, outputBuffer, bufferSize, cudaMemcpyDeviceToHost);

   // 結果を出力
   printf("変換結果:\n");
   for (int idx = 0; idx < arraySize; ++idx) {
       printf("[%d] 実部: %f, 虚部: %f\n", idx, tempArray[idx].x, tempArray[idx].y);
   }

   // メモリを解放
   cudaFree(inputBuffer);
   cudaFree(outputBuffer);
   free(tempArray);

   return 0;
}

二次元フーリエ変換(FFT)の実装:

#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>

int main() {
   // 行列の高さと幅を定義
   const int height = 4;
   const int width = 4;
   const int totalElements = height * width;
   const int bufferSize = sizeof(cufftComplex) * totalElements;

   // 入力・出力用ポインタを宣言
   cufftComplex *devInput;
   cufftComplex *devOutput;

   // GPUメモリを確保
   cudaMalloc((void**)&devInput, bufferSize);
   cudaMalloc((void**)&devOutput, bufferSize);

   // ホスト側の一時配列を初期化
   cufftComplex *hostBuffer = (cufftComplex*)malloc(bufferSize);
   for (int row = 0; row < height; ++row) {
       for (int col = 0; col < width; ++col) {
           const int linearIdx = row * width + col;
           hostBuffer[linearIdx].x = static_cast<float>(row + col);
           hostBuffer[linearIdx].y = 0.0f;
       }
   }

   // ホストからデバイスへデータをコピー
   cudaMemcpy(devInput, hostBuffer, bufferSize, cudaMemcpyHostToDevice);

   // cuFFTプランを生成(二次元変換)
   cufftHandle fftPlan;
   cufftPlan2d(&fftPlan, height, width, CUFFT_C2C);

   // 順変換を実行
   cufftExecC2C(fftPlan, devInput, devOutput, CUFFT_FORWARD);

   // プランを破棄
   cufftDestroy(fftPlan);

   // 計算結果をデバイスからホストへコピー
   cudaMemcpy(hostBuffer, devOutput, bufferSize, cudaMemcpyDeviceToHost);

   // 結果を出力(二次元配列形式)
   printf("変換結果:\n");
   for (int row = 0; row < height; ++row) {
       for (int col = 0; col < width; ++col) {
           const int linearIdx = row * width + col;
           printf("(%f, %f)\t", hostBuffer[linearIdx].x, hostBuffer[linearIdx].y);
       }
       printf("\n");
   }

   // メモリを解放
   cudaFree(devInput);
   cudaFree(devOutput);
   free(hostBuffer);

   return 0;
}

三次元フーリエ変換(FFT)の実装:

#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>

int main() {
   // 三次元配列の 각 차원을 정의
   const int dimX = 4;
   const int dimY = 4;
   const int dimZ = 4;
   const int elementCount = dimX * dimY * dimZ;
   const int bufferSize = sizeof(cufftComplex) * elementCount;

   // 入力・出力用ポインタを宣言
   cufftComplex *gpuBufferIn;
   cufftComplex *gpuBufferOut;

   // GPUメモリを確保
   cudaMalloc((void**)&gpuBufferIn, bufferSize);
   cudaMalloc((void**)&gpuBufferOut, bufferSize);

   // ホスト側の一時配列を初期化
   cufftComplex *cpuTemp = (cufftComplex*)malloc(bufferSize);
   for (int x = 0; x < dimX; ++x) {
       for (int y = 0; y < dimY; ++y) {
           for (int z = 0; z < dimZ; ++z) {
               const int idx = (x * dimY + y) * dimZ + z;
               cpuTemp[idx].x = static_cast<float>(x + y + z);
               cpuTemp[idx].y = 0.0f;
           }
       }
   }

   // ホストからデバイスへデータをコピー
   cudaMemcpy(gpuBufferIn, cpuTemp, bufferSize, cudaMemcpyHostToDevice);

   // cuFFTプランを生成(三次元変換)
   cufftHandle fftPlan;
   cufftPlan3d(&fftPlan, dimX, dimY, dimZ, CUFFT_C2C);

   // 順変換を実行
   cufftExecC2C(fftPlan, gpuBufferIn, gpuBufferOut, CUFFT_FORWARD);

   // プランを破棄
   cufftDestroy(fftPlan);

   // 計算結果をデバイスからホストへコピー
   cudaMemcpy(cpuTemp, gpuBufferOut, bufferSize, cudaMemcpyDeviceToHost);

   // 結果を出力(三次元配列形式)
   printf("変換結果:\n");
   for (int x = 0; x < dimX; ++x) {
       for (int y = 0; y < dimY; ++y) {
           for (int z = 0; z < dimZ; ++z) {
               const int idx = (x * dimY + y) * dimZ + z;
               printf("(%f, %f)\t", cpuTemp[idx].x, cpuTemp[idx].y);
           }
           printf("\n");
       }
       printf("---\n");
   }

   // メモリを解放
   cudaFree(gpuBufferIn);
   cudaFree(gpuBufferOut);
   free(cpuTemp);

   return 0;
}

タグ: CUDA CUFFT FFT GPU 並列計算

7月5日 23:19 投稿