matlab在运行一些大型程序时会比较慢,如果你的电脑正好有一张不错的显卡,那么为什么不用显卡来加速matlab运行呢?
本文将讲解如何使用gpu来加速matlab运行程序,并总结适合gpu加速的matlab程序。
准备工作:电脑上要有显卡,显卡要有cuda core。
目录
1. 认识你电脑的GPU
MATLAB指令为:gpuDevice
下面是我电脑上的gpu设备信息
>> gpuDevice
ans =
CUDADevice - 属性:
Name: 'NVIDIA RTX A2000 12GB'
Index: 1
ComputeCapability: '8.6'
SupportsDouble: 1
DriverVersion: 11.5000
ToolkitVersion: 11
MaxThreadsPerBlock: 1024
MaxShmemPerBlock: 49152
MaxThreadBlockSize: [1024 1024 64]
MaxGridSize: [2.1475e+09 65535 65535]
SIMDWidth: 32
TotalMemory: 1.2878e+10
AvailableMemory: 1.1272e+10
MultiprocessorCount: 26
ClockRateKHz: 1200000
ComputeMode: 'Default'
GPUOverlapsTransfers: 1
KernelExecutionTimeout: 1
CanMapHostMemory: 1
DeviceSupported: 1
DeviceAvailable: 1
DeviceSelected: 1
说明一下打印出来的信息的含义:
| 参数 | 含义 | 说明 |
|---|---|---|
| Compute Capability | 计算能力 | NVIDIA GPU Compute Capability解释_Forskamse的博客-优快云博客 决定了GPU的通用规格和可用特性。Compute Capability的数值和GPU的计算速度无关,但是和GPU可执行的任务种类有关。 小数点前的第一位表示设备核心架构,小数点后的一位表示更加细微的进步,包括对核心架构的改进和功能的完善。 |
| SupportsDouble | 是否支持双精度浮点运算 | 1表示支持 |
| MaxThreadsPerBlock | 每个block中可开的最大线程数量 | |
| MaxShmemPerBlock | 每个Block可用的最大共享内存大小 | |
| MaxThreadBlockSize | 三个维度各自最大的线程数量 | |
| MaxGridSize | 三个维度各自最大的Grid数量 | |
| SIMDWidth | 同一条指令多个数据位宽 | 同时执行的线程数? |
| MultiprocessorCount | streaming multiprocessors 数量 | |
| ComputeMode | 模式 | default表示该设备不受限制,多个应用程序可以同时使用它。MATLAB 可以与其他应用程序(包括其他 MATLAB 会话或工作线程)共享设备。 |
| GPUOverlapsTransfers | 是否支持覆盖传输 | |
| KernelExecutionTimeout | 长时间运行的内核的超时标志 | |
| CanMapHostMemory | 支持将主机内存映射到 CUDA 地址空间 | |
| DeviceSupported | 本机Matlab支持的GPU设备数 | |
| DeviceAvailable | 指示设备是否可用于当前 MATLAB 会话 | |
| DeviceSelected | 当前选定设备的标志 |
附上一张GPU的架构图,便于理解

如果你能扫描出类似上面的结果,那么你就可以用gpu加速matlab程序啦。
2. 内存数据搬运
在正式开始加速之前,你还得明白一点,那就是数据的搬运。

如上图所示,正常来讲,matlab运行中的数据都是在内存里的,也就是电脑CPU的内存
如果要用GPU做计算,首先数据得在GPU的显存上
这就要研究下数据的搬运了:
GPU与显存位于显卡上,CPU位于电脑主板上,CPU与GPU之间通过PCIe连接
虽然PCIe已经是目前最快的接口了,但是毕竟是有速度上限的,所以当数据量多了以后必然传输数据是要时间的,这也是做加速必须要考虑的一个问题:
加速省下的时间能不能大于数传消耗的时间?
3. GPU加速举例
话不多说,直接上代码:
M = single(rand(7000,7000)); % 生成一个随机矩阵
tic
[A1,B1] = eig(M); % 求该随机矩阵的特征值和特征向量
t_cpu = toc
M = gpuArray(M); % 将数据从CPU中搬到GPU
tic
[A2,B2] = eig(M); % 求特征值和特征向量
t_gpu = toc
% A2 = gather(A2); % 将数据从GPU中搬到CPU
% B2 = gather(B2);
求一个较大矩阵的特征值和特征向量,分别运行在CPU和GPU上,并统计结果
怎么证明上面这段代码分别跑在了CPU和GPU上呢?很简单,打开任务管理器(win11):

