当前位置:   article > 正文

【深度学习】win10下pytorch转ncnn手把手教程_ncnn python

ncnn python

前言

最近需要把pytorch转为onnx再转为ncnn,整体流程大概为:
1、pytorch转为onnx;
2、使用onnx-simplifier工具简化onnx模型;
3、onnx转化为ncnn。


一、环境配置

1.VS2019

点击链接去官网安装。

2.CMake3.21.3

点击链接去官网安装。

用户变量中配置环境变量。右键此电脑->属性->高级系统设置->环境变量->用户变量,选择Path进行添加。(在系统变量中添加也行,二者的区别在于:用户变量中添加的只对当前用户有效,而系统变量中添加的对所有用户都有效)
在这里插入图片描述

3.OpenCV3.4.13

点击链接去官网安装。
在这里插入图片描述
用户变量中配置环境变量。
在这里插入图片描述
我在E盘下新建了一个ncnnby的文件夹表示其所用到的所有依赖。opencv就装在这个文件夹下。

4.protobuf3.4.0

点击链接直接下载。
将其下载到指定文件夹下:E:\ncnnby,打开x64 Native Tools Command Prompt for VS 2019,依次输入以下指令

cd <protobuf-root-dir>
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

最终得到以下所需文件:
在这里插入图片描述

5.编译ncnn

点击链接去github下载ncnn。
在这里插入图片描述
下载得到ncnn-master.zip,解压到E:\ncnnby下。
打开x64 Native Tools Command Prompt for VS 2019,依次输入以下指令:

cd <ncnn-root-dir>
mkdir build-vs2019
cd build-vs2019
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=E:/ncnnby/protobuf-3.4.0/build-vs2019/install/include -DProtobuf_LIBRARIES=E:/ncnnby/protobuf-3.4.0/build-vs2019/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=E:/ncnnby/protobuf-3.4.0/build-vs2019/install/bin/protoc.exe -DNCNN_VULKAN=off -DOpenCV_DIR=D:/ncnnby/opencv/build ..
nmake
nmake install
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:把以-DProtobuf开头的路径改成自己protobuf所在路径,把-DOpenCV_DIR开头的命令改成自己的opencv所在路径。因此这里总共需要改动四处。
-DNCNN_VULKAN=off的意思是不使用GPU,而是用CPU进行推理。

最终得到以下所需文件:
在这里插入图片描述
至此,环境已经配置结束,且所需要的文件都已编译好。

二、模型转换

1.pytorch转onnx

Pycharm新建一个项目(名字任意),只需一个main.py即可, 采用pytorch自带的resnet18作为示例,代码如下:

import torch
import torchvision

#define resnet18 model
model = torchvision.models.resnet18(pretrained=True)
#define input shape
x = torch.rand(1, 3, 224, 224)
#define input and output nodes, can be customized
input_names = ["x"]
output_names = ["y"]
#convert pytorch to onnx
torch_out = torch.onnx.export(model, x, "resnet18.onnx", input_names=input_names, output_names=output_names)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

直接运行,会发现项目下面多了一个resnet18.onnx文件
在这里插入图片描述在这里插入图片描述
测试pytorch模型和onnx模型的推理结果是否一致,代码如下:

import torch
import torchvision
import onnxruntime as rt
import numpy as np
import cv2

#test image
img_path = "test.jpg" //测试图片放在当前目录下
img = cv2.imread(img_path)
img = cv2.resize(img, (224, 224))
img = np.transpose(img, (2, 0, 1)).astype(np.float32)
img = torch.from_numpy(img)
img = img.unsqueeze(0)

#pytorch test
model = torchvision.models.resnet18(pretrained=True)
model.eval()
output = model.forward(img)
val, cls = torch.max(output.data, 1)
print("[pytorch]--->predicted class:", cls.item())
print("[pytorch]--->predicted value:", val.item())

#onnx test
sess = rt.InferenceSession("resnet18.onnx")
x = "x"
y = ["y"]
output = sess.run(y, {x : img.numpy()})
cls = np.argmax(output[0][0], axis=0)
val = output[0][0][cls]
print("[onnx]--->predicted class:", cls)
print("[onnx]--->predicted value:", val)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

test.jpg是我在网上下载了一只猫咪图片,测试结果如下:
在这里插入图片描述
推理结果是对的,预测概率会有些许的偏差。

2.简化onnx

对于我这个用例,因为很简单,所以其实不用简化也能成功将onnx转成ncnn,但对于复杂的模型必须先简化再转换,否则会失败。这里我简化一下。
在命令行安装简化工具onnx-simplifier,指令如下:

pip install onnx-simplifier
  • 1

cd到onnx模型所在目录,我这里是F:\Pycharm\pythonProject,在命令行输入如下指令:

python -m onnxsim resnet18.onnx resnet18-sim.onnx
  • 1

注意:如果以python开头不行的话就改成python3,哪个行用哪个。

可以得到简化模型resnet18-sim.onnx
在这里插入图片描述

3.onnx转ncnn

