2、推理框架概览:主流嵌入式推理框架对比与选型

做嵌入式AI这几年,我接触过的推理框架少说也有七八个。每个框架刚出来的时候都号称「最快」、「最轻量」,但实际用起来,坑是真不少。今天我就把几个主流框架掰开揉碎了聊聊,帮你选型时少走弯路。

2.1 为什么需要推理框架?

说白了,你训练好的模型是个「胖子」。PyTorch或者TensorFlow的模型动辄几百兆,里面还带着一堆训练用的算子。到了嵌入式设备上,内存就几百KB,算力也有限,根本跑不动。

推理框架干的事就三件:

  • 模型压缩:去掉训练相关的冗余信息,只保留推理需要的计算图
  • 算子优化:针对ARM、x86、RISC-V等不同架构,用汇编或者NEON指令重写关键算子
  • 内存管理:预分配内存池,避免运行时频繁malloc/free

嗯,这里要注意,不是所有框架都适合你的芯片。选错了,性能可能差10倍以上。

2.2 五大主流框架速览

框架 维护方 核心语言 典型场景 我的评价
TensorFlow Lite Google C++ Android、树莓派 生态最全,但性能一般
ONNX Runtime Microsoft C++ 跨平台、云端+端侧 兼容性最好,但体积偏大
NCNN 腾讯 C++ 手机端、ARM Linux 轻量、稳定,我项目里用得最多
MNN 阿里巴巴 C++ 手机端、IoT 性能激进,但文档略坑
Tengine OPEN AI LAB C 安防、工业、ARM Linux 国产之光,硬件适配好

2.3 逐个拆解:每个框架的脾气秉性

2.3.1 TensorFlow Lite

Google的亲儿子,生态确实没得说。你随便搜个模型,基本都有TFLite的转换脚本。我个人习惯用它做快速原型验证,因为从TF训练到TFLite部署,一条龙服务。

但说实话,性能方面它不算顶尖。我记得有一次在RK3399上跑MobileNetV2,TFLite的推理速度比NCNN慢了将近30%。原因很简单——TFLite的算子优化偏通用,没有针对特定芯片做极致调优。

避坑指南:我曾经在项目里直接用TFLite的默认量化,结果模型精度掉了5个点。后来发现是校准数据集没选对。TFLite的量化对数据分布很敏感,一定要用真实场景的数据做校准。

2.3.2 ONNX Runtime

微软搞的这个框架,最大的优势是「中间人」角色。你训练用PyTorch,部署用ONNX Runtime,中间只需要过一次ONNX格式。跨框架迁移非常丝滑。

不过,ONNX Runtime的体积是个问题。完整版动态库几十兆,对嵌入式设备来说太奢侈了。我建议只编译你需要的算子,能省掉一大半体积。

小技巧:用 onnxruntime::SessionOptions 设置 SetIntraOpNumThreadsSetInterOpNumThreads,可以精细控制多线程推理。我一般设成2线程,既能提速又不至于把CPU占满。

2.3.3 NCNN

腾讯开源的这个框架,是我个人最偏爱的。为什么?因为它「干净」。代码风格简洁,依赖极少,编译起来几乎不会报错。你想想看,在嵌入式环境里,能一次编译通过有多幸福。

NCNN对ARM架构的优化做得相当到位。它用了很多手写汇编,比如卷积的Winograd算法、深度可分离卷积的优化。我在海思3516上跑过YOLOv5s,NCNN比TFLite快了将近一倍。

// NCNN加载模型的典型代码
ncnn::Net net;
net.load_param("model.param");
net.load_model("model.bin");

ncnn::Mat in = ncnn::Mat::from_pixels(pixels, ncnn::Mat::PIXEL_BGR, 224, 224);
ncnn::Extractor ex = net.create_extractor();
ex.input("data", in);
ncnn::Mat out;
ex.extract("output", out);

嗯,这里要注意,NCNN的输入数据格式是NHWC,和很多训练框架的NCHW不一样。我第一次用的时候忘了转格式,结果推理结果全是错的。

2.3.4 MNN

阿里的MNN,性能上确实激进。它用了很多编译优化技术,比如算子融合、内存复用、计算图优化。在骁龙865上跑分类模型,MNN的延迟比NCNN还要低10%左右。

但MNN的文档嘛……说实话,有点跟不上代码的更新速度。我遇到过好几次,照着文档写代码,结果API已经变了。建议直接看源码里的示例,比文档靠谱。

避坑指南:MNN的量化工具对某些算子支持不完整。我曾经量化一个带PReLU的模型,结果推理时直接崩溃。后来换成ReLU才解决。如果你的模型里有特殊激活函数,建议先跑一遍量化后的测试。

2.3.5 Tengine

国产框架里,Tengine的硬件适配做得最好。它支持RK3399、RV1126、算能、地平线等国产芯片,而且针对每个平台都有专门的优化库。我在安防项目里用过Tengine,部署到海思3559上,几乎开箱即用。

Tengine的另一个亮点是支持动态形状输入。有些场景下输入图片尺寸不固定,其他框架需要重新创建session,Tengine可以直接复用。

// Tengine加载模型的示例
graph_t graph = create_graph(nullptr, "tengine", model_path);
tensor_t input_tensor = get_graph_input_tensor(graph, 0, 0);
set_tensor_shape(input_tensor, dims, 4);
prerun_graph(graph);
run_graph(graph, 1);

2.4 选型建议:到底该用哪个?

这个问题没有标准答案,但我可以给你一些实际经验:

  • 如果你在Android上做App:首选TFLite,系统自带支持,集成最简单
  • 如果你在ARM Linux上做产品:NCNN或Tengine,性能稳定,社区活跃
  • 如果你需要跨框架迁移:ONNX Runtime,兼容性最好
  • 如果你追求极致性能:MNN,但要做好踩坑的准备
  • 如果你用国产芯片:Tengine,硬件适配最省心

我的个人建议:不要迷信「最快」的框架。选型时考虑三个因素:

  1. 你的芯片架构(ARM v7/v8?RISC-V?)
  2. 你的模型算子(有没有特殊层?)
  3. 你的团队维护能力(遇到bug能自己修吗?)

我见过太多人为了追求那5%的性能提升,选了一个冷门框架,结果遇到bug没人管,项目延期。稳定大于一切。

2.5 小结

这一章我们聊了五个主流推理框架的特点和坑。说白了,没有完美的框架,只有最适合你项目的框架。下一章我会深入讲NCNN的模型转换和量化,这是嵌入式部署里最常踩坑的环节。

记住一句话:选框架就像选工具,顺手比锋利更重要