显存基础:从硬件到实战

大家好,我是你们的老朋友。今天咱们聊聊显存。

说实话,我刚开始做深度学习那会儿,对显存的理解就是「显存越大越好」。后来踩了不少坑,才慢慢摸清楚这里面的门道。你想想看,一个模型训练到一半,突然爆显存,那种感觉……嗯,懂的都懂。

所以这一章,咱们把显存的基础打扎实。别急,我会用我自己的经验,帮你避开那些我当年踩过的坑。

什么是显存?

显存,全称是「显示内存」。说白了,就是显卡上专门用来存数据的内存。

在深度学习里,显存里存的是啥?

  • 模型参数(权重、偏置)
  • 中间激活值(每一层的输出)
  • 梯度信息
  • 优化器状态(比如 Adam 的动量)
  • 输入数据(图片、文本等)

我习惯把显存想象成「GPU 的工作台」。工作台越大,你能同时处理的东西就越多。但工作台再大,也有放不下的时候——这时候就得想办法优化了。

核心要点:显存是 GPU 的「临时仓库」。模型训练时,所有需要快速访问的数据都得放在这里。

显存 vs 内存:到底有啥区别?

很多人搞混这两个概念。我刚开始也犯过这个错。

简单来说:

  • 内存(RAM):CPU 用的,存操作系统、应用程序、数据。容量大(16GB、32GB 甚至更大),但速度相对慢。
  • 显存(VRAM):GPU 用的,专门给显卡处理图形和计算任务。容量小(8GB、16GB、24GB 常见),但速度极快。

为什么会这样?因为 GPU 需要频繁读写数据,显存必须用高带宽的 HBM 或 GDDR 技术。内存用的是 DDR,带宽差了一个数量级。

特性 内存(RAM) 显存(VRAM)
用途 CPU 数据存储 GPU 数据存储
典型容量 16-64 GB 8-48 GB
带宽 ~50 GB/s ~900 GB/s(HBM2e)
延迟 ~100 ns ~200-400 ns
物理位置 主板上 显卡 PCB 上

避坑指南:我曾经以为把数据放在内存里,GPU 也能直接访问。结果发现每次 GPU 要数据,都得先通过 PCIe 总线从内存拷贝到显存。这个拷贝过程慢得让人抓狂。所以记住:GPU 只认显存,不认内存。

GPU 架构简介:显存在哪?

咱们拿 NVIDIA 的 GPU 举个例子。一张显卡的核心架构大致是这样的:

GPU 核心 (SM) 流式多处理器 CUDA 核心 Tensor Core 寄存器文件 L1 缓存 / 共享内存 L2 缓存 显存 (VRAM) HBM2e / GDDR6 容量: 8-80 GB 带宽: 900 GB/s+ 延迟: ~200-400 ns 显存控制器 (Memory Controller) PCIe 总线 → 系统内存 数据流 数据流 数据流

这张图是我自己画的,方便你理解。GPU 核心(SM)直接连接 L1 缓存,然后通过 L2 缓存访问显存。显存控制器负责管理数据进出。

我个人的经验是:显存带宽比容量更重要。为什么?因为模型训练时,数据搬运的速度往往成为瓶颈。你容量再大,带宽不够,GPU 核心就得干等着。

小技巧:选显卡时,别只看显存大小。看看带宽参数。比如 A100 的 HBM2e 带宽是 1.6 TB/s,而 RTX 3090 的 GDDR6X 是 936 GB/s。差了一倍。

显存带宽与容量:怎么选?

这个问题我经常被问到。我的回答是:看你的任务。

  • 大模型训练(LLM、ViT):容量优先。模型参数动辄几十 GB,显存不够根本跑不起来。
  • 高分辨率图像处理:带宽优先。每张图数据量大,需要快速搬运。
  • 实时推理:带宽优先。延迟要求高,数据必须快进快出。

举个例子。我去年训练一个 7B 参数的 LLaMA 模型,单张 A100 80GB 勉强能塞下。但 batch size 只能设 1。如果换成 4 张 RTX 3090 24GB,虽然总容量 96GB,但跨卡通信的开销让训练速度慢了一半。

所以,容量决定你能不能跑,带宽决定你跑得快不快。

显卡型号 显存容量 显存带宽 适合场景
RTX 3060 12 GB 360 GB/s 小模型、入门
RTX 3090 24 GB 936 GB/s 中等模型、炼丹
A100 80GB 80 GB 1.6 TB/s 大模型、训练
H100 80 GB 2.0 TB/s 超大模型、训练

注意:别被「显存共享」这种技术忽悠了。有些显卡支持从系统内存借空间,但速度慢得离谱。我曾经试过,训练速度直接掉到原来的 1/10。除非万不得已,别用。

实战:如何查看显存使用情况?

说了这么多理论,来点实际的。怎么知道自己显存用了多少?

我常用的命令:

# 查看 GPU 状态
nvidia-smi

# 实时监控
watch -n 1 nvidia-smi

# Python 里查看
import torch
print(torch.cuda.memory_allocated())  # 已分配显存
print(torch.cuda.memory_reserved())   # 预留显存
print(torch.cuda.max_memory_allocated())  # 最大分配显存

我个人习惯在训练脚本里加个显存监控,每 100 步打印一次。这样能及时发现显存泄漏或者异常增长。

经验之谈:显存泄漏是常见问题。如果你发现训练过程中显存持续增长,不释放,那八成是代码里有变量没释放,或者 DataLoader 的 num_workers 设置有问题。

好了,这一章就到这里。显存的基础概念、架构、带宽和容量,咱们都聊透了。下一章开始,我会带你看看怎么用代码优化显存——那些我踩过的坑,你就不用再踩了。

想要更多资料,联系可可