给 NdArray 装上 CUDA 的轮子
内容提要
Ndarry是Rust编程语言中的高性能多维、多类型数组库,类似numpy。作者使用cublas库实现了在CUDA上运行的矩阵乘法函数,并通过FFI连接到Rust中。作者还实现了一个trait来给NdArray数组添加cuda_dot方法,实现了1D和2D矩阵之间的点乘。cublas在高维度矩阵乘法场景下展现出巨大优势。
延伸解读
为何选择 cuBLAS 而非手写 kernel
作者参考 Karpathy 的 llm.c 项目后发现,纯 C 手写的矩阵乘法 kernel 性能明显不如调用 cuBLAS 库。cuBLAS 是 NVIDIA 提供的 GPU 线性代数库,专门针对高性能科学计算优化。使用 cuBLAS 的另一个好处是无需手动通过 blockDim、threadIdx 计算数据下标,简化了开发。虽然性能不如 cuBLASLT,但接口更简单,适合作为学习 Rust 调用 CUDA 的切入点。
Rust 调用 CUDA 的工程化步骤
文章详细介绍了在 Rust 中调用 CUDA 的流程:使用 bindgen_cuda 将 .cu 文件编译打包成静态库,并通过 FFI 连接到 Rust。在 build.rs 中配置链接参数,包括 cudart、cublas、stdc++ 等库。随后封装 cublasSgemm 函数,并利用 trait 为 NdArray 添加 cuda_dot 方法,支持 1D 和 2D 矩阵的点乘。这种方案与 candle 项目类似,但更侧重于教学和轮子实现。
性能对比:低维与高维的分水岭
作者在 Azure 云主机(Nvidia A10 GPU,36 核 CPU)上进行了性能测试。结果显示,在低维度(如 64x64)时,NdArray-linalg 的 dot 耗时 2.27ms,而 cuda_dot 耗时 9.89ms,传统 BLAS 库更快。但随着维度升高,cuda_dot 优势急剧扩大:在 2048x1000 时,ndarray-linalg 耗时 22800ms,cuda_dot 仅 323.30ms。这表明 CUDA 加速在高维矩阵乘法场景下具有巨大优势,适合机器学习等大规模计算任务。
trait 设计带来的模块化与灵活性
作者通过定义 CudaDot trait,为 NdArray 数组添加了 cuda_dot 方法,并针对 1D 与 2D 矩阵的不同组合实现了多个版本。trait 是 Rust 类型系统的核心特性,无需继承或组合即可为已有库扩展功能,使代码更模块化、灵活且易于维护。这种设计模式在 Rust 生态中常见,有助于将 CUDA 加速能力无缝集成到现有数组操作中。
Q&A
NdArray是什么?
NdArray是Rust编程语言中的高性能多维、多类型数组库,类似于Python的numpy。
如何在Rust中使用CUDA进行矩阵乘法?
在Rust中使用CUDA进行矩阵乘法需要使用bindgen_cuda库将.cu文件编译成静态库,并通过FFI连接到Rust中。
cublas库的优势是什么?
cublas库优化了在GPU上执行基本线性代数操作,简化了数据下标计算,适合高性能科学计算。
cuda_dot方法支持哪些矩阵操作?
cuda_dot方法支持1D和2D矩阵之间的点乘操作。
在高维度情况下,cuda_dot的性能如何?
在高维度情况下,cuda_dot的性能明显优于NdArray-linalg库提供的dot方法。
如何实现NdArray的cuda_dot方法?
通过定义一个trait来实现NdArray的cuda_dot方法,支持1D和2D矩阵的点乘。