野路子:记录一个解决onnx转ncnn时op不支持的trick

2022 年 1 月 19 日 极市平台
↑ 点击 蓝字  关注极市平台

作者 | DefTruth@知乎(已授权) 
来源 | https://zhuanlan.zhihu.com/p/451446147 
编辑 | 极市平台
本文已获得作者授权,转载请联系原作

极市导读

 

最近准备整理一下使用TNN、MNN和NCNN的系列笔记,好记性不如烂笔头(记性也不好),方便自己以后踩坑的时候爬的利索点~ >>加入极市CV技术交流群,走在计算机视觉的最前沿

这里 ,目前70多C++推理例子,能编个lib来用,感兴趣的同学可以看看,就不多介绍了

【Lite.AI.ToolKit : A lite C++ toolkit of awesome AI models】— https://github.com/DefTruth/lite.ai.toolkit 最近会陆续更新一些文章,欢迎关注 ~

1. 前言

首先说明一下,选择什么样的推理引擎完全是个人喜好,所以这篇短文仅记录技术问题。今天,想捏一下SCRFD的C++推理,我的习惯通常是同时捏多个版本,比如MNN、NCNN、TNN和ONNXRuntime。今天在将onnx转ncnn的时候遇到无法转换的问题。这里仅简单记录一下,一个取巧的方式。如果你确实希望得到一个ncnn的模型文件,并不在乎是什么方式,那么在你遇到奇怪的op无法转换时,可以尝试下文的方式。

2. 遇到不支持的op

onnx模型文件来源于https://github.com/ppogg/onnx-scrfd-flaskgithub.com/ppogg/onnx-scrfd-flask

嗯,刚开始,我转换时,遇到的问题长这样:

➜ onnx2ncnn SCRFD/scrfd_1g.onnx SCRFD/scrfd_1g.param SCRFD/scrfd_1g.bin
Shape not supported yet!
Gather not supported yet!
  # axis=0
Shape not supported yet!
Gather not supported yet!
  # axis=0
Unsupported unsqueeze axes !
Unsupported unsqueeze axes !
Shape not supported yet!
Unknown data type 0
Unsupported Resize scales and sizes are all empty!
Shape not supported yet!
Gather not supported yet!
  # axis=0
Shape not supported yet!
Gather not supported yet!
  # axis=0
Unsupported unsqueeze axes !
...

这?!这一大堆不就是传说中的胶水op?基操onnxsim先过一遍。

➜ python3 -m onnxsim scrfd_1g.onnx scrfd_1g-sim.onnx --dynamic-input-shape --input-shape 1,3,320,320
Simplifying...
Checking 0/3...
Checking 1/3...
Checking 2/3...
Ok!

再来转ncnn看看?

➜ onnx2ncnn SCRFD/scrfd_1g-sim.onnx SCRFD/scrfd_1g.param SCRFD/scrfd_1g.bin
Shape not supported yet!
Gather not supported yet!
  # axis=0
Shape not supported yet!
Gather not supported yet!
  # axis=0
Unsupported unsqueeze axes !
Unsupported unsqueeze axes !
Shape not supported yet!
Unknown data type 0
Unsupported Resize scales and sizes are all empty!
Shape not supported yet!
Gather not supported yet!
  # axis=0
Shape not supported yet!
Gather not supported yet!
  # axis=0

还是失败了,所以这一堆胶水op要准备造反了??那咋办????

当然,这时还可以考虑参考大佬的文章来手捏param

【nihui:手工优化ncnn模型结构】— https://zhuanlan.zhihu.com/p/93017149

但,问题来了,手工优化ncnn模型结构,这时会遇到两个比较主要的问题:

  • 明显,看这个error,不支持的op在辣么多的位置出现了,手捏的难度太大了,放弃
  • 手捏本身,需要你对ncnn的op十分熟悉,并同时对模型本身的结构十分熟悉,放弃

但是,如果你确实希望得到一个ncnn的模型文件,并不在乎是什么方式,那么在你遇到奇怪的op无法转换时,可以另一个(取巧)的方式。

