吞吐与显存概述
吞吐量和显存,这两个词在AI系统里就像一对欢喜冤家。我刚开始做模型部署时,总觉得只要把吞吐量拉满就行,结果显存爆了,模型直接崩掉。后来才明白——吞吐是速度,显存是空间,两者必须一起考虑。
什么是吞吐量?
吞吐量,说白了就是单位时间内能处理多少数据。在AI推理场景里,常用的是每秒处理的样本数(Samples per Second)。
举个例子:你有一个图像分类模型,1秒钟能处理100张图片,那吞吐量就是100 samples/s。
吞吐量的核心公式
Throughput = Batch Size × Batch数 / 时间
或者更直观的:吞吐量 = 总样本数 / 总耗时
我遇到过不少团队,只盯着单张图片的推理延迟看。延迟低不代表吞吐高,你想想看——如果一次只处理1张图,延迟是10ms,但一次处理32张图,延迟可能变成50ms。算下来,后者吞吐量反而更高。
什么是显存?
显存(VRAM)就是GPU上那块高速内存。模型参数、中间激活值、优化器状态、梯度……全得塞进去。
显存消耗主要来自三块:
- 模型参数:权重和偏置,这个基本固定
- 激活值:前向传播时每层的输出,跟batch size成正比
- 临时缓冲区:框架内部的各种缓存
我记得有一次调一个LLM推理服务,显存占用从12GB飙到22GB,排查了半天——原来是激活值缓存没释放。嗯,这里要注意,显存不是无限用的,爆了就OOM,服务直接挂。
为什么两者需要协同优化?
这个问题其实很现实。你单独优化吞吐,可能会把显存撑爆;你单独省显存,吞吐又上不去。
我画了一张图,帮你理清它们的关系:
从图上你能看到,吞吐和显存是相互制约的。增大Batch Size能提升吞吐,但显存占用也线性增长。反过来,用梯度累积省显存,又会让吞吐下降。
我的经验之谈
做吞吐优化时,我习惯先摸清显存天花板。比如一张A100有80GB显存,模型参数占20GB,那留给激活值的空间就是60GB。在这个范围内,尽量把Batch Size推到最大。
但别死板——有时候显存没爆,但计算单元已经跑满了,再增大Batch Size也没用。这时候就该考虑计算与传输重叠了。
一个简单的例子
假设你有个Transformer模型,单卡推理:
# 伪代码示意
model = load_model() # 参数占 10GB
for batch in dataloader:
# 激活值占 2GB(batch_size=8)
output = model(batch)
# 处理结果...
如果显存总共16GB,那batch_size=8时,总占用12GB,还有4GB余量。你试试把batch_size提到16——激活值变成4GB,总占用14GB,依然安全。但提到32,激活值8GB,总占用18GB,直接OOM。
注意
显存占用不是线性的。框架内部还有各种临时缓冲区、CUDA context的开销。我曾经遇到过,明明算出来只占14GB,实际跑起来却报了OOM——就是因为框架额外预留了2GB的缓存。
所以,永远留10%~20%的显存余量,别卡着上限跑。
协同优化的核心思路
说白了就两句话:
- 让显存里的数据被充分利用——别加载了参数只算一次就扔掉
- 让计算单元别闲着——数据加载和计算尽量重叠
具体怎么做?后面章节会详细讲。这里先记住一个原则:吞吐和显存不是二选一,而是跷跷板的两端,你要找到那个平衡点。
我个人习惯,每次调优前先画一张显存-吞吐的二维图,标出当前系统的位置,再决定往哪个方向调。你试试看,比盲目调参有效得多。
想要更多资料,联系可可