很多团队在云上跑大模型推理或深度学习训练时,都会遇到 CUDA out of memory。云服务器的显存容量出厂就固定了,不能像内存条那样再插一根。所以“扩展显存”其实是几条不同的路:换更大显存的实例、多卡分摊、压缩模型、把部分数据挪到内存或硬盘、改程序减少占用。每条路的成本和适用场景差别很大,选错了会白花钱。

先搞清楚显存被谁占了
以大语言模型推理为例,显存主要装三样东西:模型权重、KV Cache(保存上下文的注意力缓存),以及框架本身的运行开销。FP16 下每个参数占 2 字节,所以 7B 模型的权重约 14GB,70B 约 140GB。上下文变长或并发变高时,KV Cache 增长很快,有时比权重还难估。
训练占用更多。除了权重,还要算上梯度、优化器状态和激活值。用 Adam 训练时,显存往往是权重本身的四到六倍。扩容之前,先在业务高峰期用 nvidia-smi 看峰值显存,不要只看某一个瞬时值。
方案一:直接升配到大显存实例
最直接的办法是换规格。有团队原本用单张 24GB 的 A10 部署 7B 模型,推理时经常爆显存。换成单张 80GB 的 A100 后,权重和较长上下文的 KV Cache 都放得下,服务稳定性明显好转。
这种方式代码基本不用改,但单价高,热门时段大显存实例也可能缺货。如果任务是间歇性的,按需计费的大实例通常比长期占着一台卡更省。动手前先算一笔账:每月实际运行多少小时,再和长期租用的价格对比。
方案二:多卡并行分摊
单卡怎么都放不下时,就把模型切到多张卡上。70B 模型的 FP16 权重约 140GB,至少需要两张 80GB 的卡。常见做法是张量并行。使用 vLLM 时设置 tensor-parallel-size=2,框架会把每一层的权重切到两张卡上协同计算。
多卡方案要留意卡间通信。实例支持 NVLink 时,卡间传输快很多;只能走 PCIe 时,通信开销可能抵消一部分并行收益。选实例前,用 nvidia-smi topo -m 看一下互联拓扑。
方案三:量化压缩模型
把权重从 FP16 压到 INT8 或 INT4,体积能减半,甚至降到四分之一。70B 模型做 INT4 量化后,权重约 35 到 40GB,一张 80GB 的卡就能装下,剩余空间还能留给 KV Cache。
量化会损失一部分精度,不同任务的敏感程度差别很大。上线前,用自己业务的评测集对比量化前后的结果,确认在可接受范围内再切换。只看通用榜单的分数,不足以说明问题。
方案四:把数据卸载到内存或硬盘
训练和微调时,可以把一部分状态临时挪到 CPU 内存,甚至 NVMe 硬盘上。DeepSpeed 的 ZeRO-Offload 和 ZeRO-Infinity 就是为此设计的。有团队想在单卡上微调 13B 模型,开启 ZeRO-3 并把优化器状态卸载到 CPU 后,显存压力明显下降,训练终于跑通。
代价是速度。训练耗时通常要增加一倍以上。这个方案适合预算紧、时间充裕的任务,不适合有上线期限的项目。卸载到硬盘时还要看磁盘 IO,IO 慢会直接拖慢训练。
方案五:先改程序,减少占用
很多时候显存紧张,是程序占得太多造成的。几个常见的改法如下。
- 梯度检查点(Gradient Checkpointing):反向传播时重新计算一部分激活值,用多出来的计算时间换取激活值占用的明显下降。适合激活值占大头、GPU 算力还有余量的训练任务。
- PagedAttention:vLLM 采用的分页式 KV Cache 管理,减少显存碎片,同样的显存能支撑更多并发请求。
- 限制 max_model_len 和 batch size:如果业务用不到超长上下文,就把上限设低,避免单个请求占掉大块显存。
- 混合精度(BF16 或 FP16):激活值和中间结果的占用通常能降到约一半。权重和优化器状态未必同比例下降,不要按“一半”估算总显存。
怎么选
推理且精度要求高,优先考虑升配或多卡。预算紧、能接受一点精度损失,量化通常最划算。训练任务对时间不敏感,卸载配合梯度检查点比较实用。这几种办法经常组合使用,例如量化加上限制上下文长度。
扩容前后都要记录显存峰值、利用率、吞吐和延迟。这样才能判断问题是否真的解决,也能及时发现长期空转的实例。多卡方案还要确认框架版本、驱动和 CUDA 版本互相兼容,版本对不上时,排查往往要花很久。