01 它是干嘛的
CUDA 是英伟达的并行计算平台与编程模型。它把显卡从「只会画图」变成「什么都能算」的通用计算设备,并给开发者一套统一的编程语言、库和工具链。深度学习之所以能在英伟达的显卡上爆发,根子就在这里。
02 为什么会有它
2006 年之前:想用显卡算数学题,得先把题目伪装成一张图
显卡天生擅长「同时做大量相同的小计算」——它内部有几千个简单核心,画图时正好是给几百万个像素各算一次颜色。科学家很快发现,很多数学问题也是「一堆相同的小计算」,于是想借显卡来加速,但当时只能用画图的方式硬凑。
这种办法极其别扭:你得把数据伪装成「纹理」(也就是图片),把要做的计算伪装成「着色器」(决定像素颜色的程序),算完再想办法把结果当成像素「读」回来。一个简单的加法,要绕一大圈,调试基本靠猜。
CUDA 的出现把这条路铺平了:它提供一套直接的编程接口,你可以明确地说「我要开几千个线程,每个线程算一个数」,不再需要伪装成画图。开发者从「和显卡斗智斗勇」变成「专心写并行逻辑」,成本下降了一个数量级,生态也就此滚起雪球。
03 它怎么工作
显卡里有几千个简单的小核心,适合同时做大量相同的小计算;CPU 只有几十个但个个很强,适合处理复杂的逻辑分支。CUDA 让程序员用统一的语言把这些小核心调度起来,一起为一个大任务干活。
为什么「同时算很多个一样的数」这件事,显卡天生比 CPU 强
- 1① 把数据搬进显存
待处理的数据先从内存复制到显卡自带的显存,之后的计算都在显存里进行,数据不必来回搬运。
- 2② 启动成千上万个线程
开发者把任务写成一个「核函数」,然后用 CUDA 指定要开多少个线程(例如几万个),每个线程负责处理数据里的一个元素。
- 3③ 前向传播:海量矩阵乘法并行跑
深度学习最核心的运算就是矩阵乘法,本质是「很多个相同的乘加」。几千个核心同时开工,一块显卡就能顶上一大排 CPU。
- 4④ 计算误差并反向求梯度
把预测结果与正确答案比对得到误差,再反向逐层求出「每个参数该往哪个方向调」,这一步同样是大量并行计算。
- 5⑤ 更新参数后循环
按梯度调整参数,然后拿下一批数据重复上述过程。正是这个循环,让深度学习模型在海量数据上越练越准。
04 谁在用它
训练大模型、图像识别、语音识别等模型,几乎所有主流框架的默认加速后端都是 CUDA。
气象预报、分子动力学、流体仿真等需要大量并行计算的研究领域。
视频转码、滤镜、超分辨率等对海量像素做相同运算的任务。
风险定价、大规模数值模拟等需要并行加速的计算密集型场景。
05 怎么用
需要 C 或 C++ 基础并理解并行概念;纯应用开发者通常不必直接写 CUDA,用高层的库即可。
- 01在装有英伟达显卡的机器上安装驱动与 CUDA 工具包(Toolkit)。
- 02写一个核函数(kernel),用独特的线程编号让每个线程处理不同的数据。
- 03用「三尖括号」语法指定线程块数量与大小,把核函数启动到显卡上。
- 04用 cudaMemcpy 在内存与显存之间搬运数据,用 cudaMalloc 申请显存。
- 05编译运行并用性能分析工具查看瓶颈,逐步调整线程数与内存访问方式。
// 核函数:每个线程处理数组里的一个元素
__global__ void add(int* c, const int* a, const int* b) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
c[i] = a[i] + b[i];
}
int main() {
int n = 1024, size = n * sizeof(int);
int *a, *b, *c, *d_a, *d_b, *d_c;
a = (int*)malloc(size); b = (int*)malloc(size); c = (int*)malloc(size);
cudaMalloc(&d_a, size); cudaMalloc(&d_b, size); cudaMalloc(&d_c, size);
cudaMemcpy(d_a, a, size, cudaMemcpyHostToDevice);
add<<<(n + 255) / 256, 256>>>(d_c, d_a, d_b); // 一次启动 1024 个线程
cudaMemcpy(c, d_c, size, cudaMemcpyDeviceToHost);
cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);
free(a); free(b); free(c);
return 0;
}避坑提示
- !显存与内存之间的数据搬运很慢,能一次搬完就不要分多次,能留在显存里算就不要来回拷。
- !不是所有问题都适合并行:逻辑分支复杂、数据依赖强的任务,用强 CPU 反而更合适。
- !线程数不是越多越好,要匹配显卡的并行规模并注意内存访问是否连续,否则性能不升反降。
06 关键概念
- 并行计算
- 把一个大任务拆成许多小任务同时执行,而不是按顺序一件件做。
- 核函数(Kernel)
- 在显卡上运行的函数,被成千上万个线程各执行一次。
- 显存
- 显卡自带的内存,容量比主机内存小但带宽高得多,是并行计算的战场。
- 线程与线程块
- 线程是并行执行的最小单位,线程块把它们分组以便统一调度。