记录一个解决onnx转ncnn时op不支持的trick,最近准备整理一下使用TNN、MNN和NCNN的系列笔记,好记性不如烂笔头(记性也不好),方便自己以后踩坑的时候爬的利索点~
这里 ,目前70多C++推理例子,能编个lib来用,感兴趣的同学可以看看,就不多介绍了
【Lite.AI.ToolKit : A lite C++ toolkit of awesome AI models】— https://github.com/DefTruth/lite.ai.toolkit
首先说明一下,选择什么样的推理引擎完全是个人喜好,所以这篇短文仅记录技术问题。今天,想捏一下SCRFD的C++推理,我的习惯通常是同时捏多个版本,比如MNN、NCNN、TNN和ONNXRuntime。今天在将onnx转ncnn的时候遇到无法转换的问题。这里仅简单记录一下,一个取巧的方式。如果你确实希望得到一个ncnn的模型文件,并不在乎是什么方式,那么在你遇到奇怪的op无法转换时,可以尝试下文的方式。
遇到不支持的op
onnx模型文件来源于https://github.com/ppogg/onnx-scrfd-flaskgithub.com/ppogg/onnx-scrfd-flask
嗯,刚开始,我转换时,遇到的问题长这样:
这?!这一大堆不就是传说中的胶水op?基操onnxsim先过一遍。
再来转ncnn看看?
还是失败了,所以这一堆胶水op要准备造反了??那咋办????
当然,这时还可以考虑参考大佬的文章来手捏param
【nihui:手工优化ncnn模型结构】— https://zhuanlan.zhihu.com/p/93017149
但,问题来了,手工优化ncnn模型结构,这时会遇到两个比较主要的问题:
- 明显,看这个error,不支持的op在辣么多的位置出现了,手捏的难度太大了,放弃
- 手捏本身,需要你对ncnn的op十分熟悉,并同时对模型本身的结构十分熟悉,放弃
但是,如果你确实希望得到一个ncnn的模型文件,并不在乎是什么方式,那么在你遇到奇怪的op无法转换时,可以另一个(取巧)的方式。
另一种取巧的方式
这个方式,就是利用TNN。是的,你没听错,就是利用TNN作为中间商\。你的目的是得到一个能用的ncnn文件,所以,不用管是什么方式。经常用TNN的同学一定清楚,ONNX转TNN的模型的时候,可以指定一个 --optimize 参数。指定这个参数后,TNN会对输入的原始onnx文件,先做一个优化,会包含一些胶水op的去除和合并,感觉是和onnxsim做类似的事情,但似乎针对推理引擎本身进行了优化,一些在onnxsim之后依然被保留的胶水op,会被TNN的optimize阶段进行合并或去除,然后得到一个 xxx.opt.onnx 的中间文件。TNN会继续通过这个优化后的onnx文件生成最终的tnn模型文件。
生成的文件包括:
讲到这里,大家应该想得到,我说的trick是什么了。没错,就是利用这里的 xxx.opt.onnx 去转换ncnn模型。这真是个野路子啊。我们来看看结果如何吧。来转换ncnn试一下
舒服~ 都转换成功了,看来TNN的 --optimze 比 onnxsim 会更有针对性一些。我们来用ncnnoptimize过一遍,看看有没有问题。
是的,也很顺利。那么,看到这里,自然而然地,大家就会剩下最后一个疑问了。为了用这种方式,不还得编译个TNN,不也很麻烦?emmmm,其实,不用编译TNN哦。TNN官方提供了tnn_converter的镜像哦,如果你只是为了转换模型,获得中间的 xxx.opt.onnx,而不需要用TNN做推理。那么直接用 tnn_converter的镜像就完事了,不需要编译TNN库。搭建tnn_converter 参考原作者