4、推理引擎选择:TFLite Micro、TensorRT、ONNX Runtime、NCNN、MNN的特点与选型对比

说到推理引擎选型,这其实是个老生常谈但又特别容易踩坑的话题。我见过不少团队,模型在PC上跑得飞快,一上嵌入式设备就崩了。说白了,选引擎就像选工具——没有最好的,只有最合适的。

今天咱们就把市面上主流的五个引擎掰开揉碎聊一聊。TFLite Micro、TensorRT、ONNX Runtime、NCNN、MNN,它们各自擅长什么?短板在哪?我结合自己踩过的坑,给你一份实在的选型指南。

4.1 五个引擎的定位与出身

先看一张总览表,心里有个底:

引擎 出身 主打场景 硬件支持 量化支持
TFLite Micro Google MCU、极低资源设备 ARM Cortex-M、RISC-V INT8量化为主
TensorRT NVIDIA GPU服务器、Jetson边缘 NVIDIA GPU FP16/INT8/INT4
ONNX Runtime Microsoft 跨平台、多框架互转 CPU/GPU/NPU 动态量化、静态量化
NCNN 腾讯 移动端CPU/GPU ARM、x86、Vulkan FP16/INT8
MNN 阿里巴巴 移动端、IoT设备 ARM、x86、OpenCL FP16/INT8/混合精度

核心观点:选引擎的第一步,先看你的目标硬件。GPU平台无脑TensorRT,MCU平台只有TFLite Micro可选,移动端则在NCNN和MNN之间二选一。

4.2 TFLite Micro——MCU上的唯一选择

如果你做的是Cortex-M系列或者RISC-V的嵌入式开发,那TFLite Micro几乎是唯一成熟的方案。我最早接触它是在一个智能传感器项目上,Flash只有256KB,RAM只有64KB。当时试过其他引擎,编译完就超了。

TFLite Micro的核心思路是「极致精简」。它去掉了所有运行时动态分配,所有内存都在编译期确定。这意味着什么?你不用担心内存碎片,也不用怕堆溢出。

但代价也很明显——算子支持非常有限。我记得有一次想跑一个MobileNetV3,结果发现hard-swish算子不支持,只能手动改模型结构。嗯,这里要注意,如果你模型里用了比较新的算子,最好先查一下支持列表。

我的建议:MCU上做推理,尽量用老牌经典网络。比如MobileNetV1、SqueezeNet这些,算子兼容性好。非要上Transformer?那得做好手写算子的准备。

4.3 TensorRT——GPU上的性能之王

TensorRT,说白了就是NVIDIA给自家GPU做的「特调引擎」。它能把模型压到极致,FP16推理速度比原生PyTorch快3-5倍是常有的事。

我印象最深的一个项目,是在Jetson Nano上跑YOLOv5。直接用PyTorch推理,帧率只有8FPS。换成TensorRT,做了INT8量化,直接飙到30FPS。为什么会这样?因为TensorRT做了三件事:层融合、内存复用、量化校准。

不过TensorRT有个大坑——它只认自家格式。你得先把模型转成ONNX,再用TensorRT的解析器转成TRT引擎。这个过程中,算子兼容性问题特别多。我曾经花了两天时间,就为了修一个Resize算子的对齐方式。

避坑指南:我曾经在转ONNX时,因为PyTorch版本和ONNX opset版本不匹配,导致导出的模型推理结果全是NaN。后来养成了习惯:每次转模型前,先跑一遍onnxruntime验证精度。

4.4 ONNX Runtime——跨框架的「翻译官」

ONNX Runtime的定位很特别。它不追求极致性能,而是追求「什么都能跑」。你想想看,PyTorch训练的模型、TensorFlow训练的模型、甚至Caffe2的模型,都能通过ONNX格式统一到Runtime上推理。

我个人习惯把ONNX Runtime当作「精度验证工具」。每次做模型转换,先用ONNX Runtime跑一遍,确认精度没问题,再转到目标引擎。这样能快速定位问题出在转换环节还是推理环节。

但说实话,ONNX Runtime在嵌入式设备上的表现一般。它的内存占用偏大,启动速度也慢。我试过在树莓派上跑,同样的模型,NCNN比ONNX Runtime快30%左右。

4.5 NCNN——移动端的「老牌劲旅」

NCNN是腾讯开源的,在移动端推理引擎里算是元老级的存在。它的优势在于ARM CPU优化做得特别好,尤其是ARMv8.2架构下的半精度指令支持。

我记得有一次优化一个人脸检测模型,在骁龙865上,NCNN的FP16推理速度比MNN快了15%。但换到麒麟990上,结果又反过来了。这说明什么?引擎的优化和具体硬件绑定很深,不能只看纸面数据。

NCNN的另一个特点是「轻量」。编译后的库文件只有几百KB,非常适合集成到APK里。不过它的GPU支持比较弱,Vulkan后端还在完善中。

4.6 MNN——后起之秀的「全能选手」

MNN是阿里巴巴开源的,虽然比NCNN晚,但发展很快。它的设计思路是「一次转换,到处运行」。MNN有自己的模型格式,转换工具支持TensorFlow、PyTorch、ONNX等多种来源。

我比较欣赏MNN的一点是它的混合精度支持。你可以在同一个模型里,部分层用FP16,部分层用INT8。这在一些精度敏感的场景下特别有用。比如检测模型的最后几层用FP16,前面的特征提取层用INT8,精度损失能控制在1%以内。

不过MNN的文档质量嘛...嗯,说实话,有点一言难尽。有些API的注释还是英文的,而且示例代码不够全。我当初上手时,全靠读源码才搞明白一些配置参数的含义。

4.7 选型对比:一张表说清楚

对比维度 TFLite Micro TensorRT ONNX Runtime NCNN MNN
最低RAM需求 ~10KB ~512MB ~100MB ~10MB ~10MB
算子数量 ~50个 ~200个 ~150个 ~120个 ~130个
量化工具链 完整 完整 一般 较完整 完整
社区活跃度
学习曲线 平缓 陡峭 平缓 中等 中等

选型口诀:MCU用TFLite Micro,GPU用TensorRT,跨平台验证用ONNX Runtime,移动端CPU优化选NCNN,需要混合精度或灵活部署选MNN。

4.8 我的实战建议

最后分享几个我自己的经验:

  • 不要迷信基准测试。网上那些跑分数据,很多是在特定硬件、特定模型下测的。你实际部署时,一定要在自己的目标板上跑一遍。
  • 量化是必选项。不管是INT8还是FP16,量化后推理速度能翻倍。我建议从FP16开始试,精度损失小,效果立竿见影。
  • 做好算子兼容性检查。我吃过这个亏。模型在PC上跑得好好的,转到嵌入式设备上,发现某个算子不支持,只能重新训练模型。提前查算子支持列表,能省很多时间。
  • 保留一个「安全网」。我的习惯是,每个模型都保留一份ONNX格式的副本。万一目标引擎出了问题,还能用ONNX Runtime快速验证。

好了,关于推理引擎的选型,今天就聊到这儿。下一章咱们会深入讲TFLite Micro的部署实战,包括模型转换、内存优化和性能调优。到时候我会拿一个实际项目来演示,敬请期待。