3. 另一种取巧的方式

这个方式,就是利用TNN。是的,你没听错,就是利用TNN作为中间商\。你的目的是得到一个能用的ncnn文件,所以,不用管是什么方式。经常用TNN的同学一定清楚,ONNX转TNN的模型的时候,可以指定一个 --optimize 参数。指定这个参数后,TNN会对输入的原始onnx文件,先做一个优化,会包含一些胶水op的去除和合并,感觉是和onnxsim做类似的事情,但似乎针对推理引擎本身进行了优化,一些在onnxsim之后依然被保留的胶水op,会被TNN的optimize阶段进行合并或去除,然后得到一个 xxx.opt.onnx 的中间文件。TNN会继续通过这个优化后的onnx文件生成最终的tnn模型文件。

/opt/TNN/tools/convert2tnn# python3 ./converter.py onnx2tnn ./tnn_models/SCRFD/scrfd_1g.onnx -o ./tnn_models/SCRFD/ -optimize -v v1.0 -align -in 1,3,320,320
----------  convert model, please wait a moment ----------
Converter ONNX to TNN Model...
Converter ONNX to TNN check_onnx_dim...
Converter ONNX to TNN check_onnx_dim...
Converter ONNX to TNN model succeed!
----------  align model (tflite or ONNX vs TNN),please wait a moment ----------
input.1: input shape of onnx and tnn is aligned!
Run tnn model_check...
----------  Congratulations!   ----------
The onnx model is aligned with tnn model

生成的文件包括:

/opt/TNN/tools/convert2tnn/tnn_models/SCRFD# ls | grep opt
scrfd_1g.opt.onnx
scrfd_1g.opt.tnnmodel
scrfd_1g.opt.tnnproto
scrfd_2.5g.opt.onnx
scrfd_2.5g.opt.tnnmodel
scrfd_2.5g.opt.tnnproto
scrfd_2.5g_bnkps_shape160x160.opt.onnx
scrfd_2.5g_bnkps_shape160x160.opt.tnnmodel
scrfd_2.5g_bnkps_shape160x160.opt.tnnproto
scrfd_2.5g_bnkps_shape320x320.opt.onnx
scrfd_2.5g_bnkps_shape320x320.opt.tnnmodel
scrfd_2.5g_bnkps_shape320x320.opt.tnnproto
scrfd_500m.opt.onnx
scrfd_500m.opt.tnnmodel
scrfd_500m.opt.tnnproto
scrfd_500m_bnkps_shape160x160.opt.onnx
scrfd_500m_bnkps_shape160x160.opt.tnnmodel
scrfd_500m_bnkps_shape160x160.opt.tnnproto
scrfd_500m_bnkps_shape320x320.opt.onnx
scrfd_500m_bnkps_shape320x320.opt.tnnmodel
scrfd_500m_bnkps_shape320x320.opt.tnnproto

讲到这里,大家应该想得到,我说的trick是什么了。没错,就是利用这里的 xxx.opt.onnx 去转换ncnn模型。这真是个野路子啊。我们来看看结果如何吧。来转换ncnn试一下

➜  onnx2ncnn SCRFD/scrfd_1g.opt.onnx SCRFD/scrfd_1g.param SCRFD/scrfd_1g.bin
➜  onnx2ncnn SCRFD/scrfd_2.5g.opt.onnx SCRFD/scrfd_2.5g.param SCRFD/scrfd_2.5g.bin
➜  onnx2ncnn SCRFD/scrfd_2.5g_bnkps_shape160x160.opt.onnx SCRFD/scrfd_2.5g_bnkps_shape160x160.param SCRFD/scrfd_2.5g_bnkps_shape160x160.bin
➜  onnx2ncnn SCRFD/scrfd_2.5g_bnkps_shape320x320.opt.onnx SCRFD/scrfd_2.5g_bnkps_shape320x320.param SCRFD/scrfd_2.5g_bnkps_shape320x320.bin
➜  onnx2ncnn SCRFD/scrfd_500m.opt.onnx SCRFD/scrfd_500m.param SCRFD/scrfd_500m.bin
➜  onnx2ncnn SCRFD/scrfd_500m_bnkps_shape160x160.opt.onnx SCRFD/scrfd_500m_bnkps_shape160x160.param SCRFD/scrfd_500m_bnkps_shape160x160.bin
➜  onnx2ncnn SCRFD/scrfd_500m_bnkps_shape320x320.opt.onnx SCRFD/scrfd_500m_bnkps_shape320x320.param SCRFD/scrfd_500m_bnkps_shape320x320.bin