点击任务管理器的性能标签栏,可以直观的看到CPU和GPU的利用率,CPU和GPU的利用率都依次跑到过100%
我们看看matlab打印的结果是不是gpu的时间比较短,下面是我电脑运行的结果,大家根据自己的电脑的性能适当的调节矩阵的大小。

可以看到GPU运行的速度是CPU的1.6倍。
再看一下matlab的工作区:

我们发现矩阵A2、B2、M的类型是gpuArray,代码中也调用了gpuArray()函数
所以GPU加速的关键就在于gpuArray
4. GPU加速方法
gpuArray是matlab自带的api函数,下面给出matlab官方的帮助文档:
Array stored on GPU - MATLAB - MathWorks 中国
这里总结几个常用的方法:
方法1:搬运数据 M2 = gpuArray(M1);
如第3节所示,讲位于内存的矩阵M1搬移到位于显存的矩阵M2
方法2:直接声明位于显存的数据 rand(7000,7000,'gpuArray');
支持这样直接创建gpuArray阵列的函数有300多个,若要查看,输入命令:methods('gpuArray')
方法3:让函数运行在GPU上 [A2,B2] = arrayfun(@eig,M);
arrayfun的加速效果没有前面两个好,gpu没有完全被调起来
另外与gpu有关的api函数还有一些:
| 函数 | 功能 |
| gpuArray | 在GPU上创建阵列。 |
| gather | 把分布式阵列或gpuArray转移到Matlab的workspace。 |
| existsOnGPU | 确定gpuArray或CUDAKernel在GPU上可用。 |
| gpuDevice | 查询或选择GPU设备。 |
| gpuDeviceCount | 目前GPU的设备数量。 |
| gputimeit | 在GPU上运行函数所需时间。 |
| reset | 重置GPU设备并清空它的内存。 |
| wait(GPUDevice) | 等待GPU计算完成。 |
| arrayfun | 对GPU阵列上的每个元素应用函数。 |
| bsxfun | 用于GPU阵列的二元但扩展函数。 |
| pagefun | 对GPU阵列的每一页应用函数。 |
| parallel.gpu.CUDAKernel | 从PTX和CU代码创建 GPU CUDA kernel 对象。 |
| feval | 评估GPU的核。 |
| setConstantMemory | 设置GPU的一些常量内存。 |
| mxInitGPU | 这是一个C语言函数,在当前选择的设备上初始化Matlab GPU计算库。 |
可自行查阅matlab的帮助文档。
5. 适合GPU加速的程序
适合GPU加速的程序具有以下几个特点:
数据类型不是double。如果把第3节的代码的数据类型改为默认的double,gpu的加速效果就很一般了,我的机器上如果不转化float,cpu反而比gpu还要快(细心的读者可能注意到我任务管理器cpu的主频有4.5GHz,皮)
高度并行的。各个数据之间运算互不影响,耦合度较低。由于GPU本身硬件基础决定,各个workgroup之间并不相互通信,只有同一workgroup内的work-item之间才相互通信,所以GPU本身并不支持迭代等数据耦合度较高的计算,这是GPU本身要求。
数据量大的。用大量数据或者用同一数据多次调用同一公式或者计算过程,公式本身并不复杂,只是执行的次数较多。
接口交互少的。任务可以分为计算密集型和IO密集型。GPU适合计算密集型,即少量的IO读取+大量的计算;而IO密集型,是指多次使用IO读取+少量计算,这种情况涉及到内存与设显存之间的通信问题,主要限制原因是显存带宽问题。
可多个阶段执行的。运算程序可分解为多个小程序或者同一程序可分多个阶段执行,这就类似于使用集群处理同一任务,将其分解为多个任务碎片分发到各节点执行,以提高运算速率。
本文详细介绍了如何利用MATLAB的GPU功能提升程序运行速度,包括GPU设备识别、内存数据搬运、GPU加速示例以及适合GPU加速的程序特性。通过实际代码演示,教你如何利用gpuArray进行数据搬运和计算,以实现显著的性能提升。
2223





