1. GPU矩阵运算加速导论

矩阵乘法是深度学习、科学计算和图形渲染中最常见的计算核心之一。以深度学习中一个典型全连接层为例,输入激活值是一个 [B, M, K] 的张量,权重是 [K, N],输出为 [B, M, N]。当 B=32、M=512、K=1024、N=1024 时,单次前向传播就需要执行约 32×512×1024×1024 ≈ 1.7×10¹⁰ 次乘加运算。在 CPU 上,这类计算受限于核心数量与内存带宽;而在 GPU 上,同样的运算可以被拆分成数万个并行线程同时推进。理解 GPU 为什么适合矩阵运算,是后续所有优化工作的起点。

GPU 架构与矩阵运算的契合点

GPU 的设计哲学与 CPU 截然不同。CPU 将大量晶体管用于分支预测、乱序执行和多级缓存,擅长处理逻辑复杂、依赖链长的串行任务;GPU 则将芯片面积大量投入算术逻辑单元(ALU),以成百上千个轻量级核心换取极高的吞吐量。以 NVIDIA 的 SM(Streaming Multiprocessor)结构为例,一个 SM 内包含多个 CUDA Core、若干 Warp Scheduler 以及寄存器文件和共享内存。线程以 32 个为一组构成 Warp,同一 Warp 内的线程执行相同指令,这种 SIMT(单指令多线程)模型天然适合矩阵乘法中“每个输出元素执行相同乘加模式”的特点。

矩阵乘法的核心计算 C[i][j] = Σ A[i][k] × B[k][j] 具有两个关键性质:一是输出元素之间相互独立,可完全并行;二是每个输出元素需要复用 A 的一行和 B 的一列。GPU 的层次化存储结构恰好匹配这一复用模式——全局内存容量大但延迟高,共享内存延迟低且可被同一线程块内的线程共享,寄存器则供单个线程私有使用。将 A 和 B 的分块数据先加载到共享内存,再由各线程从共享内存读取并累加到寄存器,就能大幅减少对全局内存的重复访问。这正是矩阵运算在 GPU 上获得加速的结构性原因。

GPU 层次化存储与矩阵分块计算的契合关系 矩阵分块(Tiling) 矩阵 A [M×K] A块 矩阵 B [K×N] B块 × 矩阵 C [M×N] C块 共享内存(Shared Memory) A 分块 B 分块 线程块内所有线程共享访问 延迟远低于全局内存 减少重复全局读取 寄存器与线程 线程 0 线程 1 线程 2 线程 3 私有累加器 零延迟访问 全局内存(Global Memory / HBM) 容量大、带宽高,但访问延迟约为共享内存的数十倍 —— 分块复用的目的就是减少对它的重复访问 加载分块 分块尺寸(如 16×16、32×32)决定共享内存占用与全局内存访问次数,是后续调优的关键参数

批处理加速的核心价值

单次矩阵运算的加速只是起点,真正让 GPU 发挥威力的是批处理。所谓批处理,是指将多个相互独立的计算任务(例如一个批次内的多条样本、多个卷积核、多个注意力头)组织成更大的张量,一次性提交给 GPU 执行。其价值体现在三个层面。

第一是提高并行度利用率。GPU 的 SM 数量有限,若单个任务规模太小,线程块数量不足以填满所有 SM,大量计算单元处于空闲状态。批处理将多个小矩阵拼接为大矩阵或批量矩阵,使网格规模成倍增长,SM 占用率显著提升。第二是摊薄启动与调度开销。每次内核启动都有固定开销,包括主机端到设备端的命令传递、网格调度等。批处理将多次小规模启动合并为一次大规模启动,单位计算量分摊的开销随之下降。第三是改善内存访问效率。批量数据在内存中连续排布时,相邻线程访问相邻地址,容易形成合并访问(coalesced access),一次内存事务可服务更多线程,有效带宽利用率更高。

以批量矩阵乘法(Batched GEMM)为例,假设有 64 个 64×64 的矩阵对需要相乘。若逐个调用内核,每次只有 64×64 的输出规模,网格中线程块数量有限;若采用批量 GEMM,将 64 个矩阵组织为 [64, 64, 64] 的张量,一次内核启动即可让所有矩阵对并行计算,网格规模扩大 64 倍,SM 得以充分填充。实际工程中,cuBLAS 的 cublasGemmStridedBatched 接口正是为此设计,通过 strideA、strideB、strideC 参数描述批量矩阵在内存中的步长,一次调用完成全部计算。

批处理并非越大越好。批量增大意味着显存占用上升,且当批量超过一定规模后,SM 已接近饱和,继续增大批量带来的边际收益递减。实际调优时需要在吞吐量、显存容量和延迟之间取得平衡,这一权衡将在后续章节结合具体案例展开。

课程实战项目概览

本课程以一个贯穿始终的实战项目为主线:基于 CUDA 的批量矩阵乘法加速库。项目从最朴素的三重循环实现出发,逐步引入共享内存分块、寄存器分块、向量化加载、双缓冲流水线、批量调度等优化手段,每一阶段都配有可运行的代码、性能测量方法与结果分析。项目输入为随机生成的批量矩阵对,输出为计算结果与性能指标(GFLOPS、有效带宽、SM 占用率),并通过与 cuBLAS 参考实现的对比验证正确性与加速比。

项目将分为若干递进阶段:第一阶段完成基础内核并建立正确的性能测量基线;第二阶段实现共享内存分块,观察全局内存访问次数的下降;第三阶段引入寄存器分块与线程级并行,提升计算访存比;第四阶段加入批量维度与流水线调度,处理真实规模的批量负载;最后阶段进行综合调优与结果复盘。每个阶段都要求读者能够回答三个问题:当前实现的瓶颈在哪里、采取了什么手段、性能数据如何证明改进有效。掌握这套“实现—测量—分析—改进”的闭环方法,比记住某个具体优化技巧更有长期价值。

需要强调的是,本课程中的性能数据均为教学示例或合理估算,用于说明优化趋势与判断依据,不代表在特定硬件上的实测结果。读者在自己的设备上复现时,应以实际测量为准,并结合 GPU 型号、驱动版本和编译选项综合解读。