简介:本文给出一条系统的CUDA学习路线:从线程层级与内存模型起步,依次实现元素级算子、归约、归一化与softmax等基础kernel,再深入GEMV/GEMM的访存与分块优化,进阶Tensor Core与PTX级编程,最终完成注意力类算子的高性能实现,并配套数值验证与性能剖析方法,帮助读者构建可迁移的GPU优化能力。
大模型与AI应用的爆发,让GPU算力成为基础设施的核心。主流深度学习框架自带的算子只能覆盖通用场景,实际业务中总会遇到需要手写高性能kernel的时刻:自定义激活函数、特殊布局的矩阵运算、注意力结构变体、推理链路中的算子融合等。这时“会用框架”与“能写kernel”之间的差距,会直接体现在训练与推理的成本上。
系统学习CUDA的价值可以归纳为三点:
学习CUDA最大的误区是“看得懂就等于会写”。CUDA是一门手艺,性能是测出来的,只有亲手实现、亲手验证、亲手剖析,才能把知识内化成能力。
在动手写kernel之前,建议补齐以下基础:
同时要养成两个贯穿始终的习惯:
从最简单的kernel入手,目标是把索引计算、线程组织、访存模式练成肌肉记忆。以ReLU为例:
__global__ void relu(const float* x, float* y, int n) {int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n) y[i] = fmaxf(x[i], 0.0f);}
看似简单,但每个细节都值得推敲:
float4一次读写四个元素,减少访存指令数;
__global__ void relu_float4(const float4* x, float4* y, int n4) {int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n4) {float4 v = x[i];y[i] = make_float4(fmaxf(v.x, 0.f), fmaxf(v.y, 0.f),fmaxf(v.z, 0.f), fmaxf(v.w, 0.f));}}
随后按清单推进难度递增的练手题:
__global__ void transpose(const float* in, float* out, int M, int N) {__shared__ float tile[32][32 + 1]; // +1 padding,规避bank conflictint x = blockIdx.x * 32 + threadIdx.x;int y = blockIdx.y * 32 + threadIdx.y;if (x < N && y < M) tile[threadIdx.y][threadIdx.x] = in[y * N + x];__syncthreads();x = blockIdx.y * 32 + threadIdx.x;y = blockIdx.x * 32 + threadIdx.y;if (x < M && y < N) out[y * M + x] = tile[threadIdx.x][threadIdx.y];}
__inline__ __device__ float warp_reduce_sum(float val) {for (int offset = 16; offset > 0; offset >>= 1)val += __shfl_down_sync(0xFFFFFFFFu, val, offset);return val;}
工业级kernel必须面对多种数值格式,各自的位宽与适用场景要心里有数:
实践要点:
这一阶段是把“规约能力”落到真实模型算子上:
GEMV(矩阵向量乘)是带宽受限问题,目标只有一个:把显存带宽吃满。手段包括合并访存、让每个线程负责多行多列以摊薄索引计算、向量化加载、warp级规约汇总部分和。
GEMM(矩阵乘)是计算受限问题,优化阶梯非常清晰,建议逐级迭代并记录每一级的性能:
每一步都应该用roofline的思维判断:瓶颈到底在带宽还是算力?这个“从几十GFLOPS一步步逼近硬件极限”的过程,是CUDA学习中最有成就感的部分,也是面试与实战中含金量最高的能力。
CUDA Core执行标量乘加,Tensor Core则直接完成小规模矩阵乘,吞吐量级完全不同。用好它需要分层推进:
ldmatrix等加载指令;这一层难度陡增,建议先彻底读懂指令的行列布局约定再动手。布局错误的典型表现是:数值大致正确但性能极差,或者结果整体错位——都要靠小规模用例逐块排查。
把前面所有技能串起来。Transformer的注意力计算中,中间得分矩阵如果完整写回显存再读出,访存开销会吞掉大量算力。优化思路是:
检验标准可以定得很朴素:如果用MMA实现的分块注意力算子,性能能达到业界官方实现的大致水平,说明前面各阶段的能力已经真正贯通。
学习CUDA没有捷径,但有一条清晰的路:从elementwise起步,穿过转置与规约,翻越GEMM这座大山,登上Tensor Core与注意力算子的高峰。只要每个阶段都留下能跑、能测、能讲的代码,你就拥有了属于自己的、可长期增值的CUDA知识体系。