边缘部署的第一步,为什么卡在推理引擎选型
这几年边缘 AI 的需求增长很快,从手机端的图像分类到工业设备上的缺陷检测,很多团队开始把训练好的模型塞进小型设备里。但真正做起来会发现,真正麻烦的不在训练,而在部署:模型格式怎么转、算子到目标平台上能不能跑、量化和多线程怎么调,每一步都容易翻车。

在边缘设备上做推理,TensorFlow Lite、ONNX Runtime 和 NCNN 是被提到最多的三个选项。它们覆盖了不同的生态位,也各自有“总觉得能行但实际没那么简单”的地方。本文会结合具体的工程选型问题,把三者的差异和适用边界讲清楚。
先理清三者的定位,避免选型从一开始就跑偏
很多团队的选型误区,是不看自己的模型来源和设备范围,就凭“谁快选谁”的直觉下决定。实际上,这几个推理引擎的起源决定了它们的强项。
TensorFlow Lite 是 Google 从 TensorFlow 生态里衍生出来的移动端推理方案,设计目标很明确:让 TF 模型能在手机、嵌入式设备上高效运行。它最完善的路径是 TF -> TFLite,虽然现在也可以从 PyTorch 出发,但经过 ONNX 中转后,总会遇到一些算子映射上的问题。
ONNX Runtime 是微软开源的跨平台推理引擎,底层支持 ONNX 这个开放模型格式,天然适合多框架协作的场景。它的覆盖范围很广,从服务端 CPU/GPU 到移动端都有对应版本,而且有 execution provider 这套抽象,可以接入 TensorRT、OpenVINO 等专用加速库。
NCNN 是腾讯开源的移动端高性能推理框架,没有绑定任何训练框架格式,而是用自己的模型格式来定义网络结构。它的卖点是极致的轻量级和低层优化,在 Android 和 iOS 上有很多落地项目。
一个简单的判断方式:如果模型几乎都来自 TensorFlow,且只做移动端,TFLite 是省心路径;如果模型可能来自 PyTorch,或者需要在服务端和边缘端复用同一套推理逻辑,ONNX Runtime 更合适;如果包体积和极致性能是硬指标,且你愿意投入精力做算子适配,NCNN 值得认真评估。
核心维度对比:格式、算子、性能和维护成本
下面这张表可以快速看到三者在关键维度上的差异。需要注意,具体的性能数字依赖于模型和芯片,这里只给出相对趋势和工程判断。
| 对比维度 | TensorFlow Lite | ONNX Runtime | NCNN |
|---|---|---|---|
| 模型格式 | .tflite | .onnx | .param + .bin |
| 模型来源 | TensorFlow 全家桶最顺畅,其他需转换 | ONNX 生态,支持 PyTorch/TF 等导出的模型 | 支持 ONNX/PyTorch/TF(经转换) |
| 典型场景 | Android/iOS、MCU、TPU | 服务端 CPU/GPU、Windows/Linux、移动端 | Android/iOS、嵌入式 Linux |
| 量化能力 | int8/float16,工具链成熟 | int8/float16,但量化流程需额外配置 | int8/fp16,支持混合精度 |
| 硬件加速 | NNAPI、GPU Delegate、CoreML | CPU/GPU、TensorRT、OpenVINO、NNAPI | Vulkan、ARM CPU、部分 NPU |
| 依赖体积 | 相对小,有裁剪能力 | 移动端版本中等,服务端版本较大 | 非常小,便于打包 |
| 算子覆盖 | 以 CNN 为主,Transformer 支持逐年增强,但仍有残缺 | 算子覆盖最完整,社区扩展活跃 | 常规算子完整,自定义算子需要手写 |
| 调试工具 | 官方工具链齐全,日志清晰 | 有性能分析和算子替换能力 | 相对简单,更依赖源码调试 |
这张表并不是说哪一个绝对更好,而是提醒你:选型需要先分清自己的约束条件。比如多人团队协作的项目,需要频繁修改模型结构,ONNX 生态的调试工具会省很多事;但如果是一个存储空间只有几十兆的设备,NCNN 的轻量特性可能是决定性的。
模型转换的工程陷阱:最容易在这里浪费整个迭代周期
三个引擎的转换流程看起来都是“导出 + 加载”,实际跑起来各种边界情况层出不穷。真正的工程经验是:不要等到最后才转模型,在模型选型阶段就应该用目标引擎试跑一次关键算子。
下面这段伪代码展示了一个从 PyTorch 导出到三个引擎的基本路径,看起来简单,但每一步都可能失败。
# 1. PyTorch 模型先转换为 ONNX 通用格式
import torch.onnx
torch.onnx.export(fake_model, dummy_input, "model.onnx", opset_version=17)
# 2. 从 ONNX 转为 TensorFlow/TFLite
# 使用 onnx2tf 或 onnx-tf 将 onnx 转为 pb/saved_model,再由 TFLiteConverter 转换
tflite_model = tf.lite.TFLiteConverter.from_saved_model("saved_model").convert()
# 3. 从 ONNX 转为 NCNN
# 使用官方工具链
# onnx2ncnn model.onnx model.param model.bin
这里最容易踩的坑有三个。第一是 opset 版本不匹配,PyTorch 导出的 ONNX 算子版本太新,NCNN 或 ONNX Runtime 不支持,导致转换失败或静默丢弃某层。第二是动态维度问题,如果你的模型输入尺寸不是完全固定,TFLite 和 NCNN 在某些格式下需要显式指定 shape,动态轴很容易被拒。第三是量化校准,int8 量化不是简单转个型就完事,需要准备一份有代表性的校准数据集,否则推理精度可能跌到不可用。
常见误区:这三个判断雷区一定要避开
误区一:TFLite 只能跑 TensorFlow 模型
现在通过 ONNX 中转,确实能把 PyTorch 模型转到 TFLite。但觉得“能转”就等于“能跑”,就太乐观了。不少 PyTorch 特有的操作,比如某些自定义的注意力实现,导出到 ONNX 后会变成不支持的结构,TFLite 的算子集不一定能覆盖。最后往往要修改模型实现,或者手写算子。
误区二:ONNX Runtime 是服务端专用,移动端不能碰
其实 ONNX Runtime 有专门为移动端裁剪的 Mobile 构建,也支持 Android/iOS。只不过它的体积和启动速度没有 NCNN 那种为手机“量身定制”的优化感。如果你需要一个跨平台推理方案,同时服务端和移动端都用同一套模型和 runtime 家族,ONNX Runtime 的版本一致性会让你好过很多。
误区三:NCNN 一定最快,闭眼选就行了
NCNN 对熟悉的卷积类模型确实优化得很深,但它的出发点是手机 CPU 和 Vulkan GPU。如果你遇到的模型里有大量动态 shape、频繁 reshape,或者需要在特定 NPU 上跑,NCNN 可能需要额外的手工适配,性能不一定比官方 TFLite 的 NPU delegate 好。性能要按目标设备实测,不能只信一句话。
按团队和场景选择,才是正确的打开方式
这里给出几类典型的团队画像,帮你对号入座。
- 纯移动端 App 团队:如果主要跑 Android,且模型大部分来自 TensorFlow,选 TFLite 最顺手;如果同时要 iOS 和 Android,且希望包体积更小,NCNN 更值得投入。
- 算法平台 / 模型复用团队:团队里有多个框架的模型,且需要统一部署流程,优先考虑 ONNX Runtime,它能抹平不同训练框架的差异。
- 嵌入式设备团队:如果只是做固定功能的图像识别,NCNN 的小体积和高性能很友好;但如果你需要稳定长期维护,TFLite 的官方支持和文档更完善。
另外需要特别注意,很多项目不是从一开始就要决定一个方向。可以在早期同时跑通 TFLite 和 ONNX Runtime 两个最小链路,用真实模型和真实设备对比之后再收敛。这个试错成本相对于后面返工来说,低很多。
落地部署时的几个实操建议
选型只是开始,真正决定项目成败的是后面这些细节。
- 先做“最小模型全链路测试”:不要一上来就转大模型,先用一个小网络把转换、加载、推理、后处理整个流程跑通,确认每个环节没有隐藏问题。
- 算子覆盖检查:在转换后手动打印网络结构,重点核对 pooling、resize、padding 等常见算子是否映射到了目标格式。不要迷信自动转换的成功提示。
- 精度验证:量化前后一定要用同一批真实输入做对比,统计最大误差和 mAP 等指标。不要只看单张效果。
- 性能基准:在最终目标设备上,分别用 CPU 单线程、多线程和硬件加速跑一遍,记录延迟和内存峰值。注意多线程调度可能引入非确定性,需要多次测试取中位数。
- 固定版本:转换工具和 runtime 必须用同一套版本,最好在 CI 里固化为环境。ONNX Runtime 的新版本对某些算子实现有变化,升级前必跑回归。
一个更深的思考:边缘 AI 部署的本质是“系统集成”
很多人把边缘部署看成“模型格式转换”,其实真正难的是系统集成。你把一个模型部署到设备上,还得处理前后处理、线程模型、内存生命周期、异常恢复、后台任务调度。推理引擎只负责中间那段计算,它的接口设计、线程控制和 buffer 管理方式会直接影响到整个应用的稳定性。
比如同样一个姿态检测模型,在 TFLite 中你可能会借助它的 GPU delegate 来提速,但 delegate 在复杂场景下的 buffer 生命周期和 CPU 不同步问题,是需要额外处理的。ONNX Runtime 则让你可以通过 execution provider 做精细化配置,但这也意味着你要理解更多底层机制。NCNN 的接口更灵活,但调用力大的同时坑也多。
选型过程中,除了跑通模型,最好用预期的输入频率、并发量和内存上限去压测整个应用,而不是只测一次推理延迟。很多团队都在这一步才意识到“推理引擎本身很快,但整体应用卡顿”根本不是引擎的锅,而是前后处理或资源释放写得太烂。
写在最后
TensorFlow Lite、ONNX Runtime 和 NCNN 没有真正的“最好”,只有“在约束下更适合”。如果我的团队要快速交付,我会先用 TFLite 和 ONNX Runtime 各做一个最小 demo,用目标设备实测后定方向。等模型和业务都稳定后,如果遇到性能瓶颈,再考虑 NCNN 这种低层优化方案也不迟。
边缘 AI 的工程复杂性往往不会比训练低,只是它的复杂度更后置。希望这篇文章能帮你建立起一套自己的选型判断框架,而不是被几篇性能 benchmark 带着走。
原创文章,作者:fudengji,如若转载,请注明出处:https://fudengji.cn/article/822/