导读:模型跑得慢,先别急着换卡。真正的问题往往不是 GPU 不够强,而是你有没有喂饱它。这篇不讲玄学参数表,只把 GPU 的关键单元和性能瓶颈一次讲清。
1. GPU 到底长什么样?
可以把 CPU 和 GPU 理解成两种团队:
- CPU:像一位经验丰富的全栈工程师,单兵能力强,擅长复杂控制流、串行逻辑和低延迟响应。
- GPU:像一支高度协同的流水线团队,单个单元不比 CPU 强,但人多、带宽高,适合处理成千上万个相似任务。
所以,GPU 擅长矩阵乘法、图像处理、大规模 Transformer 计算、深度学习训练和推理;但不擅长分支密集的逻辑、强依赖前一步结果的串行任务,以及频繁的 Host↔Device 数据搬运。
一句话总结:GPU 快,不是因为频率高,而是因为并行任务足够多、数据流足够顺。
更具体地说,GPU 的优势来自三件事:
- 并行度高:成千上万个线程同时工作。
- 带宽高:数据能快速进入计算单元。
- 专用单元多:Tensor Core、专用缓存、互联结构共同服务 AI 负载。
反过来,如果你的任务只有少量线程、强依赖上一步结果、或者频繁在 CPU 和 GPU 之间搬运数据,GPU 就很难发挥价值。
2. 执行模型的五层关系
在 CUDA 里,程序不是按传统函数调用跑的,而是按下面五层组织:
- Kernel:你写的并行函数,会被大量线程执行。
- Thread:最小执行单位。
- Warp:通常 32 个线程组成一个 Warp,是 GPU 调度的基本粒度。
- Block:一组线程,通常共享一块 Shared Memory。
- SM:Streaming Multiprocessor,真正执行线程的计算车间。
如果同一个 Warp 内的线程走出不同分支,就会出现 Warp Divergence,性能下降。所以写 CUDA 时,不要只问“线程够不够多”,还要问“同一 Warp 里的线程是不是在走相似路径”。
3. CUDA Core:通用计算单元
CUDA Core 是 GPU 里的通用算术单元,负责 FP32、INT32 等普通计算。它不是“最强单元”,而是“最灵活单元”。
适合做的事:
- 通用数值计算
- 向量运算
- 图像处理
- 部分 AI 训练辅助任务
不太适合做的事:
- 大规模矩阵乘法的主力计算
- 强串行逻辑
- 分支密集的控制流
一句话总结:CUDA Core 是基础算力,Tensor Core 才是为 AI 场景准备的高效车道。
4. Tensor Core:矩阵乘法专用单元
可以把 Tensor Core 理解为 GPU 里的“矩阵乘法专用车道”。
普通 CUDA Core 更像通用工人,什么都能算;Tensor Core 则专门优化了小矩阵块乘加运算,非常适合深度学习中的 GEMM 操作。
以 A100 为例,不同精度对应不同吞吐:
- TF32:训练中常用的“甜点”,代码改动少,性能提升明显。
- BF16:更适合训练,动态范围更大。
- FP16:训练和推理都常用。
- INT8 / INT4:更适合量化推理。
- 2:4 Structured Sparsity:权重满足稀疏模式时可进一步加速。
所以,模型优化时不要只问“能不能用 Tensor Core”,还要问:
- 我的精度需求是什么?
- 我的瓶颈是算力还是带宽?
- 量化后精度是否还能满足业务要求?
5. SM:GPU 里的计算车间
SM 是理解 GPU 架构的核心。它里面通常包含:
- Warp Scheduler:调度 Warp 执行。
- CUDA Core:执行通用算术。
- Tensor Core:执行矩阵乘法。
- Register File:线程私有寄存器。
- Shared Memory / L1 Cache:SM 内共享缓存。
- Load/Store Unit:负责访存。
可以把 SM 理解为一个计算车间:Warp Scheduler 是车间主任,CUDA Core 是普通工人,Tensor Core 是专用工人,Register 和 Shared Memory 是车间内的工作台和共享白板。
6. 内存层级:真正决定性能的地方
很多人把“显存”当成一个整体,这是最大的误解之一。GPU 里至少要看懂这些层级:
- Register:最快,线程私有,要避免寄存器溢出。
- Shared Memory:SM 内共享,低延迟,适合缓存复用数据。
- L1 Cache:SM 内缓存,有时和 Shared Memory 共享空间。
- L2 Cache:全局共享缓存,提高中间结果命中率。
- Global Memory / HBM:容量大、带宽高,但延迟更高,要合并访问。
- Host Memory:CPU 侧内存,要减少 PCIe 传输。
性能差的常见原因不是算力不够,而是:
- 相邻线程访问了不连续地址;
- 本来可以放进 Shared Memory 的数据,反复访问 HBM;
- 真正的瓶颈在 PCIe,而不是 GPU Kernel。
记住一句话:GPU 的性能不是算出来的,是喂出来的。
一个常见的判断方法是看计算强度:
- 如果计算量大、数据量小,通常更容易吃满算力。
- 如果计算量小、数据量大,瓶颈大概率在带宽。
- 如果频繁跨设备搬运数据,瓶颈可能在 PCIe 或主机内存。
7. 互联:NVLink、PCIe、GPUDirect
GPU 之间不是孤立工作的,互联方式决定了多卡效率。
- PCIe:通用互联,适合普通数据传输,但带宽有限。
- NVLink:GPU 间高速互联,A100 最多 12 links × 25 GB/s,总双向 600 GB/s。
- NVSwitch:让多张 GPU 形成更高效的互联拓扑。
- GPUDirect:减少 CPU 中转,让 GPU 之间或 GPU 与存储直接通信。
多卡训练时,互联经常比单卡算力更关键。
8. A100 视角:这些单元怎么组合起来
以 A100-SXM4-80GB 为例:
- Ampere 架构,Compute Capability 8.0
- 108 个 SM,约 6912 CUDA Cores
- HBM2e 显存理论带宽约 2 TB/s
- 40 MB L2 Cache
- 支持 TF32、BF16、FP16、INT8、INT4
- 支持 MIG,可以把一张物理 GPU 切分成多个隔离实例
- 支持 NVLink 3.0,多卡互联带宽 600 GB/s
A100 的价值不只是“大显存”,而是算力、带宽、互联、精度和资源隔离一起构成的数据中心 GPU 设计。
9. 优化顺序:按这个方向排查
遇到 GPU 性能问题,不要马上换卡,先按这个顺序排查:
- 先 Profile:不看数据就优化,基本等于猜。
- 看访存是否合并:相邻线程访问相邻地址,才能充分利用带宽。
- 看数据能否复用:能放 Shared Memory 或 L2 的数据,不要反复读 HBM。
- 看 Warp 分支是否发散:尽量减少同 Warp 内线程走不同路径。
- 看并行度是否足够:GPU 需要足够多的并行任务才能吃满。
- 看数据搬运:PCIe、NVLink、Host Memory 上的传输经常才是真瓶颈。
- 看同步和调度:线程块划分、Kernel 启动、流并行都会影响实际性能。
- 选对精度:不是所有任务都需要 FP32。
10. 常见坑:为什么 GPU 明明很强还是慢?
很多性能问题并不是“GPU 不够强”,而是用法不对。常见坑包括:
- 小 batch 吃不满 GPU:GPU 需要足够多的并行任务,batch 太小会导致利用率低。
- 频繁 CPU↔GPU 拷贝:每一步都在主机和设备之间搬运数据,GPU 会长时间等待数据。
- 数据布局不连续:相邻线程访问不连续地址,带宽利用率下降。
- Kernel 太碎:大量小 Kernel 反复启动,调度和同步开销盖过计算收益。
- 只看显存,不看带宽:显存够不代表带宽够,很多模型瓶颈其实在 HBM。
- 盲目上低精度:INT8/INT4 能提速,但精度损失可能影响业务效果。
- 忽略同步和通信:多卡训练时,通信时间可能比计算时间还长。
11. 什么时候才应该换卡?
换卡前建议先问六个问题:
- Profile 结果显示瓶颈真的在计算吗?
- 显存是否已经接近上限?
- 带宽是否已经打满?
- 多卡通信是否成为主要瓶颈?
- 精度和量化是否还能优化?
- 任务是否已经充分并行?
如果这些问题都没检查,先换卡通常只是把低效从一个地方搬到另一个地方。
12. 一个 5 分钟体检清单
拿到一个慢任务,可以按这个顺序快速判断:
- 看 GPU 利用率:利用率低,通常是并行度不足或数据供给不够。
- 看显存占用:显存接近上限时,优先考虑梯度检查点、混合精度或更小 batch。
- 看带宽利用率:带宽高而计算不高,说明瓶颈在访存。
- 看 PCIe/NVLink 流量:多卡任务尤其要关注通信时间。
- 看 Kernel 数量和耗时:小 Kernel 过多时,考虑算子融合或减少同步。
- 看精度选择:在满足业务精度的前提下,优先尝试 TF32/BF16/FP16。
13. 小结
真正理解 GPU,不是背型号,而是回答三个问题:
- 任务能不能被有效并行?
- 数据应该放在哪一层内存?
- 瓶颈在计算、访存、同步,还是搬运?
把这三个问题想清楚,很多“玄学调参”就会变成可解释的工程问题。
更实用的做法是:先 Profile,再看数据流,最后才考虑换硬件。
GPU 不是玄学,它是可以被解释、被测量、被优化的工程系统。