Audio-Visual Flamingo 这类模型,推理速度的瓶颈往往不在模型本身,而在调用方式。输入视频帧率、音频采样率、输出文本长度、采样/beam设定,都会直接影响单次请求耗时;并且这些参数通常可以在服务端做限制,不必每次找算法改权重。下面从这几个层面给出可操作的排查和调整方法。
一、输入规模:帧率和音频时长影响计算量
视觉编码器和音频编码器会把输入转化为序列令牌。视频帧率越高、抽帧越多,视觉令牌越多,交叉注意力层需要处理的键值对就越多。音频同理,采样率或音频时长决定音频令牌数量。以一个10秒视频为例,2fps抽帧是20帧,4fps就是40帧,视觉序列接近翻倍,注意力计算量也会跟着上涨。
适用场景:本地或服务端想降低单次推理延迟。操作:把输入预处理中的 video_fps 限制在1-2,音频用 16kHz 采样,并设置 max_frames 和 max_audio_seconds 截断。验证方式:在相同GPU/CPU上,用1fps与4fps分别跑同一段视频,记录时间差。风险边界:过度抽帧会丢失关键动作和语音细节,导致问答质量下降;建议只对短上下文任务做强制截断。
二、生成参数:解码策略和输出长度是关键
解码策略对总耗时的贡献常常被低估。beam search 开启后,模型每轮生成同时维护多个候选序列,剪枝和排序开销明显高于贪心解码;max_new_tokens 设得过大也会让自回归阶段反复计算。对多模态问答这类任务,通常可以从贪心解码和 max_new_tokens=64 开始试,确认效果后再按需放宽。
操作动作:先在调用接口时,把 do_sample 设为 false、num_beams 设为 1、early_stopping 设为 true。如果是内部封装的服务,检查生成配置是否允许外部覆盖。验证方式:用同一输入提示词,分别以 beams=1 和 beams=5 跑一次,观察总耗时和输出差异。风险边界:贪心解码对需要多样性的提示词会显得呆板;需要平衡质量和延迟时,建议设置 temperature=0.7 并限制 max_new_tokens。
三、缓存与批处理:不是所有省算力的选项都无损
KV Cache 配置是另一个常见瓶颈。多模态输入的视觉和音频特征会被拼接进语言模型的键值历史;如果推理框架没有正确启用 KV Cache,或每轮对话都重新编码整个媒体输入,速度会明显退化。另外,并发时盲目加大 batch,反而会因显存带宽饱和拖慢单次响应。
适用场景:服务端已确定单条请求的输入上限,但仍觉得吞吐不行。操作:确认推理框架中 use_cache=True(或等价开关),并记录请求队列长度与 GPU 利用率;如果显存紧张,降低 batch_size。验证方式:用一个固定输入并发跑2-4个请求,观察是否出现超时或显存不足。风险边界:KV Cache 会额外占用显存,长上下文场景需要计算最大长度;batch 加大到一定阈值后,平均耗时可能不再下降,需要结合压测调参。
四、快速定位慢点的检查清单和代码骨架
下面的配置可以作为服务端默认参数起点;代码片段是通用的耗时测量骨架,可以套用到你的推理封装里。
config = {
'video': {'fps': 2, 'max_frames': 16, 'resize': 224},
'audio': {'sample_rate': 16000, 'max_seconds': 10},
'generation': {'max_new_tokens': 64, 'do_sample': False, 'num_beams': 1, 'use_cache': True},
'runtime': {'batch_size': 1, 'precision': 'fp16'}
}
把上面配置作为服务端的默认值,再按实际输入场景覆盖。每个字段都对应一个可测变量。
import time
def time_single_inference(predict_fn, inputs, warmup=1, repeat=3):
# warmup 让 CUDA 图、内存池先就位
for _ in range(warmup):
predict_fn(inputs)
costs = []
for _ in range(repeat):
start = time.perf_counter()
predict_fn(inputs)
costs.append(time.perf_counter() - start)
costs.sort()
return costs[len(costs) // 2]
# 对比不同 fps 的影响
for fps in [1, 2, 4]:
inputs = preprocess(video_path, fps=fps, max_audio_seconds=8)
tokens = len(inputs['input_ids'])
print('fps={}, media_tokens={}'.format(fps, tokens))
print(time_single_inference(model.generate, inputs))
如果 predict_fn 内部使用 CUDA,计时前先调用一下 torch.cuda.synchronize(),否则拿到的是排入队列的时间,不是实际计算时间。
验证清单:
- 先记录单次请求耗时和显存占用,再改动任一配置;
- 每次只改一个变量,避免把多个影响混在一起;
- 优先检查输入长度是否过长,再检查生成参数;
- 显存充足但耗时长,优先看 beam search 和 max_new_tokens;
- 并发后单条请求明显变慢,优先降低 batch 或限制输入长度。
AVF 变慢通常不是单一原因。把输入长度、生成参数、缓存状态分开测量,能更快定位到可调整的环节。上述配置和代码可以直接用于实验;结果需要结合你的视频内容和后端框架确认,不要照搬默认值。