因为我一直都是在pytorch上面训练模型,所以部署模型通常采取三种方案:
- 方案一:利用腾讯开源的ncnn库(nihui大神牛皮!!);但这个适合移动端部署,特别是针对andriod的极致优化。
- 方案二:libtorch(c++版本的pytorch);pytorch为了弥补部署方面的劣势,,libtorch也在不断推陈出新,以不断打压tf等一众老炮生存空间
- 方案三:NVIDIA出品的tensorRT;这个是专门为nvidia的显卡作推断而生,所以如果是要用gpu做infer,那么tensorRT将会是一个好的选择
如果是针对ncnn和tensorRT,那么一般的方案是将pytorch生成的.pth模型先转换成.onnx模型,然后利用onnx的万能属性往不同的框架上移植。
将会分三个系列来记录一下如何使用者三种方式来部署pytorch的模型,(其实主要是工具安装和基本使用),特别是安装的坑实在是巨多(教程质量是在是令人唏嘘,而且抄袭严重。。),记录一下以免过后忘记。本篇首先记录下ncnn的安装和基本使用!
网上看了很多ncnn的教程,感觉好多都回避了重要步骤,导致你我这样的新手ncnn编译失败,(包括ncnn的官方文档也只是对protbuf提了一句,并未强调这就导致很多不细心的网友看飘).我的系统是ubuntu16,所以按照ncnn官方的build-for-linux-x86的指导来操作.
编译ncnn的准备工作:g++, cmake,protobuf,opencv,
前两个不必说,很容易。其中安装protobuf和opencv都可以分别写一篇博客了。
关于opencv的安装:不仅是对于ncnn,无论是对于哪种部署方式,opencv都是必须的。所以一定要提前装好。网上教程蛮多,这里推荐一篇还不错的
ubuntu16.04安装opencv3.4.1教程_人工智能_cocoaqin的博客-CSDN博客blog.csdn.net![917a6666c69bdda61c3bce9168b397a6.png](https://i-blog.csdnimg.cn/blog_migrate/7df082ac403cfd70e55024eb36107f76.png)
注意两点:
- 如果电脑里面已经装过anoconda,那么编译opencv的过程很可能会出现问题,需要在cmake的时候指定一些选项(遇到错误了百度or谷歌可解决)。
- 关于版本的问题 2.x/3.x/4/x,这个我一般选择3.x,如果选得不合适可能会导致ncnn调不动。。
关于protobuf的安装:这个需要强调说明,这个直接决定了ncnn编译的成功与否,网上大部分失败的貌似都是protobuf没有装成功。但是解决办法千奇百怪的,像神马在CMakeList里面注释掉add onnx、caffe神马的,这个指标不治本啊,显然是不行的。
protobuf的github仓库:
https://github.com/protocolbuffers/protobuf/tree/master/srcgithub.com可以按照上面链接的指导进行安装:关键步骤标识如下:
![6bb41d0ca46984850c8e13c886de2036.png](https://i-blog.csdnimg.cn/blog_migrate/3183cf3e72a2682ee4db70e4149acfa0.jpeg)
如果protobuf安装成功后,编译ncnn还是报错,那可以试试重启,还不行,重新编译安装protobuf再重启。(一切的问题基本都可以在ncnn仓库的issue区找到答案,学会利用issue区是一项重要的能力)。
ncnn的github开源仓库:
https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-linux-x86github.com正式编译ncnn:
![70aa168260c9844a9ec173efb40fed43.png](https://i-blog.csdnimg.cn/blog_migrate/8745f2005d40e2aed36161e22124c7a5.jpeg)
对于官方给的编译步骤来说,cmake那里可以指定的选项:vulkan是针对gpu的,如果想要ncnn能调用gpu做推理,那么选项需要打开。
完事了记得在./build下面make install一下。完了会生成include和lib,后面利用ncnn调用自己模型时需要链接到这里。
关于x.pth转onnx:嗯。。。这个不多说,很复杂,坑巨多,自求多福,如果在pytorch里面直接定义了很多骚操作,那么多半转onnx要凉,唯一的办法就是绕开某些操作。这个话题不是本篇重点,跳过。说一点就是:输入和输出一定要命名啊:几个输出就命名几个,这样在用ncnn的load的时候才能直接提取出来。一般导出onnx的代码举例如下:
![bfcad8e0e7ef7681fb88358dbf0c7d49.png](https://i-blog.csdnimg.cn/blog_migrate/bcab49b5cdf4370406b36adadb8dd06b.jpeg)
关于onnx2ncnn:这个是重点,得到了onnx模型,你也就告别了pytorch的框架了,可以随心所欲了,现在需要将onnx格式的模型转成ncnn能够加载的.bin和.param。用于是前面编译好的ncnn带的工具,如果ncnn编译成功的话:ncnn/build/tools/onnx/下面有一个编译好的onnx2ncnn。只需要:
./
(model是你的onnx名字),如果什么都没输出,那恭喜成功了!如果遇到下面这种情况:
![9cf71172aefb3c70a466d8628158cde7.png](https://i-blog.csdnimg.cn/blog_migrate/d17fcb19bab0b97c87d10c5d806891ea.jpeg)
那完蛋!虽然成功生成了.param和.bin,但是用ncnn 来load模型的时候一般都会失败!因为目前ncnn对于某一些操作还不支持,所以这里还有引入一个工具:ONNX Simplifier!
ONNX Simplifier:
github连接:
daquexian/onnx-simplifiergithub.com![1c41d597d56b2a0ffb4ef98d0a042525.png](https://i-blog.csdnimg.cn/blog_migrate/0fd7a32b1fa34a7e45c819844b6b1aac.png)
![f0a7105c74c368ae6415b1810e5fc3ed.png](https://i-blog.csdnimg.cn/blog_migrate/8a0873e697bd7754b7fbcf264bf288f8.png)
如果simplifier都失败了,那可能真得回过头反思反思(根据报错的位置对应到pytorch网络的位置)自己的pytorch定义的网络或者某些后处理操作是不是有问题(一般问题出在后处理部分:譬如目标检测的坐标解码,nms等),所以一般不建议将除网络以外的部分打包到onnx中,其实后处理这些最好还是用c++来写,主要也快(我个人也有疑问,到底是把后处理放到里面好,还是单独c++来写好?)
ncnn调用生成的模型以及一些基本操作:
建议新建一个目录来存放下面的东西:
编写CMakeList.txt,main.cpp
CMakeList.txt里面需要包括下面的一些基本内容:
cmake_minimum_required
编写main.cpp:
#include
上面是一个基本模板;后续的一些针对tensor的处理就需要根据需求来定,譬如需要对其进行解码,NMS等,可以编写纯c++的代码来处理。
ncnn的就先到这里,后面有时间再好好研究研究ncnn框架。下一篇会讲一下如何使用LibTorch来部署pytorch的模型。