舒服~ 都转换成功了,看来TNN的 --optimze 比 onnxsim 会更有针对性一些。我们来用ncnnoptimize过一遍,看看有没有问题。

➜  ncnnoptimize SCRFD/scrfd_1g.param SCRFD/scrfd_1g.bin SCRFD/scrfd_1g.opt.param SCRFD/scrfd_1g.opt.bin 0
fuse_convolution_activation Conv_0 Relu_1
fuse_convolution_activation Conv_4 Relu_5
fuse_convolution_activation Conv_8 Relu_9
fuse_convolution_activation Conv_12 Relu_13
fuse_convolution_activation Conv_16 Relu_17
fuse_convolution_activation Conv_20 Relu_21
fuse_convolution_activation Conv_24 Relu_25
fuse_convolution_activation Conv_28 Relu_29
fuse_convolution_activation Conv_32 Relu_33
fuse_convolution_activation Conv_36 Relu_37
fuse_convolution_activation Conv_40 Relu_41
fuse_convolution_activation Conv_44 Relu_45
fuse_convolution_activation Conv_48 Relu_49
fuse_convolutiondepthwise_activation Conv_2 Relu_3
fuse_convolutiondepthwise_activation Conv_6 Relu_7
fuse_convolutiondepthwise_activation Conv_10 Relu_11
fuse_convolutiondepthwise_activation Conv_14 Relu_15
fuse_convolutiondepthwise_activation Conv_18 Relu_19
fuse_convolutiondepthwise_activation Conv_22 Relu_23
fuse_convolutiondepthwise_activation Conv_26 Relu_27
fuse_convolutiondepthwise_activation Conv_30 Relu_31
fuse_convolutiondepthwise_activation Conv_34 Relu_35
fuse_convolutiondepthwise_activation Conv_38 Relu_39
fuse_convolutiondepthwise_activation Conv_42 Relu_43
fuse_convolutiondepthwise_activation Conv_46 Relu_47
Input layer input.1 without shape info, shape_inference skipped
Input layer input.1 without shape info, estimate_memory_footprint skipped

是的,也很顺利。那么,看到这里,自然而然地,大家就会剩下最后一个疑问了。为了用这种方式,不还得编译个TNN,不也很麻烦?emmmm,其实,不用编译TNN哦。TNN官方提供了tnn_converter的镜像哦,如果你只是为了转换模型,获得中间的 xxx.opt.onnx,而不需要用TNN做推理。那么直接用 tnn_converter的镜像就完事了,不需要编译TNN库。搭建tnn_converter,可以参考我的文章:

【DefTruth:tnn-convert搭建简记-YOLOP转TNN】— https://zhuanlan.zhihu.com/p/431418709

码字不易,持续更新,欢迎点赞关注~

如果觉得有用,就请分享到朋友圈吧!

△点击卡片关注极市平台,获取 最新CV干货

公众号后台回复“transformer”获取最新Transformer综述论文下载~


极市干货
课程/比赛: 珠港澳人工智能算法大赛 保姆级零基础人工智能教程
算法trick 目标检测比赛中的tricks集锦 从39个kaggle竞赛中总结出来的图像分割的Tips和Tricks
技术综述: 一文弄懂各种loss function 工业图像异常检测最新研究总结(2019-2020)


CV技术社群邀请函 #

△长按添加极市小助手
添加极市小助手微信(ID : cvmart4)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)


即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群


每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~


觉得有用麻烦给个在看啦~   
登录查看更多
12

