先算清显存和帧数再选卡——LingBot-Video 本地跑视频生成的取舍

文章导读
想在本地跑 LingBot-Video,卡的选择先别急着看型号,先看三个互相拉扯的变量:帧数、分辨率、精度。显存不够,不一定立刻换卡——把帧数或分辨率退一档,往往就能跑起来。但该退哪一档,取决于占用随哪个变量涨得更快,这件事只能在自己的驱动、CUDA 版本和注意力实现上测一遍,别人机器上的数字搬过来不一定成立。
📋 目录
  1. 壹 先用最低配置跑一次,拿到基线占用
  2. 贰 只加帧数,看占用怎么变
  3. 叁 只加分辨率,看占用怎么变
  4. 肆 把长片段拆成多次短生成再拼接
  5. 伍 写出一条选卡判断线
A A

想在本地跑 LingBot-Video,卡的选择先别急着看型号,先看三个互相拉扯的变量:帧数、分辨率、精度。显存不够,不一定立刻换卡——把帧数或分辨率退一档,往往就能跑起来。但该退哪一档,取决于占用随哪个变量涨得更快,这件事只能在自己的驱动、CUDA 版本和注意力实现上测一遍,别人机器上的数字搬过来不一定成立。

先把帧数、分辨率、精度都压到最低,跑通一次并记录峰值显存、主机内存和单次耗时,这就是你的基线。之后每次只改一个变量:只加帧数、只加分辨率,分别记录读数,找出先撞墙的那一个。撞墙前的组合就是可跑区间,往外扩用分段生成绕开,选卡时按目标组合的峰值占用留出余量反推显存容量。

先用最低配置跑一次,拿到基线占用

最低配置的目的是让流程先跑通,同时拿到一组可信读数。帧数取模型允许的最小值,分辨率取 256×256 这类小尺寸,精度用 fp16,先不要开量化。参数名不一定和下面一致,先用 python infer.py `--help` 对齐,重点看帧数的合法步长(不少视频模型要求 4n+1 或 8n+1)以及宽高是否必须为 32 或 64 的倍数。

python infer.py \
  `--prompt` 'a red ball rolling on a table' \
  `--num-frames` 9 \
  `--height` 256 \
  `--width` 256 \
  `--dtype` fp16 \
  `--seed` 0

运行期间用 nvidia-smi `--query-gpu`=memory.used,memory.total `--format`=csv -l 1 轮询显存,主机内存用 /usr/bin/time -v 的 Maximum resident set size,两者不要混着看。更贴近真实占用的是在脚本里打点,生成前后各取一次差值:

import torch
torch.cuda.reset_peak_memory_stats()
# ... 调用一次生成 ...
print(torch.cuda.max_memory_allocated() / 1024**3, 'GiB')

把基线填进下面这张表,后面每一节都在它上面做单变量改动,每格记录“峰值显存 / 单次耗时 / 是否 OOM”。如果最低档这一步就 OOM,先把帧数降到更小的合法档位;仍不行再用 `--cpu-offload` 这类把权重和中间张量挪到主机内存的选项,它省显存但会明显拖慢单次耗时,只当能跑起来的手段,不要当成优化。

分辨率 \ 帧数9 帧17 帧33 帧
256×256   
384×384   
512×512   

只加帧数,看占用怎么变

固定 256×256、fp16、同一 seed 和提示词,只改 `--num-frames`,依次跑 9、17、33 三档,每档跑两三次,取峰值显存的较大值,避免偶然波动误导判断。

  • 9 帧:峰值显存 ___ GiB,单次耗时 ___ 秒,是否 OOM ___
  • 17 帧:峰值显存 ___ GiB,单次耗时 ___ 秒,是否 OOM ___
  • 33 帧:峰值显存 ___ GiB,单次耗时 ___ 秒,是否 OOM ___

看趋势比看单点有用:多数实现里显存随帧数近似线性增长,但如果注意力是全局时空的,增长会更陡。判断办法是比增量——17 帧到 33 帧的增量明显大于 9 帧到 17 帧,说明再往上拉帧数风险很快累积。首次 OOM 的那个帧数就是你在这张卡、这个分辨率下的帧数上限,日常出片值取它下面一档或一半更稳。

只加分辨率,看占用怎么变

把帧数固定在上一节能稳定跑的档位,只改 `--height` 和 `--width`,例如 256×256、384×384、512×512,宽高按 32 或 64 的倍数调整,避免内部下采样对不齐报错。

先算清显存和帧数再选卡——LingBot-Video 本地跑视频生成的取舍
  • 256×256:峰值显存 ___ GiB,单次耗时 ___ 秒
  • 384×384:峰值显存 ___ GiB,单次耗时 ___ 秒
  • 512×512:峰值显存 ___ GiB,单次耗时 ___ 秒,是否 OOM ___

分辨率吃的是像素面积,帧数吃的是时间长度,通常分辨率比帧数更费显存,但以你这三档的实测增量关系为准。画质是否够用不能只看显存够不够:512 档在十几帧的短片段里,人脸细节和文字通常还是偏糊;如果目标只是看构图和动作,320 或 256 档就够,把省下的显存加在帧数上,动作连续性往往提升得更明显。

把长片段拆成多次短生成再拼接

绕开显存上限最直接的做法是分段:把长片段切成首尾有重叠的若干段,上一段最后一帧导出为图片,作为下一段的首帧条件,段间保留 1~2 帧重叠来压低动作断点。

python infer.py \
  `--prompt` 'a red ball rolling on a table' \
  `--init-image` seg01_last.png \
  `--num-frames` 33 `--height` 384 `--width` 384 \
  `--dtype` fp16 `--seed` 0

各段导出成统一编码的 mp4 再拼接,参数一致时可以直接流拷贝:

ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4
# 需要软过渡时改用 xfade
ffmpeg -i seg01.mp4 -i seg02.mp4 -filter_complex 'xfade=transition=fade:duration=0.2:offset=3.9' joined.mp4

拼完逐帧检查三件事:重叠帧是否被重复播放、动作方向是否接得上、两段整体亮度和色调是否一致。分段意味着模型看不到全局信息,长程一致性本来就是短板,所以宁可每段短一些、重叠多一些,也不要指望拼接结果和一次生成长片完全一致。

写出一条选卡判断线

选卡先不看型号,先看目标组合:在目标分辨率和目标帧数下连跑几次的峰值显存,再乘一个余量系数(例如 1.3~1.5,按你机器上框架和驱动的实际开销定),这个值才是容量底线。峰值占用贴着整卡容量跑的配置,只能算调试档。

  • 只够调试:在 256~320 档、十几帧的规模能跑通,但一上 512 档或三十几帧就 OOM。这张卡的价值是验证流程、调提示词、比较不同 seed 的构图,不适合连续出片。
  • 能连续出片:目标分辨率与帧数下峰值显存和卡容量之间还有余量,连续多次运行不 OOM,且单次耗时符合你的出片节奏。这里没有通用的秒数标准,只能用自己的基线读数去比。

降精度换显存要算清代价:fp16 换 bf16 显存变化通常不大,主要影响数值稳定性;int8、fp8 一类量化能省显存,但画质和速度是否可接受,要用同一 seed、同一提示词对比输出后再决定。`--cpu-offload`、顺序 VAE 解码这些做法是把显存压力转移到主机内存或分片计算上,省显存的同时拖慢单次耗时,是让任务跑得起来的折中,不是提速方案。最终判断线落在一条上:目标分辨率与帧数下,这台机器能不能连续跑完你要出的那几条片子。