本地跑 SenseNova-Vision 这类视觉大模型,卡选错的常见原因不是算力不够,而是显存账没算清:权重按什么精度加载、图像按什么分辨率送进去、一次送几张,这三项各自吃多少显存,先分开估,再用本机实测对齐,最后才轮到挑型号。顺序颠倒过来——先买卡再试精度和分辨率——很容易落到“模型能加载但批量只能给 1”或者“单图能跑、批量一开就 OOM”的局面。
适用场景:准备为视觉大模型采购或升级本地显卡。操作动作:按参数量乘每参数字节数先估权重下限,再按特征图尺寸与批量估激活上限,然后用 nvidia-smi 记录基线、峰值、稳态占用,最后按单图、小批量、多分辨率顺序压测。验证方式:同一配置重复跑两次,确认峰值显存能稳定复现。风险边界:激活部分的系数受实现影响很大,只能实测确定;估算值用于排除明显不合适的档位,不能代替实跑。
算权重本身占多少:不同精度下每个参数占几个字节
显存需求的下限就是权重本身,它只跟参数量和加载精度有关,跟图像尺寸、批量都无关。换算口径可以直接写成:
权重显存下限 ≈ 参数量 P × 每参数字节数 B
B 的常用口径(按加载精度取):
fp32 4 字节/参数
fp16/bf16 2 字节/参数
fp8/int8 1 字节/参数
4bit 约 0.5 字节/参数,另加量化元数据
参数量 P 从模型卡、权重文件元信息或加载日志里读,不要凭模型名字猜。视觉大模型通常由语言塔、视觉编码器和投影层组成,三部分参数都要计入;有的仓库会把视觉塔和语言塔放进不同权重文件,各文件字节数之和是权重显存下限的一个直观参照,但实际加载时还会有临时副本和格式转换的中间缓冲,通常比文件总和大一些,可以先按文件总字节数打底,再用实测修正。
量化档位不要只按名义位宽算。4bit 权重通常带 scale、zero-point 之类的分组元数据,按 0.5 字节/参数估会偏低,实际以“加载前后整卡显存增量”为准,这个增量在同一台机器上重复测基本可复现。这一节只给口径,不给具体型号结论——同一张卡跑不跑得动,取决于你选的参数量、精度,以及下一节的激活开销。
把激活与中间张量算进去,说明分辨率翻倍时显存为何涨得更快
只按权重估显存一定偏低,因为推理时还要驻留激活与中间张量。以视觉编码器为例,某一层的特征图可以写成 [B, C, H, W],它占的字节数大致是:
特征图显存 ≈ B × C × H × W × 每元素字节数
ViT 类结构先把图切成 patch:
token 数 N ≈ (H / patch) × (W / patch)
分辨率 H、W 各翻一倍 → N 约变为 4 倍
若注意力把分数矩阵物化:注意力中间张量 ≈ B × heads × N × N
→ N 变 4 倍时,这一项约变 16 倍
这就是分辨率翻倍、显存涨得更快的来源:线性部分(特征图、KV 缓存随 token 数)按约 4 倍涨,二次部分(注意力分数矩阵)按约 16 倍涨,实际落在哪一侧,取决于实现是否物化分数矩阵、是否用分块注意力。
需要实测确定、不能靠公式拍板的系数包括:注意力实现是否物化 N×N 矩阵;图像 token 是否在投影层被压缩到固定长度(有些实现会把任意分辨率压到固定 token 数,此时分辨率影响会被削弱);KV 缓存用什么精度、保留多长;框架是否保留全部中间层激活、是否启用显存复用。建议把上面公式当成趋势判断工具:它告诉你哪个方向涨得快,不告诉你具体涨到多少 MB。
在本机实测一次:跑前跑后各看一次显存
把估算值和真实值对上,只需要一条采样命令加一张记录表。加载模型前采一次基线,加载后采一次稳态,跑到目标配置时盯峰值。
# 每秒采样一次,观察整卡占用变化
nvidia-smi `--query-gpu`=timestamp,memory.used,memory.total `--format`=csv -l 1
# 只看当前快照,配合 watch 可做简易监控
watch -n 1 nvidia-smi
需要记录的四个字段:
- 基线占用:模型未加载时整卡已用显存,系统、其他进程、CUDA 上下文都算进去。
- 峰值占用:首次推理时整卡 memory.used 的最高点。首次推理常含编译和缓存分配,通常高于后续几次。
- 稳态占用:连续多次同配置推理后,整卡占用是否回落并稳定在某条水平线上。
- 失败点:出现 OOM 时的完整配置(精度、分辨率、批量)和报错原文。
如果推理栈基于 PyTorch,除整卡视角外还可以读框架自身的统计口径(max_memory_allocated、memory_reserved 一类接口),用来区分框架实际用了多少、缓存分配器占着多少。判定标准:峰值占用与总显存之间要留余量,不要把峰值压到等于可用显存;余量留多少取决于输入尺寸是否固定、是否可能出现更长序列,需要结合自己的使用场景确认。
按单图、小批量、高分辨率做阶梯压测
压测顺序固定为由小到大:单图、小批量、多分辨率。每一档只改一个变量,否则失败时说不清是哪一项超了。
- 单图档:分辨率取你打算使用的最小值,批量 1。判定条件:能跑通、输出正常、峰值占用稳定且与总显存之间留有余量。失败回退:先降分辨率,再考虑换更低位宽的加载精度。
- 小批量档:批量按 2、4、8 逐步加,分辨率保持不变。判定条件:每加一档后峰值增量是否大致线性,线性说明主要压力来自特征图和 KV。失败回退:退回上一档批量,把它记为这台机器的可用批量上限;若必须更大批量,再回头调分辨率或精度。
- 多分辨率档:分辨率按实现可整除的步长往上走(patch 尺寸决定哪些尺寸不浪费算力),批量固定在单图或已验证的小批量。判定条件:能跑通且峰值仍在余量范围内。失败回退:回到上一档分辨率,把该档记为这台机器在你这个精度下的可用上限。
每档都要记录:配置(精度、分辨率、批量)、峰值显存、稳态显存、单次耗时、是否 OOM、报错原文。把模型切到 CPU 或做部分卸载可以绕过 OOM,但吞吐会明显下降,它只用来确认“是不是显存不够”这个判断,不要当成可用配置写进选型结论。
把实测结果整理成选型口径表
压测结束后把每一档填进同一张表,换卡决策就变成“目标行能不能跑通”的问题,而不是凭感觉。
| 精度 | 分辨率 | 批量 | 峰值显存 | 是否可跑通 | 瓶颈在哪一环 |
|---|---|---|---|---|---|
| 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
| 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
| 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
“瓶颈在哪一环”从三处判断:如果峰值显存相比权重下限只多出很少,说明瓶颈不在权重;如果批量每加一档峰值近似按比例上涨,瓶颈在批量;如果单图就已经逼近可用显存,说明这台机器在这个精度下只适合单图或更低精度。换卡时看的不是峰值本身,而是你实际要用的精度和分辨率落在哪一行、那一行是否可跑通、峰值显存与目标卡可用显存之间还差多少余量。