相关内容

跨框架的模型中间表达框架
CVPR2022 | 一种适用于密集场景的渐进式端到端目标检测器
卷积神经网络压缩中的知识蒸馏技术综述
专知会员服务
54+阅读 · 2021年10月23日
【UAI2021教程】贝叶斯最优学习,65页ppt
专知会员服务
64+阅读 · 2021年8月7日
Transformer模型-深度学习自然语言处理,17页ppt
专知会员服务
103+阅读 · 2020年8月30日
CVPR2020 | 商汤-港中文等提出PV-RCNN:3D目标检测新网络
专知会员服务
43+阅读 · 2020年4月17日
一网打尽!100+深度学习模型TensorFlow与Pytorch代码实现集合
开源书:PyTorch深度学习起步
专知会员服务
50+阅读 · 2019年10月11日
实操教程|Pytorch转ONNX详解
极市平台
3+阅读 · 2022年4月4日
ONNXRUNTIME C++ 版本推理部署踩坑记录
极市平台
2+阅读 · 2022年3月29日
实例:手写 CUDA 算子,让 Pytorch 提速 20 倍
极市平台
4+阅读 · 2022年3月8日
CVPR2021 | 记录SCRFD人脸检测C++工程化(含docker镜像)
极市平台
5+阅读 · 2022年1月16日
Tensorrt踩坑日记 | python、pytorch 转 onnx 推理加速
极市平台
15+阅读 · 2021年12月24日
「逃离」ONNX
机器之心
2+阅读 · 2021年12月10日
Pytorch 数据流中常见Trick总结
极市平台
0+阅读 · 2021年12月7日
实践教程|YOLOP ONNXRuntime C++工程化记录
极市平台
5+阅读 · 2021年11月8日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
3+阅读 · 2013年12月31日
国家自然科学基金
1+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
2+阅读 · 2008年12月31日
国家自然科学基金
0+阅读 · 2008年12月31日
Arxiv
0+阅读 · 2022年4月19日
Arxiv
0+阅读 · 2022年4月15日
VIP会员
相关VIP内容
CVPR2022 | 一种适用于密集场景的渐进式端到端目标检测器
卷积神经网络压缩中的知识蒸馏技术综述
专知会员服务
54+阅读 · 2021年10月23日
【UAI2021教程】贝叶斯最优学习,65页ppt
专知会员服务
64+阅读 · 2021年8月7日
Transformer模型-深度学习自然语言处理,17页ppt
专知会员服务
103+阅读 · 2020年8月30日
CVPR2020 | 商汤-港中文等提出PV-RCNN:3D目标检测新网络
专知会员服务
43+阅读 · 2020年4月17日
一网打尽!100+深度学习模型TensorFlow与Pytorch代码实现集合
开源书:PyTorch深度学习起步
专知会员服务
50+阅读 · 2019年10月11日
相关资讯
实操教程|Pytorch转ONNX详解
极市平台
3+阅读 · 2022年4月4日
ONNXRUNTIME C++ 版本推理部署踩坑记录
极市平台
2+阅读 · 2022年3月29日
实例:手写 CUDA 算子,让 Pytorch 提速 20 倍
极市平台
4+阅读 · 2022年3月8日
CVPR2021 | 记录SCRFD人脸检测C++工程化(含docker镜像)
极市平台
5+阅读 · 2022年1月16日
Tensorrt踩坑日记 | python、pytorch 转 onnx 推理加速
极市平台
15+阅读 · 2021年12月24日
「逃离」ONNX
机器之心
2+阅读 · 2021年12月10日
Pytorch 数据流中常见Trick总结
极市平台
0+阅读 · 2021年12月7日
实践教程|YOLOP ONNXRuntime C++工程化记录
极市平台
5+阅读 · 2021年11月8日
相关基金
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
3+阅读 · 2013年12月31日
国家自然科学基金
1+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
2+阅读 · 2008年12月31日
国家自然科学基金
0+阅读 · 2008年12月31日
Top
微信扫码咨询专知VIP会员