技术2026 · 09 / 096 分钟♡ 41评论 8

显存不够的时候,我先砍的不是模型

一张 24G 的卡跑一条多模态产线,最后发现真正吃显存的不是模型本身,是我对「同时」这两个字的执念。

这块卡,一年跑了四万多分钟

这条产线最早是在一张 24G 的卡上跑起来的。语音、口型、动画、合成,四个模型,理论上加起来 19G 出头,应该塞得下。

实际第一次跑,OOM。第二次把批大小砍到 1,还是 OOM。

我当时的第一反应和大多数人一样:换个小一点的模型。 幸好没有立刻动手,因为后来发现,模型根本不是问题所在。

显存不是「加起来」的,是「同时」的

把每个阶段的峰值显存单独测了一遍,一个反直觉的数字跳出来:四个模型里最大的那个,稳态只占 7G,但加载和第一次前向的瞬间峰值是 13G。那多出来的 6G 是什么?是框架为了加速预分配的工作区、是 kv 缓存的预留、是解码时临时的中间张量。

而我的编排逻辑,是四个模型同时驻留,等着上一步的产物一到就立刻接手。这个「随时待命」的设计在显存充足的机器上很漂亮,在 24G 的卡上就是四个峰值叠在一起,随便哪一刻踩到就炸。

问题不在任何一个模型,在我让它们同时存在。

第一刀:把「同时」改成「排队」

改动本身很无趣——把编排改成严格串行,前一个模型算完就释放,再加载下一个。

代价是每个环节之间多了几秒的加载时间。一条五分钟的成片,端到端慢了大概四十秒。

收益是:峭壁消失了。 显存曲线从四座山叠在一起,变成四座山排成一行,最高点就是那个 13G 的加载峰值。24G 的卡从「随时会炸」变成「绰绰有余」。

四十秒换一个不炸的系统,这笔账不用算。

第二刀:把「加载」这件事本身变便宜

串行化之后,瓶颈变成了反复加载。同一个模型一天要加载几百次,每次几秒,加起来是实实在在的一小时。

这里有两个我试过的办法:

第二个办法效果更好,但它改变了产线的形态——从「流式」变成了「批式」。这个取舍后面会单独写。

第三刀才是砍模型,而且砍的不是我以为的那个

做完前两步,显存已经不是瓶颈了。但我还是回头看了一眼模型选择,发现真正值得替换的不是最大的那个,而是一个很小、但被调用次数最多的辅助模型——它每次调用都要重建一部分状态,累计的开销比大模型还高。

换成一个更轻的实现,产线整体又快了 15%。

如果一开始就按直觉「砍最大的那个」,我会花一周替换一个根本不该动的模型,然后发现 OOM 照旧。

我从这件事里记住的

显存问题先看时间轴,再看模型列表。 把每个阶段的峰值画在同一条时间线上,哪些峰叠在一起一眼就能看出来。叠在一起的才是问题,单独看谁都不是问题。

还有一句更泛一点的:系统里最贵的往往不是最大的那个组件,而是你以为理所当然、从来没单独量过的那部分。

这篇里的照片Frames全部相册 →
深夜的生产线 · 三块屏都在跑
深夜的生产线 · 三块屏都在跑家 · 书房 · Sony A7C II · 24mm f/4
← 更早一篇
主引擎 + 降级兜底:我把工具链做成了容灾系统

关注公众号「十年追随」

新文章第一时间推给你。留言我都会回,公众号里也能收到回复通知。 不发广告,一周最多两条。

十年追随 公众号二维码
评论Comments8 条 · 匿名也能评,昵称头像会记住
评论服务(Waline)待部署 —— 香港 VPS 起来后填 SERVICES.waline 即生效。
想说话可以先去 留言板,那边我每条都回。
关注公众号「十年追随」更新第一时间推给你 · 留言也能收到我的回复
看二维码