1. GPU 加速简介
(1)为什么使用 GPU 加速?
CPU 擅长处理逻辑复杂的串行任务,而 GPU 拥有数千个流处理器,专为并行计算设计。对于大规模矩阵运算、深度学习训练或科学计算等任务,GPU 加速可将计算速度提升数十至数百倍。
(2)Matlab 的 GPU 支持
- 功能依赖:需安装 Parallel Computing Toolbox(并行计算工具箱)。
- 硬件要求:支持 CUDA 的 NVIDIA GPU(如 Tesla、GeForce RTX 等)。
- 适用场景:大规模矩阵运算、深度学习(
trainNetwork
)、数值仿真(如求解 PDE)等。
2. GPU 加速实现方式
(1)GPU 数据与函数库
数据上传与下载
通过gpuArray
将数据从 CPU 内存拷贝到 GPU 显存,运算后通过gather
取回:A_cpu = rand(1000, 1000); % CPU 数据 A_gpu = gpuArray(A_cpu); % 上传至 GPU B_gpu = A_gpu * A_gpu; % GPU 矩阵乘法 B_cpu = gather(B_gpu); % 下载至 CPU
支持的 GPU 函数
Matlab 为 GPU 重写了大部分数学函数(如sin
,exp
,fft
,svd
),直接支持gpuArray
输入:% GPU 上的指数运算和 FFT data_gpu = gpuArray(randn(1e4, 1e4)); result_gpu = exp(data_gpu) + abs(fft(data_gpu));
(2)内核函数加速(arrayfun
与 pagefun
)
自定义并行函数(
arrayfun
)
将逐元素操作封装为 GPU 可并行执行的函数:% 定义逐元素操作函数 func = @(x) x.^2 + sin(x) / (1 + abs(x)); % 在 GPU 上执行 x_gpu = gpuArray(linspace(0, 10, 1e6)); y_gpu = arrayfun(func, x_gpu);
分页矩阵操作(
pagefun
)
对多维数组的每一页(如 3D 矩阵的第 3 维度)执行函数:% 对每个 2x2 页执行矩阵乘法 A_gpu = gpuArray(rand(2, 2, 1000)); B_gpu = gpuArray(rand(2, 2, 1000)); C_gpu = pagefun(@mtimes, A_gpu, B_gpu);
3. GPU 实战案例与性能对比
(1)矩阵乘法加速
A = rand(5000, 5000);
B = rand(5000, 5000);
% CPU 测试
tic; C_cpu = A * B; t_cpu = toc; % 约 3.5 秒(i7-12700K)
% GPU 测试
A_gpu = gpuArray(A);
B_gpu = gpuArray(B);
tic; C_gpu = A_gpu * B_gpu; wait(gpuDevice); t_gpu = toc; % 约 0.18 秒(RTX 3090)
fprintf('加速比:%.2f 倍\n', t_cpu / t_gpu); % 输出约 19.4 倍
(2)神经网络训练加速
使用 trainNetwork
的 GPU 模式:
options = trainingOptions('adam', ...
'MaxEpochs', 10, ...
'ExecutionEnvironment', 'auto'); % 指定 'gpu' 强制使用 GPU
% 假设已有数据 imds(图像数据)和 layers(网络结构)
net = trainNetwork(imds, layers, options);
性能对比:
- 使用 GPU(NVIDIA RTX 3090)时,单批次耗时可缩减至 CPU 的 1/10。
(3)大规模 PDE 求解(以热传导方程为例)
问题描述:求解二维热传导方程 。
GPU 代码片段:
nx = 1000; ny = 1000; % 网格精度
u_gpu = gpuArray(rand(nx, ny));
dt = 0.01;
% 迭代计算(显式差分法)
for k = 1:1000
laplacian = del2(u_gpu); % GPU 计算拉普拉斯项
u_gpu = u_gpu + dt * laplacian; % GPU 更新温度场
end
耗时对比:
- CPU:约 45 秒
- GPU:约 2.1 秒(加速 21 倍)
4. 高级优化技巧
(1)混合编程(CPU + GPU)
- 任务拆分:将数据敏感任务(如数据预处理)交给 CPU,计算密集任务交给 GPU。
- 减少数据传输:尽量在 GPU 上完成多个连续操作,避免频繁
gather
。
(2)显存管理
- 监控显存:使用
gpudevice
查看当前 GPU 显存状态:gpu = gpuDevice; fprintf('可用显存: %.2f GB\n', gpu.AvailableMemory / 1e9);
- 清理显存:若显存不足,主动释放变量:
clear A_gpu B_gpu % 清除非必要 GPU 变量 reset(gpuDevice); % 重置 GPU 设备(强制清空)
(3)多 GPU 并行
通过 parpool
和 spmd
分配任务到多个 GPU:
parpool(2); % 启动 2 个进程
spmd
gpu_idx = labindex; % 当前进程编号
gpuDevice(gpu_idx); % 绑定不同 GPU
% 执行各自任务(如分块处理矩阵)
end
5. 性能优化注意事项
并非所有任务都适合 GPU
- 低效场景:小规模数据(例如 100x100 矩阵)可能因数据传输开销导致 GPU 更慢。
- 串行依赖任务:如递归算法或高度依赖前一步结果的循环。
避免过度同步
GPU 异步计算需用wait(gpuDevice)
显式等待结果,但频繁同步会降低效率。预热 GPU
初次运行 GPU 代码可能因编译内核耗时较长,多次运行取均值获得稳定性能评估。
6. 总结
- 关键优势:
- 大规模矩阵运算加速 10-100 倍;
- 内置函数与深度学习框架(如 Deep Learning Toolbox)无缝集成。
- 核心步骤:
- 数据上传:
gpuArray()
; - 执行计算:使用 GPU 函数或自定义内核;
- 结果取回:
gather()
。
- 数据上传:
- 未来方向:
- 更广泛的多 GPU 分布式支持;
- 深度优化复杂算法的 GPU 实现(如稀疏矩阵运算)。
附:GPU 加速性能基准测试工具
通过 gpuBench
命令测试当前 GPU 的浮点性能和内存带宽:
gpuBench % 输出当前 GPU 在常见任务中的表现