一、显存基础与硬件原理

大家好,我是你们这趟显存优化之旅的向导。今天咱们先不急着调参数、改代码,先把最底层的硬件逻辑理清楚。说白了,显存优化这件事,如果你不懂GPU怎么“看”数据、怎么“搬”数据,那后面所有的技巧都是空中楼阁。

我个人习惯,每接触一个新项目,第一件事就是翻翻硬件手册。你想想看,连你家水管多粗、水压多大都不清楚,怎么设计水路?显存优化也是这个道理。

1.1 GPU架构简介:从“大核”说起

GPU和CPU最大的区别是什么?CPU是“全能冠军”,什么活都能干,但一次只能干几件。GPU是“流水线工人”,每个工人只会简单的加减乘除,但胜在人多——成千上万个一起上。

现代NVIDIA GPU的核心架构,我习惯把它想象成一个“工厂园区”:

  • GPC(图形处理簇):相当于一个车间,里面有若干SM
  • SM(流式多处理器):核心生产单元,里面有CUDA核心、共享内存、寄存器等
  • CUDA Core:最底层的“工人”,执行算术运算

举个例子,A100 GPU有108个SM,每个SM里有64个FP32 CUDA核心。算下来总共6912个核心。但注意,这些核心不是独立的——它们共享SM内的寄存器文件和共享内存。

关键认知: 显存优化的本质,不是让单个CUDA核心跑得更快,而是让所有核心在等待数据时“少发呆”。

我在项目中遇到过不少同学,一上来就盯着算法复杂度优化,结果发现瓶颈根本不在计算,而在显存带宽。嗯,这就是典型的“方向错了”。

1.2 显存类型与带宽:数据高速公路的“车道数”

显存,全称是“视频随机存取存储器”(VRAM)。目前主流的是GDDR6和HBM2/2e/3。它们有什么区别?

类型 带宽(GB/s) 容量(常见) 典型卡型
GDDR6 ~500-900 8-24 GB RTX 3090, RTX 4090
HBM2 ~900-1200 16-32 GB V100, A100
HBM2e ~1200-1600 32-80 GB A100 80GB, MI250
HBM3 ~2000-3500 80-144 GB H100, B200

带宽为什么这么重要?我打个比方:假设你的CUDA核心是“厨师”,显存就是“食材仓库”。厨师切菜再快,如果食材从仓库搬过来的速度跟不上,厨师就得干等着。这个“搬食材的速度”就是带宽。

我的经验: 做显存优化时,先看一眼你的kernel是“计算密集型”还是“访存密集型”。如果是后者,优化计算逻辑基本没用,得从数据布局和访存模式下手。

为什么会这样?因为GPU的算力增长远快于显存带宽增长。你看,H100的FP16算力接近2000 TFLOPS,但显存带宽只有3.35 TB/s。算力与带宽的比值越来越大,这意味着“喂饱”计算核心越来越难。

1.3 显存与主存的数据通路:PCIe这根“独木桥”

显存和CPU主存之间怎么通信?靠PCIe总线。目前主流是PCIe 4.0 x16,单向带宽约32 GB/s。注意,这个数字比显存带宽低了一个数量级。

我曾经踩过一个坑:训练一个大模型,数据预处理在CPU上做,然后每次迭代都从主存拷贝到显存。结果发现GPU利用率只有30%多,大部分时间都在等数据从PCIe传过来。后来改成异步预取 + 数据提前驻留显存,利用率直接拉到95%以上。

数据通路的关键路径是这样的:

CPU主存 → PCIe控制器 → GPU显存控制器 → L2缓存 → L1/共享内存 → 寄存器 → CUDA核心

每一步都有延迟和带宽限制。我个人习惯把这条路径上的“瓶颈点”画出来,然后逐个击破。

避坑指南: 我曾经见过有人把整个数据集放在CPU内存里,每次训练都通过PCIe传输。对于小数据集还好,一旦数据量超过几十GB,这个做法基本不可行。正确的做法是:能放显存就放显存,放不下就用数据加载器做流水线。

1.4 CUDA核心与显存的关系:计算与存储的“博弈”

CUDA核心和显存之间,不是简单的“取数据→算结果”关系。中间还有一层层的缓存结构:

  • 寄存器:每个线程私有,速度最快,容量极小(每个SM约64K-256K个32位寄存器)
  • 共享内存:同一个线程块内共享,可编程管理,延迟约20-30周期
  • L1缓存:每个SM私有,通常和共享内存共用一块物理存储
  • L2缓存:所有SM共享,容量几MB到几十MB
  • 显存:全局存储,延迟约200-400周期

你想想看,从显存读一次数据要几百个周期,而从寄存器读只要1个周期。这差距有多大?所以优化的核心思路就是:让数据尽量靠近计算单元。

我举个例子,矩阵乘法优化中,最经典的手法就是“分块”(tiling)。把大矩阵切成小块,先加载到共享内存,然后让CUDA核心反复使用这些数据。这样,原本需要反复访问显存的操作,变成了访问共享内存——速度提升一个数量级。

核心公式: 程序性能 ≈ 计算时间 + 访存时间。当访存时间占主导时,优化计算逻辑是徒劳的。先解决“数据搬运”问题。

下面这张图,是我自己总结的显存优化知识体系。你可以把它当作整个课程的地图:

显存优化知识体系 目标:最小化显存占用 + 最大化带宽利用 硬件理解 访存模式优化 显存管理策略 硬件理解 • GPU架构(SM/CUDA Core) • 显存类型与带宽 • 数据通路(PCIe/缓存层级) • 计算与访存的比例关系 访存模式优化 • 合并访问(Coalescing) • 共享内存分块(Tiling) • 数据复用与局部性 • 向量化加载/存储 显存管理策略 • 显存池与复用 • 梯度检查点(Checkpointing) • 混合精度训练 • 显存碎片整理 工具链:nsys / ncu / nvprof / 自定义Profiler 持续迭代:Profile → 分析 → 优化 → 验证

这张图把整个课程的核心脉络串起来了。你会发现,所有优化技巧最终都回归到两个基本问题:数据放在哪?数据怎么搬?

好了,第一章的内容就到这里。记住我今天说的:显存优化的起点,是对硬件的敬畏和理解。后面我们会一步步深入每个技术细节,到时候你会发现,今天讲的这些“底层知识”,会反复出现在每一个优化案例中。

课后小作业: 打开你的GPU,用 nvidia-smi -q -d MEMORY 看看显存带宽和容量。再跑一个简单的矩阵乘法,用 nsys profile 看看实际带宽利用率。你会发现,理论值和实际值之间,往往差着一个“优化”的距离。

可可精品资料库