pytorch转ncnn是要在电脑上部署好ncnn环境,下图为可部署ncnn的平台
一.安装VS2019
下载地址:https://visualstudio.microsoft.com/zh-hans/vs/
二.安装cmake 3.16.5
1.下载后解压
2.添加环境变量(将解压后cmake-3.16.5-win64-x64文件夹点开进入bin将该路径添加至环境变量)
三.安装protobuf-3.4.0
1.下载后解压
2.使用VS2019中X64的命令行(下图红框)
4.打开命令行后输入命令( 为你刚刚解压的protobuf-3.4.0文件夹的根目录)
> cd
> mkdir build-vs2019
> cd build-vs2019
> cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF ../cmake
> nmake
> nmake install
5.成功后会产生build-vs2019文件夹以及该文件夹下的若干文件夹及文件
四.构建ncnn
1.ncnn下载地址:https://github.com/Tencent/ncnn (官网)
2.git clone该项目,或者直接下载压缩包
3.打开VS2019的X64命令行(进入到ncnn根目录下)执行以下语句
注意:cmake -G…这条命令有三个需要换成之前安装protobuf-3.4.0的根目录
> cd
> mkdir -p build-vs2019
> cd build-vs2019
> cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=/build-vs2019/install/include -DProtobuf_LIBRARIES=/build-vs2019/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=/build-vs2019/install/bin/protoc.exe -DNCNN_VULKAN=OFF ..
> nmake
> nmake install
4.成功后会产生build-vs2019文件夹以及该文件夹下的若干文件夹及文件
五.安装opencv
1.下载地址:https://github.com/opencv/opencv/releases/tag/3.4.2
2.下载opencv-3.4.2-vc14_vc15.exe
3.下载后解压
4.配置环境变量(类比cmake)
一.将gcc、g++降级为4.8.5版本
sudo apt-get install gcc-4.8 g++4.8
cd /usr/bin
sudo rm g++ gcc
sudo ln -s gcc-4.8 gcc
sudo ln -s g++-4.8 g++
二.安装protobuf
1.下载地址: https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
2.下载protobuf后解压
3.执行以下命令
cd protobuf-2.6.1
./configure
make -j8
make check
sudo make install
sudo ldconfig
三.安装opencv
1.1安装cmake
sudo apt-get install cmake
1.2所需依赖
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install pkg-config
2.1下载opencv(建议3.版本的)
下载地址:https://opencv.org/releases/
2.2解压文件并进入文件夹
mkdir build
cd build
sudo cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j8
sudo make install
2.3配置环境
使用vim打开/etc/ld.so.conf,在文件中加一行/usr/local/lib(其中/user/loacal是opencv安装路径也就是makefile中指定的安装路径)
sudo gedit /etc/ld.so.conf
sudo ldconfig
用vim在bash.bashrc文件末尾加入:
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
然后使用命令
source /etc/bash.bashrc
四.安装ncnn
git clone https://github.com/Tencent/ncnn.git
cd ncnn
mkdir build && cd build
cmake ..
make
make install
pytorch转onnx主要是用pytorch里面自带的*torch.onnx.export()*这个函数(这个函数目前在pytorch1.4版本存在)。
先看来一下torch.onnx.export()的原型与部分参数
torch.onnx.export(model, args, f, export_params=True, verbose=False, training=False, input_names=None, output_names=None, aten=False, export_raw_ir=False, operator_export_type=None, opset_version=None, _retain_param_name=True, do_constant_folding=False, example_outputs=None, strip_doc_string=True, dynamic_axes=None, keep_initializers_as_inputs=None)
model:要转换的模型。
args:模型输入。
export_params : 如果指定为True或默认, 参数也会被导出. 如果你要导出一个没训练过的就设为 False.
verbose: 如果指定,我们将打印出一个导出轨迹的调试描述。
training : 训练模式导出模型。 目前,ONNX 仅面向导出模型以进行推理,因此通常不需要将其设置为 True。
input_names : 按顺序分配名称到图中的输入节点。
output_names :按顺序分配名称到图中的输出节点。
opset_version :默认情况下,将模型导出到 onnx 子模块的 opset 版本。
样例:
import torch
from model import td4_psp18 ##引入自己的网络
##加载模型
model = td4_psp18.td4_psp18(nclass=19,path_num=4,model_path=".\\pretrained\\cityscapes\\td4-psp18.pkl")
model.eval()
input=torch.randn(1,3,769,1537) ##网络输入
input_names=["input"]
output_names=["output"]
out_onnx='C:\\Users\\30229\\Desktop\\TDNet-master\\test.onnx'
torch.onnx.export(model,input,out_onnx,input_names=input_names,output_names=output_names,opset_version=11)
我这里设置opset_version=11是因为在转换模型的时候报错说opset_version=9不支持,需要换成opset_version=11。
TDnet除了这个参数会报错之外还不支持AdaptiveAvgPool2d,可以将AdaptiveAvgPool2d转为AvgPool2d
原代码
# self.pool1 = nn.AdaptiveAvgPool2d(1)
# self.pool2 = nn.AdaptiveAvgPool2d(2)
# self.pool3 = nn.AdaptiveAvgPool2d(3)
# self.pool4 = nn.AdaptiveAvgPool2d(6)
修改后
self.pool1=nn.AvgPool2d(kernel_size = (97,193),stride=(97,193),ceil_mode=False)
self.pool2=nn.AvgPool2d(kernel_size = (49,97),stride=(48,96),ceil_mode=False)
self.pool3=nn.AvgPool2d(kernel_size = (33,65),stride=(32,64),ceil_mode=False)
self.pool4=nn.AvgPool2d(kernel_size = (17,33),stride=(16,32),ceil_mode=False)
修改之后就可以使用torch.onnx.export()将pth/pkl文件转onnx了,虽然可以转到ncnn但是在使用ncnn时会发现LayerNorm层报错,可能是不兼容的问题,之后我把LayerNorm层删掉重新转出来的ncnn文件就可以正常使用了。可能是不兼容的问题,等后面改好了再添加修改方案。
转成的onnx文件还要测试一下,看看模型是否正常。测试代码如下
import os.path as osp
import numpy as np
import onnx
import onnxruntime as ort
import torch
import torchvision
##加载模型所在模块
from model import td4_psp18, td2_psp50, pspnet
# 模型输入
test_arr = np.random.randn(1, 3, 769, 1537).astype(np.float32)
dummy_input = torch.randn(1, 3, 769, 1537, device='cuda')
#载入pytorch模型
model = td4_psp18.td4_psp18(nclass=19,path_num=4,model_path="C:\\Users\\30229\\Desktop\\TDNet-master\\pretrained\\cityscapes\\td4-psp18.pkl").cuda().eval()
print('pytorch result:', model(torch.from_numpy(test_arr).cuda()))
input_names = ["input"]
output_names = ["output"]
# if not osp.exists('TDnet.onnx'):
# # translate your pytorch model to onnx
# torch.onnx.export(model, dummy_input, "TDnet.onnx", verbose=True, input_names=input_names, output_names=output_names)
#载入onnx模型
model = onnx.load("转ncnn\\test.onnx")
ort_session = ort.InferenceSession('转ncnn\\test.onnx')
outputs = ort_session.run(None, {'input': test_arr})
print('test result:', outputs[0])
然后可以对比一下原输出和转onnx模型的输出。两个输出有部分误差的话是正常现象,一般转模型都可能出现精度损失。下图为我输出的对比图
用torch导出的模型有时候参数过多,直接转ncnn会报错。查阅资料后发现可以使用onnxsim进行简化
pip install onnx-simplifier
python -m onnxsim model_name.onnx model_name-sim.onnx
之后到之前部署好的ncnn目录里面打开build-vs2019(Windows)或者build(Ubuntu)依次进入tool和onnx,里面有个onnx2ncnn.exe 。把转换好的onnx文件和这个exe文件放在一起后运行
./onnx2ncnn.exe model_name.onnx model_name.bin model_name.param
在文件中出现bin和param文件,就说明转化成功
参考文章
在windows上部署ncnn:https://blog.csdn.net/qq_36890370/article/details/104966786
在ubuntu上安装opencv:https://blog.csdn.net/public669/article/details/99044895