- Published on
cuBLAS 基础教程:GPU 上的高性能矩阵运算
cuBLAS 教程
学习目标
- 理解 cuBLAS 库及其在 CUDA 编程中的作用
- 学习如何使用 cuBLAS 执行基本的矩阵运算
- 探索 cuBLAS 的高级功能以优化性能
1. cuBLAS 概述
cuBLAS 是 NVIDIA 在 GPU 上实现的基本线性代数子程序库。它提供了经过高度优化的常用线性代数运算例程,例如矩阵乘法、向量加法等。cuBLAS 专门设计用于利用 NVIDIA GPU 的并行处理能力,是高性能计算应用的有力工具。
cuBLAS 特别适用于需要高效矩阵运算的应用,例如科学计算、深度学习等。
cuBLAS 提供了以下常用线性代数运算的优化例程:
- 向量运算(Level 1 BLAS)
- 矩阵-向量运算(Level 2 BLAS)
- 矩阵-矩阵运算(Level 3 BLAS)
2. 使用 cuBLAS 进行矩阵乘法
cuBLAS 的矩阵乘法操作为:C = alpha * A * B + beta * C,其中 A、B 和 C 都是矩阵。
重要提示: cuBLAS 的头文件是
cublas_v2.h,链接库时需要添加-lcublas参数。
3. 列主序与行主序
存储方式对比
- 行主序:矩阵按行连续存储在内存中
- 列主序:矩阵按列连续存储在内存中
示例
对于矩阵 A[2][2] = {{1, 2}, {3, 4}}:
行主序存储:
内存地址: 0 1 2 3
存储元素: 1 2 3 4
列主序存储:
内存地址: 0 1 2 3
存储元素: 1 3 2 4
重要区别
cuBLAS 使用列主序(类似 Fortran),而 C/C++ 使用行主序。如果需要在两者之间转换,可以使用以下宏定义:
#define IDX2C(i,j,ld) (((j)*(ld))+(i)) // 列主序索引宏
4. cuBLAS 句柄
cuBLAS 是一个有状态库。它不使用全局状态,而是通过句柄对象(cublasHandle_t)来跟踪:
- 使用哪个 CUDA 流
- 分配的工作空间
- 算法偏好
- 错误状态
有状态库说明:有状态库是指在函数调用之间通过上下文或句柄维护内部状态的库。这种状态会影响函数的行为,允许库管理配置、资源或执行上下文。
这种设计支持:
- 多个独立的 cuBLAS 上下文
- 线程安全(可在不同线程中使用不同句柄)
- 更好的性能调优控制
创建和销毁句柄
// 创建句柄
cublasHandle_t handle;
cublasCreate(&handle);
// 使用句柄进行运算...
// 销毁句柄(释放资源)
cublasDestroy(handle);
5. cuBLAS 运算
cublasSgemm 函数
cublasSgemm 是用于单精度矩阵乘法的函数,执行的操作为:C = alpha * A * B + beta * C
其中:
A是 m × n 矩阵B是 n × k 矩阵C是 m × k 矩阵alpha是乘积 A * B 的标量乘数beta是现有矩阵 C 的标量乘数
领先维度说明
领先维度 是指内存中一列开始到下一列开始之间的距离。对于 cuBLAS 使用的列主序存储,它指的是矩阵的行数。
函数调用示例
cublasSgemm(
handle, // cuBLAS 句柄
CUBLAS_OP_N, // A 的操作类型(CUBLAS_OP_N 表示不转置)
CUBLAS_OP_N, // B 的操作类型
N, // A 和 C 的行数
N, // B 和 C 的列数
N, // A 的列数和 B 的行数
&alpha, // A*B 的标量乘数
d_A, // 设备内存中矩阵 A 的指针
N, // A 的领先维度
d_B, // 设备内存中矩阵 B 的指针
N, // B 的领先维度
&beta, // C 的标量乘数
d_C, // 设备内存中矩阵 C 的指针
N // C 的领先维度
);
注意:在使用 cuBLAS 时,你不需要像原始 CUDA 内核启动那样手动配置线程块和网格。cuBLAS 内部会自动:
- 检查矩阵大小和布局
- 选择最佳的内核和块/线程/网格配置
- 使用其内部逻辑启动内核
6. 结果输出
最终结果 C 采用列主序存储,这是 cuBLAS 的默认方式。打印结果时需要使用正确的索引:
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
std::cout << h_C[IDX2C(i, j, N)] << " ";
}
std::cout << "\n";
}
7. 关键要点总结
✅ cuBLAS 是一个有状态库,使用句柄管理其状态 ✅ 句柄通过 cublasCreate 创建,通过 cublasDestroy 销毁 ✅ 矩阵乘法使用 cublasSgemm 执行,需要指定操作类型、维度和矩阵指针 ✅ cuBLAS 对矩阵使用列主序,与 C/C++ 使用的行主序不同 ✅ 领先维度对于在内存中正确访问矩阵元素非常重要 ✅ 可以在同一程序中运行多个 cuBLAS 内核,甚至可以并发运行
THE END