将简化后文件移动到E:\ncnnby\ncnn-master\build-vs2019\tools\onnx文件夹下
在这里插入图片描述
注意:不是E:\ncnnby\ncnn-master\tools\onnx,而是E:\ncnnby\ncnn-master\build-vs2019\tools\onnx,我一开始就在这里踩坑了。前者只包含onnx2ncnn.cpp这个文件,缺少头文件和可执行文件等等一系列我们所需要的文件,而后者是我们之前编译ncnn的时候创建的,里面万事俱备。

在当前目录下打开命令行,输入如下指令:

onnx2ncnn resnet18-sim.onnx resnet18.param resnet18.bin
  • 1

得到ncnn模型文件
在这里插入图片描述
生成了resnet18的param文件和bin文件,其中,param文件保存了模型结构,bin文件保存了模型参数。

4.测试ncnn

打开Visual Studio2019,选择创建新项目
在这里插入图片描述
选择空项目,点击下一步
在这里插入图片描述
随便起一个名字,我这里叫ncnn-by-test,且把它放在了E:\ncnnby下面,点击创建
在这里插入图片描述
现在点击视图->其他窗口->属性管理器,右键Release x64,选择添加新项目属性表
在这里插入图片描述
命名属性表为ncnn_opencv_releasex64,点击添加在这里插入图片描述
双击打开属性页开始编辑,我们依次需要修改VC++目录下的包含目录、库目录,以及链接器->输入下的附加依赖项
包含目录中添加如下代码:

<opencv-root-dir>/build/include 
<opencv-root-dir>/build/include/opencv 
<opencv-root-dir>/build/include/opencv2 
<ncnn-root-dir>/build-vs2019/install/include/ncnn
<protobuf-root-dir>/build-vs2019/install/include
  • 1
  • 2
  • 3
  • 4
  • 5

前面的分别是opencv的根目录,ncnn的根目录和protobuf的根目录。
在这里插入图片描述
库目录中添加如下代码:

<opencv-root-dir>/build-vs2019/x64/vc15/lib
<ncnn-root-dir>/build-vs2019/install/lib
<protobuf-root-dir>/build-vs2019/install/lib
  • 1
  • 2
  • 3

在这里插入图片描述
点击链接器->输入->附加依赖项,增加如下内容:

ncnn.lib
opencv_world3413.lib
libprotobuf.lib
libprotobuf-lite.lib
libprotoc.lib
  • 1
  • 2
  • 3
  • 4
  • 5

这里一定要注意opencv_world3413.lib这个玩意儿,因为opencv的官网是不断更新的,所以你从官网上下载下来的这个文件的版本号不知道已经迭代到多少版了,所以你需要去相应的目录看你下载的到底是多少,我的目录是E:\ncnnby\opencv\build\x64\vc15\lib,可以看到我的是3413,你的如果是3410你就要改成opencv_world3410.lib
在这里插入图片描述
在这里插入图片描述
至此,VS2019的相关操作结束,注意测试的时候要选择release以及x64,如图所示:
在这里插入图片描述
最后,测试ncnn模型的前向推理结果的正确性,在源文件下新建一个ncnn_test.cpp的文件,添加如下代码:

#include <opencv2/highgui/highgui.hpp> //这些东西在我们刚才添加依赖的时候已经添加进来了
#include <vector>
#include "net.h"

using namespace std;

vector<float> get_output(const ncnn::Mat& m)
{
	vector<float> res;
	for (int q = 0; q < m.c; q++)
	{
		const float* ptr = m.channel(q);
		for (int y = 0; y < m.h; y++)
		{
			for (int x = 0; x < m.w; x++)
			{
				res.push_back(ptr[x]);
			}
			ptr += m.w;
		}
	}
	return res;
}

int main()
{
	cv::Mat img = cv::imread("test.jpg"); //替换为你的图片地址
	int w = img.cols;
	int h = img.rows;
	ncnn::Mat in = ncnn::Mat::from_pixels_resize(img.data, ncnn::Mat::PIXEL_BGR, w, h, 224, 224);

	ncnn::Net net;
	net.load_param("resnet18.param"); //刚才生成的param文件
	net.load_model("resnet18.bin"); //刚才生成的bin文件
	ncnn::Extractor ex = net.create_extractor();
	ex.set_light_mode(true);
	ex.set_num_threads(4);

	ex.input("x", in);
	ncnn::Mat feat;
	ex.extract("y", feat);
	vector<float> res = get_output(feat);
	vector<float>::iterator max_id = max_element(res.begin(), res.end());
	printf("predicted class: %d, predicted value: %f", max_id - res.begin(), res[max_id - res.begin()]);
	net.clear();
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

运行结果如下:
在这里插入图片描述

预测类别和pytorch/onnx保持一致,由于计算库的不同,预测概率略微偏差。
这里我遇到一个FATAL ERROE!的问题,百度了一些找不到解决办法,只能说不影响检测结果。如果你遇到了并且解决了,请告知我。

至此,全部ok。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/297950
推荐阅读
相关标签
  

闽ICP备14008679号