CUDA 中 FFT 的使用
CUDA 中 FFT 的使用
@(10.CUDA)[CUDA,并行,fft]
1. 流程
- 使用
cufftHandle
创建句柄 - 使用
cufftPlan1d()
,cufftPlan3d()
,cufftPlan3d()
,cufftPlanMany()
对句柄进行配置,主要是配置句柄对应的信号长度,信号类型,在内存中的存储形式等信息。cufftPlan1d()
:针对单个 1 维信号cufftPlan2d()
:针对单个 2 维信号cufftPlan3d()
:针对单个 3 维信号cufftPlanMany()
:针对多个信号同时进行 fft
- 使用
cufftExec()
函数执行 fft - 使用
cufftDestroy()
函数释放 GPU 资源
2. 单个 1 维信号的 fft
假设要执行 fft 的信号data_dev
的长度为N
,并且已经传输到 GPU 显存中,data_dev
数据的类型为cufftComplex
,可以用一下方式产生主机段的data_dev
,如下所示:
cufftComplex *data_Host = (cufftComplex*)malloc(NX*BATCH*sizeof(cufftComplex)); // 主机端数据头指针// 初始数据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()
将主机端的data_host
拷贝到设备端的data_dev
,即可用下述方法执行 fft :
cufftHandle plan; // 创建cuFFT句柄cufftPlan1d(&plan, N, CUFFT_C2C, BATCH);cufftExecC2C(plan, data_dev, data_dev, CUFFT_FORWARD); // 执行 cuFFT,正变换
cufftPlan1d()
:
- 第一个参数就是要配置的 cuFFT 句柄;
- 第二个参数为要进行 fft 的信号的长度;
- 第三个
CUFFT_C2C
为要执行 fft 的信号输入类型及输出类型都为复数;CUFFT_C2R
表示输入复数,输出实数;CUFFT_R2C
表示输入实数,输出复数;CUFFT_R2R
表示输入实数,输出实数; - 第四个参数
BATCH
表示要执行 fft 的信号的个数,新版的已经使用cufftPlanMany()
来同时完成多个信号的 fft。
cufftExecC2C()
:
- 第一个参数就是配置好的 cuFFT 句柄;
- 第二个参数为输入信号的首地址;
- 第三个参数为输出信号的首地址;
- 第四个参数
CUFFT_FORWARD
表示执行的是 fft 正变换;CUFFT_INVERSE
表示执行 fft 逆变换。
需要注意的是,执行完逆 fft 之后,要对信号中的每个值乘以 $\frac{1}{N}$
完整代码:GitHub
3. 多个 1 维信号的 fft
要进行多个信号的 fft,就不得不使用 cufftPlanMany
函数,该函数的参数比较多,需要特别介绍,
cufftPlanMany(cufftHandle *plan, int rank, int *n, int *inembed, int istride, int idist, int *onembed, int ostride, int odist, cufftType type, int batch);
为了叙述的更准确,此处先引入一个图,表示输入数据在内存中的布局,如下图所示,数据在内存中按行优先存储,但是现有的信号为一列表示一个信号,后四列灰白色的表示无关数据,要对前 12 个彩色的列信号分别进行 fft。
- plan:表示 cufft 句柄
- rank:表示进行 fft 的每个信号的维度数,一维信号为 1,二维信号为2,三维信号为 3 ,针对上图,rank = 1
- n:表示进行 fft 的每个信号的行数,列数,页数,必须用数组形式表示,例如假设要进行 fft 的每个信号的行、列、页为(m, n, k),则 int n[rank] = {m, n, k};针对上图,int n[1] = {5}
- inembed:表示输入数据的[页数,列数,行数],这是三维信号的情况;二维信号则为[列数,行数];一维信号为[行数];inembed[0] 这个参数会被忽略,也就是此处 inembed 可以为{0},{1},{2}等等。
- istride:表示每个输入信号相邻两个元素的距离,在此处 istride = 16(每个信号相邻两个元素间的距离为16)
- idist:表示两个连续输入信号的起始元素之间的间隔,在此处为 idist = 1(第一个信号的第一个元素与第二个信号的第一个元素的间隔为1);如果把上图数据的每一行看成一个信号,那么应该为 idist = 16;
- onembed:表示输出数据的[页数,列数,行数],这是三维信号的情况;二维信号则为[列数,行数];一维信号为[行数];onembed[0] 这个参数会被忽略,也就是此处 onembed 可以为{0},{1},{2}等等。
- ostride:表示每个输出信号相邻两个元素的距离,在此处 ostride = 16(每个信号相邻两个元素间的距离为16)
- odist:表示两个连续信号的起始元素之间的间隔,在此处为 odist = 1(第一个信号的第一个元素与第二个信号的第一个元素的间隔为1);如果把上图数据的每一行看成一个信号,那么应该为 odist = 16;
如下所示:是第 b 个信号的 [z][y][x] (表示第 z 列,第 y 行,第 x 页的元素)的索引(由于 c 和 c++ 中数组的声明方式的问题,array[X][Y][Z]表示数组有 X 页,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]
/* 申请 cufft 句柄*/cufftHandle plan_Nfft_Many; // 创建cuFFT句柄const int rank = 1; // 一维 fftint n[rank] = { Nfft }; // 进行 fft 的信号的长度为 Nfftint inembed[1] = { 0 }; // 输入数据的[页数,列数,行数](3维);[列数,行数](2维)int onembed[1] = { 0 }; // 输出数据的[页数,列数,行数];[列数,行数](2维)int istride = NXWITH0; // 每个输入信号相邻两个元素的距离int idist = 1; // 每两个输入信号第一个元素的距离int ostride = NXWITH0; // 每个输出信号相邻两个元素的距离int odist = 1; // 每两个输出信号第一个元素的距离int batch = NX; // 进行 fft 的信号个数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); // 执行 cuFFT,正变换cufftExecC2C(plan_Nfft_Many, data_dev, data_dev, CUFFT_INVERSE); // 执行 cuFFT,逆变换CufftComplexScale<<<dimGrid2D_NXWITH0_Nfft, dimBlock2D>>>(data_dev, data_dev, 1.0f / Nfft); // 乘以系数cudaMemcpy(resultIFFT, data_dev, Nfft * NXWITH0 * sizeof(cufftComplex), cudaMemcpyDeviceToHost);
完整代码:GitHub
CUDA 中 FFT 的使用相关推荐
- C语言使用CUDA中cufft函数做GPU加速FFT运算,与调用fftw函数的FFT做运算速度对比
目录 任务介绍 环境所需相关软件下载与安装 C语言:不调用库的GPU加速FFT代码 C语言:调用fftw库的未使用GPU的FFT代码 C语言:调用cufft库的GPU加速FFT gnuplot安装画图 ...
- CUDA实现FFT并行计算
前言 本文是个人学习心得的分享,希望大家在阅读文章后能在评论中一起学习交流!另外还可以访问我的HelloCUDA仓库查看我在学习CUDA中写的一些demo程序. 内容概要 复数的CUDA C++实 ...
- CUDA中grid、block、thread、warp与SM、SP的关系
首先概括一下这几个概念.其中SM(Streaming Multiprocessor)和SP(streaming Processor)是硬件层次的,其中一个SM可以包含多个SP.thread是一个线程, ...
- java如何给一个链表定义和传值_如何在CUDA中为Transformer编写一个PyTorch自定义层...
如今,深度学习模型处于持续的演进中,它们正变得庞大而复杂.研究者们通常通过组合现有的 TensorFlow 或 PyTorch 操作符来发现新的架构.然而,有时候,我们可能需要通过自定义的操作符来实现 ...
- Cuda中Global memory中coalescing例程解释
Global memory是cuda中最常见的存储类型,又叫做Device memory,位于Host主机区域上,它的生命周期是在整个Grid里面,大约具有500个cycle latency.在cud ...
- [原]CUDA中grid、block、thread、warp与SM、SP的关系
[原]CUDA中grid.block.thread.warp与SM.SP的关系 2015-3-27阅读209 评论0 首先概括一下这几个概念.其中SM(Streaming Multiprocessor ...
- CUDA中的一些基本概念
线程 线程是CUDA中并行程序的基本构建,一个线程就是程序中国的一个单一的执行流,就像一件衣服上的一块棉,一块块棉交织在一起组成衣服,同样 一个个线程组成成并行程序. 随着处理器的核越来越多,硬件可以 ...
- CUDA中并行规约(Parallel Reduction)的优化
Parallel Reduction是NVIDIA-CUDA自带的例子,也几乎是所有CUDA学习者的的必看算法.在这个算法的优化中,Mark Harris为我们实现了7种不同的优化版本,将Bandwi ...
- CUDA中的复数定义、开内存空间以及运算
最近在做时频混合域的全波形反演(FWI),用CUDA加速,要做复数运算,所以研究了一下CUDA中复数运算等.简单说一下CUDA中复数的基本应用. 在CUDA中用CUFFT的库来定义与运算复数,基本如下 ...
最新文章
- (转)使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
- MongoDB 索引
- 亲历惊心48小时抢救35亿交易数据
- 自定义带DropDownTable的TextField(事件)
- socket 编程入门教程(一)TCP server 端:1、建模
- DataCleaner(4.5)第一章
- KDD Cup2020 正式开赛,天池诚邀各路豪杰来挑战!!
- 前端JS笔试面试题目
- 穹顶之下 众信金融邀您共植树助环保
- setwindowpos怎么改变z序_Windows转Mac——操作习惯的改变!
- 安装django步骤
- 配置Gitlab Push自动触发jenkins构建
- win10无法安装软件,点击大部分exe文件无反应,无提示(安装了火绒)
- 泛微E9 MVC开发
- 书到用时方恨少,一大波JS开发工具函数来了
- Excel在统计分析中的应用—第十二章—回归分析与预测-运用LINEST函数进行多元线性回归分析
- 服务器系统如何重装?
- python面向对象的特征_python 面向对象的三大特性
- 遭遇“windows已经阻止此软件因为无法验证发行者”
- 牛客练习赛51 C、勾股定理 只一边求另外两边 结论