CUDA 中 FFT 的使用
CUDA 中 FFT 的使用
@(10.CUDA)[CUDA,并行,fft]
1. 流程
- cufftPlan1d():針對(duì)單個(gè) 1 維信號(hào)
- cufftPlan2d():針對(duì)單個(gè) 2 維信號(hào)
- cufftPlan3d():針對(duì)單個(gè) 3 維信號(hào)
- cufftPlanMany():針對(duì)多個(gè)信號(hào)同時(shí)進(jìn)行 fft
2. 單個(gè) 1 維信號(hào)的 fft
假設(shè)要執(zhí)行 fft 的信號(hào)data_dev的長(zhǎng)度為N,并且已經(jīng)傳輸?shù)?GPU 顯存中,data_dev數(shù)據(jù)的類型為cufftComplex,可以用一下方式產(chǎn)生主機(jī)段的data_dev,如下所示:
cufftComplex *data_Host = (cufftComplex*)malloc(NX*BATCH*sizeof(cufftComplex)); // 主機(jī)端數(shù)據(jù)頭指針// 初始數(shù)據(jù)for (int i = 0; i < NX; i++){data_Host[i].x = float((rand() * rand()) % NX) / NX;data_Host[i].y = float((rand() * rand()) % NX) / NX;}然后用cudaMemcpy()將主機(jī)端的data_host拷貝到設(shè)備端的data_dev,即可用下述方法執(zhí)行 fft :
cufftHandle plan; // 創(chuàng)建cuFFT句柄cufftPlan1d(&plan, N, CUFFT_C2C, BATCH);cufftExecC2C(plan, data_dev, data_dev, CUFFT_FORWARD); // 執(zhí)行 cuFFT,正變換cufftPlan1d():
- 第一個(gè)參數(shù)就是要配置的 cuFFT 句柄;
- 第二個(gè)參數(shù)為要進(jìn)行 fft 的信號(hào)的長(zhǎng)度;
- 第三個(gè)CUFFT_C2C為要執(zhí)行 fft 的信號(hào)輸入類型及輸出類型都為復(fù)數(shù);CUFFT_C2R表示輸入復(fù)數(shù),輸出實(shí)數(shù);CUFFT_R2C表示輸入實(shí)數(shù),輸出復(fù)數(shù);CUFFT_R2R表示輸入實(shí)數(shù),輸出實(shí)數(shù);
- 第四個(gè)參數(shù)BATCH表示要執(zhí)行 fft 的信號(hào)的個(gè)數(shù),新版的已經(jīng)使用cufftPlanMany()來(lái)同時(shí)完成多個(gè)信號(hào)的 fft。
cufftExecC2C():
- 第一個(gè)參數(shù)就是配置好的 cuFFT 句柄;
- 第二個(gè)參數(shù)為輸入信號(hào)的首地址;
- 第三個(gè)參數(shù)為輸出信號(hào)的首地址;
- 第四個(gè)參數(shù)CUFFT_FORWARD表示執(zhí)行的是 fft 正變換;CUFFT_INVERSE表示執(zhí)行 fft 逆變換。
需要注意的是,執(zhí)行完逆 fft 之后,要對(duì)信號(hào)中的每個(gè)值乘以 $\frac{1}{N}$
完整代碼:GitHub
3. 多個(gè) 1 維信號(hào)的 fft
要進(jìn)行多個(gè)信號(hào)的 fft,就不得不使用 cufftPlanMany 函數(shù),該函數(shù)的參數(shù)比較多,需要特別介紹,
cufftPlanMany(cufftHandle *plan, int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch);為了敘述的更準(zhǔn)確,此處先引入一個(gè)圖,表示輸入數(shù)據(jù)在內(nèi)存中的布局,如下圖所示,數(shù)據(jù)在內(nèi)存中按行優(yōu)先存儲(chǔ),但是現(xiàn)有的信號(hào)為一列表示一個(gè)信號(hào),后四列灰白色的表示無(wú)關(guān)數(shù)據(jù),要對(duì)前 12 個(gè)彩色的列信號(hào)分別進(jìn)行 fft。
- plan:表示 cufft 句柄
- rank:表示進(jìn)行 fft 的每個(gè)信號(hào)的維度數(shù),一維信號(hào)為 1,二維信號(hào)為2,三維信號(hào)為 3 ,針對(duì)上圖,rank = 1
- n:表示進(jìn)行 fft 的每個(gè)信號(hào)的行數(shù),列數(shù),頁(yè)數(shù),必須用數(shù)組形式表示,例如假設(shè)要進(jìn)行 fft 的每個(gè)信號(hào)的行、列、頁(yè)為(m, n, k),則 int n[rank] = {m, n, k};針對(duì)上圖,int n[1] = {5}
- inembed:表示輸入數(shù)據(jù)的[頁(yè)數(shù),列數(shù),行數(shù)],這是三維信號(hào)的情況;二維信號(hào)則為[列數(shù),行數(shù)];一維信號(hào)為[行數(shù)];inembed[0] 這個(gè)參數(shù)會(huì)被忽略,也就是此處 inembed 可以為{0},{1},{2}等等。
- istride:表示每個(gè)輸入信號(hào)相鄰兩個(gè)元素的距離,在此處 istride = 16(每個(gè)信號(hào)相鄰兩個(gè)元素間的距離為16)
- idist:表示兩個(gè)連續(xù)輸入信號(hào)的起始元素之間的間隔,在此處為 idist = 1(第一個(gè)信號(hào)的第一個(gè)元素與第二個(gè)信號(hào)的第一個(gè)元素的間隔為1);如果把上圖數(shù)據(jù)的每一行看成一個(gè)信號(hào),那么應(yīng)該為 idist = 16;
- onembed:表示輸出數(shù)據(jù)的[頁(yè)數(shù),列數(shù),行數(shù)],這是三維信號(hào)的情況;二維信號(hào)則為[列數(shù),行數(shù)];一維信號(hào)為[行數(shù)];onembed[0] 這個(gè)參數(shù)會(huì)被忽略,也就是此處 onembed 可以為{0},{1},{2}等等。
- ostride:表示每個(gè)輸出信號(hào)相鄰兩個(gè)元素的距離,在此處 ostride = 16(每個(gè)信號(hào)相鄰兩個(gè)元素間的距離為16)
- odist:表示兩個(gè)連續(xù)信號(hào)的起始元素之間的間隔,在此處為 odist = 1(第一個(gè)信號(hào)的第一個(gè)元素與第二個(gè)信號(hào)的第一個(gè)元素的間隔為1);如果把上圖數(shù)據(jù)的每一行看成一個(gè)信號(hào),那么應(yīng)該為 odist = 16;
如下所示:是第 b 個(gè)信號(hào)的 [z][y][x] (表示第 z 列,第 y 行,第 x 頁(yè)的元素)的索引(由于 c 和 c++ 中數(shù)組的聲明方式的問(wèn)題,array[X][Y][Z]表示數(shù)組有 X 頁(yè),Y 行,Z 列) :
? 1D
input[ b * idist + x * istride ]output[ b * odist + x * ostride ]
? 2D
input[ b * idist + (x * inembed[1] + y) * istride ]output[ b * odist + (x * onembed[1] + y) * ostride ]
? 3D
input[b * idist + (x * inembed[1] * inembed[2] + y * inembed[2] + z) * istride]output[b * odist + (x * onembed[1] * onembed[2] + y * onembed[2] + z) * ostride]
/* 申請(qǐng) cufft 句柄*/cufftHandle plan_Nfft_Many; // 創(chuàng)建cuFFT句柄const int rank = 1; // 一維 fftint n[rank] = { Nfft }; // 進(jìn)行 fft 的信號(hào)的長(zhǎng)度為 Nfftint inembed[1] = { 0 }; // 輸入數(shù)據(jù)的[頁(yè)數(shù),列數(shù),行數(shù)](3維);[列數(shù),行數(shù)](2維)int onembed[1] = { 0 }; // 輸出數(shù)據(jù)的[頁(yè)數(shù),列數(shù),行數(shù)];[列數(shù),行數(shù)](2維)int istride = NXWITH0; // 每個(gè)輸入信號(hào)相鄰兩個(gè)元素的距離int idist = 1; // 每?jī)蓚€(gè)輸入信號(hào)第一個(gè)元素的距離int ostride = NXWITH0; // 每個(gè)輸出信號(hào)相鄰兩個(gè)元素的距離int odist = 1; // 每?jī)蓚€(gè)輸出信號(hào)第一個(gè)元素的距離int batch = NX; // 進(jìn)行 fft 的信號(hào)個(gè)數(shù)cufftPlanMany(&plan_Nfft_Many, rank, n, inembed, istride, idist, onembed, ostride, odist, CUFFT_C2C, batch);/* 核心部份 */cudaMemcpy(data_dev, data_Host, Nfft * NXWITH0 * sizeof(cufftComplex), cudaMemcpyHostToDevice);cufftExecC2C(plan_Nfft_Many, data_dev, data_dev, CUFFT_FORWARD); // 執(zhí)行 cuFFT,正變換cufftExecC2C(plan_Nfft_Many, data_dev, data_dev, CUFFT_INVERSE); // 執(zhí)行 cuFFT,逆變換CufftComplexScale<<<dimGrid2D_NXWITH0_Nfft, dimBlock2D>>>(data_dev, data_dev, 1.0f / Nfft); // 乘以系數(shù)cudaMemcpy(resultIFFT, data_dev, Nfft * NXWITH0 * sizeof(cufftComplex), cudaMemcpyDeviceToHost);完整代碼:GitHub
與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的CUDA 中 FFT 的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java xml dom4j 解析_Ja
- 下一篇: Hibert变换