端侧跑 LingBot-Vision 这类带视觉编码器的模型,推理速度明显受设备内存带宽和算子执行效率影响。不同设备、不同推理框架下,耗时卡点的位置可能完全不一样。有的场景卡在图像预处理,有的在视觉编码器,还有的在自回归生成阶段。因此,优化速度的第一件事不是找框架或换量化,而是先做一次完整的耗时拆分,把“图像输入到预处理结束”“预处理到编码器结束”“编码器到第一个输出 token”“后续每个 token 的平均耗时”分别记下来。
端侧推理速度优化没有通用万能配置,优先确认当前卡点是预处理、视觉编码还是生成阶段;量化、降分辨率、限制最大 token 数和选择匹配设备特性的推理后端是常见有效动作,但每一项都要在目标设备上重新测量。建议先建立耗时拆分表和可重复对比的测试脚本,再逐项调整,避免凭感觉优化。
先建基线,再谈优化
测量是优化动作的前提,这一步不能省。建议准备一组固定输入:一张固定尺寸的图片、一个固定提示词、一个固定的最大输出 token 数。在该条件下分别记录预处理耗时、视觉编码耗时、生成耗时和总延迟。同时记录设备温度,因为端侧设备在长时间运行后会降频,导致测量漂移。
下面是一个在任意框架里都可以用的耗时打点思路,核心是在主流程的每个阶段前后记录时间戳:
start = now()
preprocess(image, prompt)
t1 = now()
vision_encoder(image_tensor)
t2 = now()
generate(prompt_tensor)
t3 = now()
print('preprocess:', t1 - start)
print('vision_encoder:', t2 - t1)
print('generate:', t3 - t2)
print('total:', t3 - start)
除了记录日志,还需要在固定输出长度下对比,避免因为生成长度不同而看不出真实瓶颈。记录 3-5 次并取中位数,不要只看一次结果。
模型和输入侧的调整选项
如果耗时拆分显示视觉编码阶段占大头,优先考虑降低输入分辨率或裁剪无需计算的模态分支;如果生成阶段长,限制最大输出 token 数会更直接。量化(8bit/4bit)可以降低权重和某些激活的内存读取量,但在端侧部分框架里,量化后速度提升取决于是否有对应的算子和设备支持,不能一概而论。量化后需要重新跑精度验证,至少确认关键场景输出没有明显退化。
- 降低输入分辨率:先试缩小到原输入的一半,观察延时变化和回答质量。
- 限制最大 token:如果是问答场景,设置 max_output_tokens 上限,避免尾部空转。
- 跳过不需要的输入源:如果模型支持音频、视频等多模态输入,当前只使用图像,就关闭其他模态的编码器。
- 减少视觉 token 数量:通过后端拼图或特征压缩减少视觉编码器输出 token 数,对生成阶段的注意力计算有帮助。
推理框架与算子执行选择
端侧可用的推理后端通常不止一个,很多设备厂商还提供专有的 NPU 或 GPU 加速方案。可以先用 ONNX Runtime、MNN、NCNN、TNN 这类通用框架分别做一次最小基准测试,再结合目标设备的硬件特性选型。但要注意:一个框架对模型里某些算子可能没有高效实现,自动切到 CPU fallback 后速度反而下降。因此不能只看框架名称,要看实际 profiling 时算子的执行时间。
如果模型结构中包含复杂注意力算子,优先选在目标设备上算子覆盖较好的框架。先把模型导出为标准格式,再用目标框架转换和验证输出一致性。如果某些算子性能很低,可以考虑重写为算子融合形式。
运行时策略与资源调度
模型权重和推理全过程都在同一台端侧设备上运行时,内存带宽会先成为瓶颈。建议把运行时的线程数固定在一个合理范围,不要把 CPU 核全部占满,否则系统调度可能反过来拖慢速度。如果框架支持 KV cache 复用,在连续多轮对话场景里预估好 cache 大小并提前分配,能减少重复创建内存对象的开销。首次推理前用一张固定输入做一次预热,触发算子初始化、内存分配和内核编译,避免把第一次调用的延迟计入正式体验。
优化后的回归验证
- 用同一组输入图片和同一段提示词,在修改前后分别记录三组耗时,取中位数对比。
- 跑一遍关键任务样例,确认输出质量没有因为量化或分辨率调整而明显变差。
- 在目标设备上连续运行一段时间,观察耗时是否有逐渐增大(可能和内存泄漏或缓存膨胀有关)。
- 切换不同后端时,比较视觉编码器和生成阶段各自的耗时,不只看端到端数字。
常见问题
量化后看起来没有明显提速,问题出在哪里?
量化主要减少权重读入的内存消耗,但如果计算瓶颈在注意力矩阵乘法或内存带宽,量化收益会受限。需要先用耗时拆分确认瓶颈在哪个阶段,只量化某一层或更换推理框架可能更快。
同一个模型在不同端侧设备上速度差异很大,正常吗?
端侧设备的 CPU 核心数、是否支持 NPU、内存带宽、系统调度策略都会影响真实速度。同一套参数很难在不同设备上都达到最优,建议至少为高、中、低三档设备分别做一次基准测试和参数调整。