描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302493174
作者简介赵地获得美国路易斯安娜理工大学(Louisiana Tech University)计算机与应用数学专业博士学位,曾在美国哥伦比亚大学(Columbia University)和美国俄亥俄州立大学(The Ohio State University)从事博士后研究工作。 赵地博士在GPU计算方面具有丰富的研究经验,发表了多篇学术论文和会议论文。现任CNIC-英伟达公司GPU研究中心(GPU Research Center, GRC)、CNIC-英伟达公司GPU教育中心(GPU Education Center, GEC)和CNIC-英伟达公司“智慧医疗”联合实验室负责人;中国图象图形学学会视觉大数据专业委员会委员,CCF会员。
本书首先介绍了MATLAB程序的性能评估的方法,帮助读者找到制约MATLAB程序运行速度的“瓶颈”所在; 接着循序渐进地介绍加速MATLAB编程的方法,包括基于多核处理器的MATLAB程序加速、基于大内存和向量化的MATLAB程序加速、基于并行计算工具箱和GPU计算的MATLAB加速、基于CUDA库的MATLAB加速、基于CUDA语言的MATLAB加速等。同时,本书附带了大量程序实例,包括深度学习及大数据分析领域的例子,深入浅出地示范各种基于CUDA语言的MATLAB程序加速的技巧。
本书可帮助读者对所在领域的MATLAB应用程序进行显著加速,大幅提升算法开发的效率。
目录
第1章绪论
1.1MATLAB程序的加速
1.2MATLAB程序加速的可能途径
1.2.1基于多核CPU的MATLAB程序加速
1.2.2基于大内存的MATLAB程序加速
1.2.3基于英伟达公司GPU的MATLAB程序加速
1.2.4基于AMD公司GPU的MATLAB程序加速
1.2.5基于Intel公司Xeon Phi的MATLAB程序加速
1.3MATLAB程序加速的度量
1.4基于GPU计算的MATLAB程序的编制
1.4.1并行计算工具箱简介
1.4.2CUDA库
1.4.3CUDA编程
第2章MATLAB程序的性能评估
2.1bench()函数
2.2tic()函数/toc()函数
2.3timeit()函数
2.4cputime()函数
2.5clock()函数和etime()函数
2.6gputimeit()函数
2.7MATLAB探查器
第3章基于多核处理器的MATLAB程序加速
3.1MATLAB矩阵及运算符
3.1.1MATLAB矩阵的创建
3.1.2矩阵的性质的检验
3.1.3MATLAB矩阵的操作
3.2MATLAB函数
3.2.1MATLAB函数的定义
3.2.2MATLAB函数的执行
3.3语句与代码
3.3.1分支结构
3.3.2循环结构
3.4MATLAB代码
3.5MATLAB并行设置
3.6基于并行for循环(parfor循环)的MATLAB程序加速
第4章基于大内存的MATLAB程序的加速
4.1内存条的选择与安装
4.2内存预分配
4.2.1已知数组大小
4.2.2未知数组大小
4.3MATLAB向量化简介
4.4MATLAB矩阵运算的向量化
4.4.1创建MATLAB矩阵的函数
4.4.2数据复制
4.4.3MATLAB的矩阵变换函数
4.4.4索引
4.4.5矩阵操作的向量化
4.4.6符合条件的元素总数
4.5MATLAB函数的向量化
4.5.1基于arrayfun()函数、bsxfun()函数、cellfun()函数、
spfun()函数和structfun()函数的向量化
4.5.2基于pagefun()函数的向量化
4.6MATLAB语句的向量化
第5章基于并行计算工具箱的MATLAB加速
5.1GPU卡的选择与安装
5.1.1GPU卡的选择
5.1.2电源功率
5.1.3散热问题
5.2基于并行计算工具箱的GPU计算简介
5.3基于并行计算工具箱的矩阵运算
5.3.1在设备端(GPU端)直接创建MATLAB矩阵
5.3.2在设备端(GPU端)生成随机数矩阵
5.3.3设备端(GPU端)的稀疏矩阵
5.3.4设备端(GPU端)矩阵的数据类型
5.3.5设备端(GPU端)矩阵的检验
5.3.6设备端(GPU端)矩阵的操作
5.4基于并行计算工具箱的设备端(GPU端)函数
5.4.1设备端(GPU端)函数的定义
5.4.2设备端(GPU端)函数的执行
5.5基于设备端(GPU端)大内存的MATLAB程序的加速
5.6例子
5.6.1卷积神经网络前向传播的卷积层
5.6.2卷积神经网络前向传播的激活函数
5.6.3卷积神经网络前向传播的降采样层
5.6.4卷积神经网络后向传播的升采样层
5.6.5卷积神经网络后向传播的卷积层
5.6.6卷积神经网络后向传播中的梯度计算
第6章MATLAB与C/C 的接口
6.1MEX库API
6.1.1MEX相关的函数
6.1.2从MEX中调用MATLAB函数
6.1.3mexGet()函数
6.1.4MEX库API与输入输出相关的函数
6.1.5MEX库API与锁定相关的函数
6.2MATLAB的C/C 矩阵库API
6.2.1定义MEX函数的数据类型
6.2.2创建数组、分配内存和释放内存
6.2.3数据类型校验: 数组的数据类型和性质
6.2.4数据存取: 从数组读取和写入数据
6.2.5数据类型转换: 将字符串数组和结构数组转换成对象数组
6.3MEX函数编译器
6.3.1MEX介绍
6.3.2编译MEX
6.3.3MEX文件的查错
第7章基于CUDA库的MATLAB加速
7.1基于CUDA库的MATLAB加速简介
7.2基于ArrayFire库的MATLAB加速简介
7.2.1ArrayFire简介
7.2.2ArrayFire数组
7.2.3ArrayFire函数
7.2.4CUDA的混合编程
7.2.5实例
7.3基于其他CUDA库的MATLAB加速简介
第8章GPU计算简介
8.1芯片技术的发展与摩尔定律
8.2每秒浮点运算次数
8.3GPU计算加速的度量
8.3.1GPU程序的加速比
8.3.2阿姆达尔定律和古斯塔夫森定律
8.3.3并行程序的并行状况
8.4并行计算部件
8.4.1张量处理器
8.4.2现场可编程门阵列
8.4.3类脑处理器
8.4.4视觉处理器
8.4.5物理处理器
8.4.6图形处理器
8.5英伟达公司GPU简介
8.5.1计算单元
8.5.2GPU内存
8.5.3计算能力
8.5.4GPU当前状态的检测
8.5.5GPU集群设置
8.5.6集群管理软件
第9章CUDA编程简介
9.1CUDA核
9.2CUDA线程与线程块
9.2.1CUDA线程
9.2.2CUDA线程块
9.3内存结构与管理
9.3.1全局内存
9.3.2共享内存
9.3.3锁页内存
9.3.4纹理内存和表面内存
9.4并行管理
9.4.1非同步并行执行
9.4.2流和事件
9.4.3同步调用
9.5CUDA流
9.5.1CUDA流的创建和结束
9.5.2默认CUDA流
9.5.3显式同步
9.5.4隐式同步
9.5.5重叠行为
9.5.6回调函数
9.5.7CUDA流的优先级
9.6CUDA事件
9.6.1CUDA事件的创建与清除
9.6.2CUDA事件的运行
9.7多设备系统
9.7.1多设备系统的初始化
9.7.2多设备系统的设备计数
9.7.3多设备系统的设备选择
9.7.4多设备系统的CUDA流和CUDA事件
9.7.5不通过统一虚拟地址的多设备系统的设备间的内存复制
9.7.6通过统一虚拟地址的多设备系统的设备间的内存复制
9.8动态并行
9.8.1动态并行简介
9.8.2动态并行的编程模型
9.8.3动态并行的环境配置
9.8.4动态并行的内存管理
9.8.5动态并行的嵌套深度
9.9统一虚拟地址空间
9.9.1统一虚拟地址空间简介
9.9.2统一内存编程的优点
9.9.3统一内存分配
9.9.4统一内存的连续性与并行性
9.9.5统一内存的检验
9.9.6统一内存的性能优化
9.10CUDA的编译
9.10.1CUDA编译工作流
9.11CUDA程序实例
9.11.1序列蒙特卡罗的类别分布随机数
9.11.2哈尔变换
第10章CUDA程序优化
10.1CUDA程序优化的策略
10.2指令级别的优化
10.2.1算术指令吞吐量化
10.2.2控制流指令
10.2.3同步指令
10.3线程和线程块级别的优化
10.3.1warp简介
10.3.2CUDA线程块的warp数量
10.3.3CUDA占用率
10.3.4线程warp对设备端(GPU端)内存读写
10.4CUDA核级别的优化
10.4.1优化CUDA核参数
10.4.2减少内存同步
10.4.3减少寄存器总量
10.4.4提高指令层次的并行度
10.5CUDA程序级别的优化
第11章基于CUDA的MATLAB加速
11.1基于CUDAKernel的MATLAB加速
11.2基于MEX函数的MATLAB加速
11.3多GPU编程
11.4例子
11.4.1基于MEX函数的多GPU矩阵相加
11.4.2基于MEX函数的多GPU的LSE函数
第12章总结
12.1加速MATLAB编程方法的比较
12.2进一步加速MATLAB
12.2.1多路多核处理器的MATLAB程序加速
12.2.2基于AMD公司GPU的MATLAB程序加速
12.2.3基于Intel公司Xeon Phi的MATLAB程序加速
参考文献
前言【写作背景】从20世纪70年代以来,MATLAB便受到学术界和工业界的欢迎。时至今年,MATLAB拥有大约200万用户。MATLAB的优点是易用性: Cleve Moler当年开发MATLAB的初衷是不用学习Fortran语言,也能够使用线性代数库LINPACK和EISPACK。MATLAB的易用性能够显著降低开发难度和减小开发周期,对于面临科研成果压力的学术界和面临利润压力的工业界有很大的吸引力。易用性的代价是MATLAB的运算效率不如编译型的编程语言,如C/C 和Fortran。同时,创新的压力使学术界和工业界开发出来的MATLAB程序越来越复杂。多项因素综合的结果,使MABLAB程序的效率不高,运行时间长。很多MATLAB程序的用户对程序运行时间有要求。例如,金融领域的算法开发者和使用者,往往对程序的运行时间有苛刻的要求; 医学领域的算法开发者和使用者希望MATLAB程序的速度达到临床的要求; 对于数据分析领域的MATLAB使用者,分析大数据所耗费的运行时间是很大的问题。因此,工业界和学术界的MATLAB的开发者和使用者,都有对于MATLAB程序加速的强烈需求。现代硬件技术的发展,使MATLAB程序的开发者和使用者能够拥有多核(multicore)、大内存等有效工具; 图形处理器(Graphics Processing Unit,GPU)具有很好的加速能力。同时,一些公司还推出了专用的计算加速卡,如英伟达公司的Tesla系列计算加速卡、AMD公司的Fire Pro系列计算加速卡、Intel公司的Xeon Phi计算加速卡等。MATLAB提供了调用其他程序的接口,并能够完成MATLAB与其他程序之间的数据传输: MATLAB能够通过MEXfile(MATLAB executable)的形式,调用C/C 和Fortran语言的程序; Windows版本的MATLAB可以调用ActiveX和DotNet(.NET)程序; 从2000年的6.0版本(R12)开始,MATLAB捆绑了JVM(Java Virtual Machine),能够调用Java程序; MATLAB也能够通过perl()调用perl代码。MATLAB集成较好的多核(multicore)加速能力。大多数情况下,MATLAB的开发者和使用者能够不做任何修改,自动获得多核加速能力。多核加速性能要求苛刻的用户,能够通过MATLAB与其他程序的接口,获得极致的多核加速能力。现代计算机都配有较大的内存容量,大内存能够显著提升MATLAB的计算速度。MATLAB没有提供对大内存优化的自动工具。为了有效利用大的内存容量,MATLAB的开发者和使用者需要通过向量化(vectorization)对MATLAB程序进行优化。GPU是现代计算机的配件,都有不错的加速能力。GPU的主要生产厂商包括英伟达公司和AMD公司。MATLAB通过并行计算工具箱(Parallel Computing Toolbox,PCT)对英伟达公司的GPU单卡提供支持,MATLAB的开发者和使用者可以通过PCT使用英伟达公司生产的GPU。需要英伟达公司GPU多卡的计算支持和对英伟达公司GPU计算加速性能要求极致的程序员,可以通过MATLAB与C/C 程序或者Fortran程序的接口,获得计算性能的提升。MATLAB不直接提供对AMD公司GPU的支持,MATLAB的开发者和使用者需要对AMD公司生产的GPU编写程序,并通过MATLAB与C/C 程序或者Fortran程序的接口功能(wrapper function),获得MATLAB对AMD公司的GPU的支持。本书基于作者多年GPU计算与加速的研究和经验[112],全面叙述了基于CUDA编程的加速MATLAB编程的方法。【读者人群】本书适用于各行各业利用MATLAB进行算法开发,并且对MATLAB程序有加速需求的专业人员。本书主要面向满足日常办公需要的个人计算机(Personal Computer,PC)和服务器(Server),并安装了GPU加速卡。【衷心感谢】感谢英伟达公司袁永清先生等对于本书撰写与出版的大力支持。感谢MATLAB公司吕凌曦女士对本书出版的大力支持。感谢清华大学出版社电子信息事业部主任梁颖先生对于本书出版的大力支持。感谢丽台科技王锋先生提供了测试用GPU卡。【相关读物】为了确保内容的正确性,在本书编写的过程中,作者参考了MATLAB Programming Fundamentals R2017a、MATLAB Parallel Computing Toolbox User’s Guide R2017a和CUDA C Programming Guide v8.0等。读者还可以参阅GPU计算与MATLAB编程相关中英文书籍[1316]。编者
2017年7月
CUDADevice (具有属性):
Name:’GeForce GTX 1080 Ti’ Index:1 ComputeCapability:’6.1′ SupportsDouble:1 DriverVersion:8 ToolkitVersion:7.5000 MaxThreadsPerBlock:1024 MaxShmemPerBlock:49152 MaxThreadBlockSize:[1024 1024 64] MaxGridSize:[2147483647 65535 65535] SIMDWidth:32 TotalMemory:2.1475e 09 AvailableMemory:2.0331e 09 MultiprocessorCount:3584 ClockRateKHz:1582000 ComputeMode:’Default’ GPUOverlapsTransfers:1 KernelExecutionTimeout:1 CanMapHostMemory:1 DeviceSupported:1 DeviceSelected:1
gpuDevice()函数的输出结果对GPU进行基本介绍,每一项的含义如下: Name: 表示当前GPU的类型。本例显示当前GPU的型号是GeForce GTX 1080 Ti。 Index: 表示当前GPU的序号。本例显示当前GPU的序号是1。 ComputeCapability: 表示当前GPU的计算能力。本例显示当前GPU的计算能力为6.1版本。 SupportsDouble: 是否支持双精度。本例显示当前GPU支持双精度。 DriverVersion: CUDA驱动程序版本。本例显示当前GPU的CUDA驱动程序版本是8。 ToolkitVersion: CUDA版本。本例显示当前GPU的CUDA驱动程序是75版本。 MaxThreadsPerBlock: 每个线程块包含的线程数目。本例显示当前GPU的每个线程块包含的线程数目是1024。 MaxShmemPerBlock: 每个线程块包含共享内存数目。本例显示当前GPU的每个线程块包含共享内存数目是49152字节。 MaxThreadBlockSize: 线程块大小。本例显示当前GPU的每个线程块包含线程块是[1024102464]。 MaxGridSize: 线程网格大小。本例显示当前GPU的每个线程块包含线程网格是[21474836476553565535]。 SIMDWidth: warp包含的线程数目。本例显示当前GPU的每个warp包含的线程数目是32。 TotalMemory: 总内存大小。本例显示当前GPU的总内存是2.1475e 09字节。 AvailableMemory: 可用内存大小。本例显示当前GPU的可用内存是20331e 09字节。 MultiprocessorCount: CUDA核数目。本例显示当前GPU的CUDA核数目是3584。 ClockRateKHz: GPU时钟频率。本例显示当前GPU的时钟频率是1582MHz。 ComputeMode: 计算模式。本例显示当前GPU的计算模式是默认模式。 GPUOverlapsTransfers: 是否支持重叠传输模式。本例显示当前GPU的支持重叠传输模式。 KernelExecutionTimeout: CUDA核执行超时设置。本例显示当前GPU的CUDA核执行超时设置是开。 CanMapHostMemory: 是否支持主机端(CPU端)内存映射。本例显示当前GPU支持主机端(CPU端)内存映射。 DeviceSupported: MATLAB支持的GPU数目。本例显示MATLAB支持的GPU数目是1个。 DeviceSelected: MATLAB的当前GPU数目。本例显示MATLAB的当前GPU数目是1个。从以上输出可以看出,当前计算机配备了一块GeForce GTX 1080 Ti的GPU,包含11GB的总内存(total memory)和3584个CUDA核。其中非常有价值的信息是总内存和可用内存(available memory),这些信息决定着gpuArray数组的范围,也是将设备端(GPU端)的MATLAB向量化的重要指标之一。2. 在主机端(CPU端)内存和GPU内存之间传递MATLAB数组在主机端(CPU端)内存,即MATLAB工作区(worksplace)和GPU内存之间传递MATLAB数组包括两种情况: 从主机端(CPU端)向设备端(GPU端)发送MATLAB数组和从设备端(GPU端)向主机端(CPU端)发送MATLAB数组。可以通过gpuArray()函数实现从主机端(CPU端)向设备端(GPU端)发送MATLAB数组,将主机端(CPU端)内存,即MATLAB工作区(worksplace)的MATLAB数组传送到设备端(GPU端)内存。例如:
N = 6;
M = magic(N);
G = gpuArray(M);
gpuArray()函数的输入数据必须是数值型或者逻辑型,可以是复数。可以通过MATLAB的gather()函数实现从主机端(CPU端)向设备端(GPU端)发送MATLAB数组,将设备端(GPU端)的MATLAB数组传送到主机端(CPU端)内存。5.3基于并行计算工具箱的矩阵运算5.3.1在设备端(GPU端)直接创建MATLAB矩阵
MATLAB的很多内置函数支持gpuArray数组,而这些函数的完全列表可以通过methods(‘gpuArray’)命令查找。MATLAB的gpuArray类的一些方法能够直接在GPU内存中创建MATLAB数组,这些方法包括: 以a开头的函数: abs()函数、accumarray()函数、acos()函数、acosd()函数、acosh()函数、acot()函数(弧度反余切)、acotd()函数、acoth()函数、acsc()函数(弧度反余割)、acscd()函数、acsch()函数、all()函数、and()函数、angle()函数(计算复数的位相角)、any()函数、applylut()函数、area()函数、arrayfun()函数、asec()函数(弧度逆割线)、asecd()函数、asech()函数、asin()函数、asind()函数、asinh()函数、assert()函数(当条件为假时,输出错误信息)、atan()函数、atan2()函数、atan2d()函数、atand()函数、atanh()函数等。 以b开头的函数: bandwidth()函数(频率响应带宽)、bar()函数、bar3()函数、bar3h()函数、barh()函数、besselj()函数(类贝塞尔函数)、bessely()函数(第二类贝塞尔函数)、beta()函数(Beta函数)、betainc()函数(不完全Beta函数)、betaincinv()函数(Beta逆累积分布函数)、betaln()函数(Beta函数的对数值)、bicg()函数(双共轭梯度法)、bicgstab()函数(双共轭梯度稳定解法)、bicgstabl()函数、bitand()函数(按位与运算)、bitcmp()函数(按位补码)、bitget()函数(按位取得)、bitor()函数(按位或运算)、bitset()函数(按位设置)、bitshift()函数(按位移动)、bitxor()函数(按位异或运算)、bsxfun()函数、bwdist()函数、bwlabel()函数、bwlookup()函数、bwmorph()函数等。 以c开头的函数: cast()函数(数据类型转换)、cat()函数(沿着某一个维度对数组进行压缩)、cconv()函数、cdf2rdf()函数(复对角矩阵转化为实对角矩阵)、ceil()函数、cgs()函数、chol()函数、circshift()函数、clabel()函数、classUnderlying()函数(高层数组元素的类型)、colon()函数、comet()函数、comet3()函数、compass()函数、complex()函数、cond()函数(求矩阵的条件数)、coneplot()函数、conj()函数(求复共轭)、contour()函数、contour3()函数、contourc()函数、contourf()函数、contourslice()函数、conv()函数(求卷积)、conv2()函数、convn()函数、corr2()函数、corrcoef()函数(求相关系数)、cos()函数、cosd()函数、cosh()函数、cot()函数(角弧度余切)、cotd()函数、coth()函数、cov()函数、csc()函数(输入角的余割)、cscd()函数、csch()函数、ctranspose()函数(复共轭转置)、cummax()函数(累积值)、cummin()函数(累积小值)、cumprod()函数(以乘积的形式进行累积)、cumsum()函数(以和的形式进行累积)、curl()函数等。 以d开头的函数: deg2rad()函数(角度转弧度)、del2()函数(求离散拉普拉斯)、det()函数(求矩阵的行列式)、detectFASTFeatures()函数、detectHarrisFeatures()函数、detrend()函数、diag()函数、diff()函数(求导数)、discretize()函数(将数据集合到不同的区间之中)、disp()函数(显示变量的值)、display()函数、divergence()函数、dot()函数(求点积)、double()函数等。 以e开头的函数: edge()函数、eig()函数(求特征值与特征向量)、end()函数、eps()函数(求相对精度)、eq()函数、erf()函数(求误差函数)、erfc()函数、erfcinv()函数、erfcx()函数、erfinv()函数、errorbar()函数、existsOnGPU()函数、exp()函数、expint()函数、expm()函数、expm1()函数、eye()函数(创建单位矩阵)、ezcontour()函数、ezcontourf()函数、ezgraph3()函数、ezmesh()函数、ezmeshc()函数、ezplot()函数、ezplot3()函数、ezpolar()函数、ezsurf()函数、ezsurfc()函数等。 以f开头的函数: factorial()函数(求阶乘)、false()函数(创建逻辑假的矩阵)、feather()函数、fft()函数、fft2()函数、fftfilt()函数、fftn()函数、fill()函数、fill3()函数、filter()函数、filter2()函数、find()函数、fix()函数(向数值0取整)、flip()函数(调换元素的顺序)、flipdim()函数、fliplr()函数、flipud()函数、floor()函数、fplot()函数、fprintf()函数、freqspace()函数、full()函数(将稀疏矩阵转换成全矩阵)等。 以g开头的函数: gamma()函数、gammainc()函数、gammaincinv()函数、gammaln()函数、gather()函数、ge()函数(判断是否大于或等于)、gmres()函数、gpuArray()函数、gradient()函数(求数值梯度)、gt()函数等。 以h开头的函数: hist()函数、histc()函数、histcounts()函数(柱状图)、histeq()函数、histogram()函数、horzcat()函数(从行的方向将矩阵连接起来)、hsv2rgb()函数(将HSV彩色图转换成RGB彩色图)、hypot()函数(平方和的平方根)等。 以i开头的函数: idivide()函数、ifft()函数、ifft2()函数、ifftn()函数、im2double()函数、im2int16()函数、im2single()函数、im2uint16()函数、im2uint8()函数、imabsdiff()函数、imadjust()函数、imag()函数(用图表示MATLAB矩阵)、image()函数、imagesc()函数、imbothat()函数、imclose()函数、imcomplement()函数、imdilate()函数、imerode()函数、imfill()函数、imfilter()函数、imgaussfilt()函数、imgaussfilt3()函数、imgradient()函数、imgradientxy()函数、imhist()函数、imlincomb()函数、imnoise()函数、imopen()函数、imreconstruct()函数、imregdemons()函数、imregionalmax()函数、imregionalmin()函数、imresize()函数、imrotate()函数、imrotate_old()函数、imshow()函数、imtophat()函数、ind2sub()函数、inf()函数、inpolygon()函数(多边形边界或者内部的点)、int16()函数(转换成16位带符号的整数)、int2str()函数、int32()函数(转换成32位带符号的整数)、int64()函数(转换成64位带符号的整数)、int8()函数(转换成8位带符号的整数)、interp1()函数(一维数据插值)、interp2()函数(二维数据插值)、interp3()函数(三维数据插值)、interpn()函数(n维数据插值)、interpstreamspeed()函数、intersect()函数(寻找MATLAB矩阵共同拥有的元素)、inv()函数(求逆矩阵)、ipermute()函数(重新安排矩阵的不同的维)、iradon()函数、isaUnderlying()函数、isbanded()函数(检验MATLAB矩阵是否在)、isdiag()函数、isempty()函数、isequal()函数、isequaln()函数、isfinite()函数、isfloat()函数、ishermitian()函数、isinf()函数、isinteger()函数、islogical()函数、ismember()函数、ismembertol()函数、isnan()函数、isnumeric()函数、isocaps()函数、isocolors()函数、isonormals()函数、isosurface()函数、isreal()函数、issorted()函数、issparse()函数、issymmetric()函数、istril()函数、istriu()函数等。 以k开头的函数: kmeans()函数、knnsearch()函数等。 以l开头的函数: ldivide()函数、le()函数、legendre()函数(勒让德多项式)、length()函数、line()函数、linspace()函数、loadobj()函数、log()函数、log10()函数、log1p()函数、log2()函数、logical()函数、loglog()函数、logspace()函数、lsqr()函数(LSQR算法)、lt()函数、lu()函数等。 以m开头的函数: mat2gray()函数、mat2str()函数、max()函数、mean()函数、medfilt2()函数、mesh()函数、meshc()函数、meshgrid()函数、meshz()函数、min()函数、minres()函数、minus()函数、mldivide()函数、mod()函数、mode()函数(MATLAB矩阵中频繁出现的元素)、mpower()函数(MATLAB矩阵的乘方)、mrdivide()函数、mtimes()函数等。 以n开头的函数: nan()函数、ndgrid()函数、ndims()函数、ne()函数(定义不等式)、nextpow2()函数(2的小的多少次方大于或等于输入值)、nnz()函数(MATLAB矩阵中非零元素的数目)、nonzeros()函数(MATLAB矩阵中非零元素的数目)、norm()函数(求范数)、normest()函数、normxcorr2()函数、not()函数、nthroot()函数、null()函数(求矩阵的零空间)、num2str()函数、numel()函数、nzmax()函数等。 以o开头的函数: ones()函数、or()函数等。 以p开头的函数: padarray()函数、pagefun()函数、pareto()函数、patch()函数、pcg()函数(预条件共轭梯度法)、pcolor()函数、pdist()函数、pdist2()函数、permute()函数(变换MATLAB数组的维度)、pie()函数、pie3()函数、planerot()函数(吉文斯平面旋转)、plot()函数、plot3()函数、plotmatrix()函数、plotyy()函数、plus()函数、polar()函数、poly()函数(生成具有给定的解或者特征多项式的多项式)、polyder()函数(多项式求导数)、polyfit()函数、polyval()函数、polyvalm()函数、pow2()函数、power()函数、prod()函数、psi()函数(polygamma函数)等。 以q开头的函数: qmr()函数(准小残差法)、qr()函数(QR分解)、quiver()函数、quiver3()函数等。 以r开头的函数: rad2deg()函数(角度转换)、radon()函数、rand()函数、randi()函数、randn()函数、randperm()函数、rdivide()函数、real()函数、reallog()函数、realpow()函数、realsqrt()函数、reducepatch()函数、reducevolume()函数、regionprops()函数、rem()函数(求余数)、repmat()函数、reshape()函数、rgb2gray()函数、rgb2hsv()函数、rgb2ycbcr()函数、ribbon()函数、roots()函数(多项式求解)、rose()函数、rot90()函数、round()函数等。 以s开头的函数: scatter3()函数、sec()函数(求正割)、secd()函数、sech()函数、semilogx()函数、semilogy()函数、setdiff()函数、setxor()函数、shiftdim()函数、shrinkfaces()函数、sign()函数、sin()函数、sind()函数、single()函数(转化成单精度数)、sinh()函数、size()函数、slice()函数、smooth3()函数、sort()函数、sortrows()函数、sparse()函数、speye()函数、spfun()函数、spones()函数、sprand()函数(产生均一分布的随机数矩阵)、sprandn()函数、sprandsym()函数、sprintf()函数、spy()函数、sqrt()函数、stairs()函数、std2()函数、stdfilt()函数、stem()函数、stem3()函数、stream2()函数、stream3()函数、streamline()函数、streamparticles()函数、streamribbon()函数、streamslice()函数、streamtube()函数、stretchlim()函数、sub2ind()函数、subsasgn()函数(重新定义下标值)、subsindex()函数(将对象转换为数组索引)、subspace()函数、subsref()函数、subvolume()函数、sum()函数、superiorfloat()函数、surf()函数、surfc()函数、surfl()函数、svd()函数、swapbytes()函数(交换字节顺序)、symmlq()函数等。 以t开头的函数: tan()函数、tand()函数、tanh()函数、tfqmr()函数、times()函数、transpose()函数、trapz()函数(梯形数值积分)、tril()函数、trimesh()函数、trisurf()函数、triu()函数、true()函数、typecast()函数(更改数据类型)等。 以u开头的函数: uint16()函数、uint32()函数、uint64()函数、uint8()函数、uminus()函数(一元负运算)、union()函数、unique()函数、uniquetol()函数、unwrap()函数(解卷绕)、uplus()函数(一元负运算)等。 以v开头的函数: var()函数、vertcat()函数(按照垂直方向将)、vissuite()函数、volumebounds()函数、voronoi()函数等。 以w开头的函数: waterfall()函数等。 以x开头的函数: xcorr()函数、xor()函数等。 以y开头的函数: ycbcr2rgb()函数等。 以z开头的函数: zeros()函数等。通过MATLAB支持gpuArray数组的函数,程序员可以在设备端(GPU端)直接创建MATLAB矩阵。对于支持gpuArray数组的任一函数fun来说,直接创建gpuArray数组的方法包括: gpuArray.fun()或者fun(, ‘gpuArray’)。另外,随着MATLAB新版本的推出,越来越多的MATLAB内置函数支持gpuArray数组。5.3.2在设备端(GPU端)生成随机数矩阵本节讨论在设备端(GPU端)生成随机数矩阵的4个问题: 在设备端(GPU端)生成随机数矩阵的函数、在设备端(GPU端)生成随机数矩阵的伪随机数产生器(combined multiplicative recursive generator)、在设备端(GPU端)生成随机数矩阵的随机数流和在设备端(GPU端)生成随机数矩阵的分布。1. 在设备端(GPU端)生成随机数矩阵的函数5.3.1节讲到,MATLAB的rand()函数、randi()函数和randn()函数支持gpuArray数组。可以通过gpuArray()函数直接在设备端(GPU端)生成随机数矩阵,也可以通过arrayfun()函数或bsxfun()函数在设备端(GPU端)生成随机数矩阵,但是只有基本功能能够使用。2. 在设备端(GPU端)生成随机数矩阵的伪随机数产生器GPU使用伪随机数产生器产生随机数。设备端(GPU端)的随机数流可以通过parallel.gpu.rng()函数和parallel.gpu.RandStream()函数产生。GPU支持三种类型的随机数产生器: combRecursive、Philox4x3210和Threefry4x6420。另外,MATLAB的gpuArray()函数、arrayfun()函数和bsxfun()函数使用相同的随机数流。3. 在设备端(GPU端)生成随机数矩阵的随机数流通常情况下,MATLAB的主机端(CPU端)和设备端(GPU端)的随机数流是不同的。如果需要MATLAB的主机端(CPU端)和设备端(GPU端)产生相同的随机数,随机数流需要设置为相同的。4. 在设备端(GPU端)生成随机数矩阵的分布MATLAB提供的随机数种类有限,包括均一分布随机数rand()函数、正态分布(normal distribution)随机数randn()等。对于MATLAB不提供的随机数,如以后章节将详细讨论的类别分布(categorical distribution)随机数,程序员需要通过编写MATLAB函数来实现。5.3.3设备端(GPU端)的稀疏矩阵一些MATLAB函数支持设备端(GPU端)稀疏gpuArray矩阵,这些函数包括: abs()函数、angle()函数、bicg()函数、bicgstab()函数、ceil()函数、classUnderlying()函数、conj()函数、ctranspose()函数、deg2rad()函数、end()函数、expm1()函数、find()函数、fix()函数、floor()函数、full()函数、gmres()函数、gpuArray.speye()函数、imag()函数、isaUnderlying()函数、isdiag()函数、isempty()函数、isequal()函数、isequaln()函数、isfloat()函数、isinteger()函数、islogical()函数、isnumeric()函数、isreal()函数、issparse()函数、istril()函数、istriu()函数、length()函数、log1p()函数、minus()函数、mtimes()函数、ndims()函数、nextpow2()函数、nnz()函数、nonzeros()函数、numel()函数、nzmax()函数、pcg()函数、plus()函数、rad2deg()函数、real()函数、realsqrt()函数、round()函数、sign()函数、size()函数、sparse()函数、spfun()函数、spones()函数、sprandsym()函数、sqrt()函数、sum()函数、transpose()函数、tril()函数、triu()函数、uminus()函数、uplus()函数等。设备端(GPU端)的稀疏矩阵可以通过调用sparse()函数定义,也可以通过gpuArray()函数实现。特别的,当设备端(GPU端)的函数的输出值为复数(complex)数据类型的时候,设备端(GPU端)的函数的输入值也应该设置为复数数据类型。5.3.4设备端(GPU端)矩阵的数据类型在设备端(GPU端),gpuArray支持的数据类型有无符号64位整型(uint64)、无符号32位整型(uint32)、逻辑型(logical)、64位整型(int64)、无符号8位整型(uint8)、16位整型(int16)、无符号16位整型(uint16)、单精度型(single)、双精度型(double)、8位整型(int8)、32位整型(int32)等。在设备端(GPU端),GPU对单精度型数据的处理速度远远高于双精度型数据,应该在设备端(GPU端)运行的MATLAB代码中,尽量使用单精度型数据类型,以提高数据处理的速度。另外,不同的精度之间可以相互转换。例如,将单精度的矩阵转化成双精度:
double(gpuArray)
5.3.5设备端(GPU端)矩阵的检验检验gpuArray对象特性的方法包括classUnderlying()函数、existsOnGPU()函数、isreal()函数、length()函数、ndims()函数、size()函数等。其中: classUnderlying()函数的功能是检查设备端(GPU端)的gpuArray数组的数据类型; existsOnGPU()函数的功能是检查gpuArray数组是否存在; isreal()函数的功能是检查gpuArray数组是否为实数; length()函数的功能是检查gpuArray数组的维的长度; ndims()函数的功能是检查gpuArray数组的维数; size()函数的功能是检查gpuArray数组的大小。5.3.6设备端(GPU端)矩阵的操作MATLAB矩阵包含3种操作: 数值操作、矩阵操作、关系操作。MATLAB所有的算术运算都是通过这两种操作进行的。其中数值操作通过单个标量的方式进行,而矩阵操作通过线性代数的规则进行。因此,MATLAB数值操作支持高维数值,而矩阵操作不能在多维矩阵上操作。综上所述,MATLAB主机端(CPU端)和设备端(GPU端)都包含3种矩阵操作: 数值操作、矩阵操作和关系操作。通过算术运算符、关系运算符和逻辑运算符的组合,形成了表达式(expression)。5.4基于并行计算工具箱的设备端(GPU端)函数MATLAB函数来源于内置函数、自定义函数、MEX函数等。除了编程简便以外,MATLAB的一大优点就是提供多种多样的内置函数,并通过工具箱的形式组织起来。
5.4.1设备端(GPU端)函数的定义MATLAB包含大量内置函数,并通过工具箱的形式组织起来。如何在GPU上运行这些MATLAB的内置函数呢?许多MATLAB内置函数的输入可以是设备端(GPU端)的gpuArray数组,详细列表请见5.3.1节。在设备端(GPU端)执行MATLAB内置函数的时候,主机端(CPU端)和设备端(GPU端)的MATLAB矩阵可以混合使用。当主机端(CPU端)和设备端(GPU端)的MATLAB矩阵混合使用的时候,主机端(CPU端)的MATLAB矩阵将自动复制到设备端(GPU端)。当MATLAB的内置函数运行完成以后,输出的数组是设备端(GPU端)的gpuArray。如果输出的结果是标量,这些标量将储存在主机端(CPU端)。当输出的数组是复数的时候,输出的结果存储在设备端(GPU端)。MATLAB的whos命令的作用是: 显示当前内存的变量信息,包括设备端(GPU端)的gpuArray数组。5.4.2设备端(GPU端)函数的执行总的来说,MATLAB函数可以直接执行,也可以通过arrayfun()函数执行。MATLAB的arrayfun()函数可以用于执行主机端(CPU端)和设备端(GPU端)的元素级函数。如果arrayfun()函数的输入为设备端(GPU端)数组的话,输出也为设备端(GPU端)数组。程序员可以利用支持gpuArray的函数将主机端(CPU端)的代码转换为设备端(GPU端)的代码,获得了运行速度的提升。为了进一步提升MATLAB代码的运行速度,程序员应该利用arrayfun()函数运行设备端(GPU端)的元素级函数。因为MATLAB的arrayfun()函数将元素级函数转换成相应的CUDA核,程序员可以通过MATLAB的arrayfun()函数提高设备端(GPU端)的元素级函数的运行速度。5.5基于设备端(GPU端)大内存的MATLAB程序的加速
现代GPU都具有较大的内存。例如,英伟达公司生产GeForce GTX 1080 Ti型号GPU具有多达11GB的全局内存(global memory)。一般来说,在第4章中讨论过的基于主机端(CPU端)大内存的MATLAB程序的加速的方法,在设备端(GPU端)也是适用的。运用在第4章中讨论过的基于主机端(CPU端)大内存的MATLAB程序的加速的方法,程序员可以对并行计算工具箱编写的MATLAB代码进行向量化改写,获得更高的加速比。5.6例子5.6.1卷积神经网络前向传播的卷积层
卷积神经网络前向传播(forward propagation)的卷积层包含有卷积操作。卷积操作的对象为输入图像和卷积核。首先将所有的卷积核旋转90°,然后将输入图像与卷积核分别进行卷积操作:
for imageNum = 1 : numImages
image = images(:, :, imageNum);
for filterNum = 1 : numFilters
filteredImage = conv2(image, Wc_rotated(:, :, filterNum), ‘valid’) bc(filterNum);
end
end
因为所有的图像都进行相同的一层卷积和一层池化,在主机端CPU具有富余计算能力的情况下,程序可以简单地通过parfor对卷积和池化过程进行加速:
parfor imageNum = 1 : numImages
image = images(:, :, imageNum);
for filterNum = 1 : numFilters
filteredImage = conv2(image, Wc_rotated(:, :, filterNum), ‘valid’) bc(filterNum);
end
end
在卷积层(convolutional layer)之后,将卷积以后的二维图转换成一个一维向量,并存储在二维数据矩阵的列中。以上代码利用内外两层的嵌套循环,确定需要处理的图像和卷积核后,进行卷积和池化的操作。为了充分利用设备端(GPU端)GPU的存储资源与计算资源,程序员可以利用MATLAB的并行计算工具箱,将卷积过程完全向量化。
parfor imageNum = 1 : numImages* filterNum
filterNum = fix(i/numFilters) 1;
imageNum = rem(i,numImages);
filteredImage = conv2(images(:, :, imageNum), Wc_rotated(:, :, filterNum), ‘valid’) bc(filterNum);
end
通过向量化,程序将获得显著的加速。5.6.2卷积神经网络前向传播的激活函数卷积神经网络前向传播的激活函数非常简单,主要包括Sigmoid()函数、Tanh()函数、ReLU()函数等。在卷积层和降采样层(mean pooling)之间,程序员需要存储激活函数(activation)的值,用于后向传播(back propagation)的计算。在主机端(CPU端),卷积神经网络前向传播激活函数的实现如下:
for imageNum = 1 : numImages
image = images(:, :, imageNum);
for filterNum = 1 : numFilters
switch activationType
case ‘relu’
filteredImage = max(filteredImage, 0);
case ‘sigmoid’
filteredImage = sigmoid(filteredImage);
end
activations(:, :, filterNum, imageNum) = filteredImage;
end
end
因为卷积神经网络前向传播激活函数Sigmoid()和ReLU()非常简单,程序员可以自行实现支持三维操作的版本。因此在设备端(GPU端),卷积神经网络前向传播激活函数能够通过以下代码高效地实现:
switch activationType
case ‘relu’
filteredImage = max(filteredImage, 0);
case ‘sigmoid’
filteredImage = sigmoid(filteredImage);
end
5.6.3卷积神经网络前向传播的降采样层卷积神经网络的卷积操作对输入图像提取特征后,降采样层将卷积层提取的特征进行进一步整合,得到新的更有代表性的特征。常用的降采样层(pooling)的方法包括均值降采样层(mean pooling)、值降采样(max pooling)和随机降采样(stochastic pooling)。在主机端(CPU端),卷积神经网络前向传播降采样层的实现如下:
for imageNum = 1 : numImages
image = images(:, :, imageNum);
for filterNum = 1 : numFilters
pooledImage = conv2(filteredImage, meanPoolingFilter, ‘valid’);
end
end
因为MATLAB的conv2()函数只支持二维数组,在卷积神经网络前向传播降采样层的主机端(CPU端)实现中,程序员需要用到两层嵌套的for循环。因为MATLAB的conv2()函数支持gpuArray,卷积神经网络前向传播降采样层的设备端(GPU端)实现如下:
parfor imageNum = 1 : numFilters*numImages
filterNum = fix(i/numFilters) 1;
imageNum = rem(i,numImages);
pooledImage = conv2(filteredImage, meanPoolingFilter, ‘valid’);
end
5.6.4卷积神经网络后向传播的升采样层卷积神经网络后向传播(back propagation)的过程中,对于所有的图像而言,程序员需要通过升采样(upsample)的方式,将误差值通过池化层(the pooling layer)反向传播。代码如下:
for imageNum = 1:numImages
for filterNum = 1:numFilters
e = errorsPooled(:, :, filterNum, imageNum);
errorsPooling(:, :, filterNum, imageNum) = kron(e, unpoolingFilter);
end
end
程序员可以运用parfor循环和reshape()函数,对卷积神经网络后向传播的升采样层,代码如下:
errorsPooled=reshape( errorsPooled (:, :, filterNum*imageNum) );
parfor imageNum = 1:numImages* numFilters
e = errorsPooled(:, :, filterNum*imageNum);
errorsPooling(:, :, filterNum*imageNum) = kron(e, unpoolingFilter);
end
errorsPooled=reshape( errorsPooled (size(errorsPooled,1), size(errorsPooled,2), filterNum*imageNum) );
5.6.5卷积神经网络后向传播的卷积层为了将前向传播的误差反向的传过卷积层,程序员需要将误差与激活函数的微分值相乘。卷积神经网络后向传播卷积层(convolution)的CPU实现代码如下:
for imageNum = 1:numImages
for filterNum = 1:numFilters
e = errorsPooling(:, :, filterNum, imageNum) ;
switch activationType
case ‘relu’
a = activations(:, :, filterNum, imageNum) > 0;
errorsConvolution(:, :, filterNum, imageNum) = e .* a ;
case ‘sigmoid’
a = activations(:, :, filterNum, imageNum);
errorsConvolution(:, :, filterNum, imageNum) = e .* a .* (1 – a);
end
end
end
按照4.4.5节叙述的数值操作的向量化,卷积神经网络后向传播卷积层的设备端(GPU)实现的代码如下:
switch activationType
case ‘relu’
errorsConvolution(:, :, filterNum, imageNum) = errorsPooling .* activations ;
case ‘sigmoid’
errorsConvolution(:, :, filterNum, imageNum) = errorsPooling .* activations .* (1 – activations);
end
5.6.6卷积神经网络后向传播中的梯度计算对于每一个图像的每一个卷积核而言,程序员需要先将误差项与原始的输入图像做卷积,然后计算梯度值(gradient)。在卷积层之前,应该使用MATLAB的flip()函数调整误差矩阵的次序。在卷积计算的过程中,应该使用MATLAB的conv2()函数处理图像的边界。对于一个确定的卷积核而言,可以通过将所有图像与误差项进行卷积运算,将结果加起来的方式,获得梯度的终值。对于误差项而言,可以通过计算误差项的和的方式,计算卷积层上的每一个卷积核的梯度。卷积神经网络后向传播梯度计算的主机端(CPU)实现的代码如下:
for filterNum = 1 : numFilters
Wc_gradFilter = zeros(size(Wc_grad, 1), size(Wc_grad, 2));
for imageNum = 1 : numImages
Wc_gradFilter = Wc_gradFilter conv2(images(:, :, imageNum), errorsConvolution(:, :, filterNum, imageNum), ‘valid’);
end
Wc_grad(:, :, filterNum) = Wc_gradFilter;
end
与前述的双层嵌套的for循环的并行化方法相似,卷积神经网络后向传播梯度计算的设备端(GPU)实现的代码如下:
parfor i = 1 : numFilters*numImages
filterNum = fix(i/numFilters) 1;
imageNum = rem(i,numImages);
if imageNum == 0
Wc_gradFilter = zeros(size(Wc_grad, 1), size(Wc_grad, 2));
end
Wc_gradFilter = Wc_gradFilter conv2(images(:, :, i), errorsConvolution(:, :, i), ‘valid’);
Wc_grad(:, :, filterNum) = Wc_gradFilter;
end
评论
还没有评论。