深度学习模型C++部署的常见方法(一)

发布时间:2022-08-19 12:18

opencv DNN 模块加载onnx模型

onnx模型是一种针对深度学习所设计的开放式的文件格式,简而言之,onnx是一种“百搭”于各种主流深度学习框架和不同开发语言的中间模型格式,onnx模型的导出方式有多种,主流的深度学习框架例如Pytorch、Paddle都自带onnx模型的导出工具。以Pytorch模型为例,新的Pytorch版本自带了onnx的API接口,使得用户更加方便地导出、转换和加载onnx模型。

model.eval()

inputX = torch.randn((1,1,64,64))     #预定义模型输入shape

torch.onnx.export(model=model,args=inputX,f="model_path/model.onnx",input_names=["input"],output_names=["output"])

参数:

model:预训练好的模型

args:定义模型输入shape,可以是tensor类型,也可以是tuple类型

f:onnx模型保存地址和名称

input_names:模型输入名称(可多输入)

output_names:模型输出名称(可多输出)

opencv的dnn模块可以直接加载onnx模型,并进行模型推理,其优势是利用opencv做视觉前端时无需再搭配例如Libtorch或onnxruntime等外部开发环境,更加方便。

#include 
#include 
#include 
#include 
#include 

using namespace std;


void main()
{
	cv::dnn::Net net = cv::dnn::readNetFromONNX("model.onnx");
    ///加载onnx模型
	cv::Mat image = cv::imread("img.jpg");
	///加载图片
	cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
    ///转为灰度图片
	cv::Mat blob;
	blob = cv::dnn::blobFromImage(image, 1.0, cv::Size(64, 64), cv::Scalar(0, 0, 0), false, false, CV_32F);
    
	net.setInput(blob, "input");
	cv::Mat predict = net.forward("output");
    ///模型推理

    double min, max;
	cv::Point maxp, minp;
	cv::minMaxLoc(predict, &min, &max, &minp, &maxp);
    
    cout<

打印输出:

1437.4578    5

[-3263.5632, 1294.3146, 577.03925, -274.58981, -2270.4136, 1437.4578]

Libtorch加载Pytorch模型

Libtorch下载:Libtorch官方下载链接

深度学习模型C++部署的常见方法(一)_第1张图片

 Libtorch是Pytorch官方提供的C++/Java的API接口,支持CPU端和GPU端的部署。将Pytorch在Python平台上训练的模型部署到C++或者Java平台上,其优点是对Pytorch模型的部署相对方便,因为两者属于同一个生态,API接口匹配度较高,对于Pytorch模型的兼容性也相对较高。

需要注意的是下载版本,最新版本的Libtorch以及不再支持cuda10.x,也就意味着如果你的显卡型号不知此cuda11以上就只能下载以前的版本,其次是Libtorch分为Release和Debug版本,大家根据自己需要下载。

自从PyTorch 的 1.0 版本发布依赖,最核心的两个新特性就是 JIT 和 C++ API,JIT(Just In Time Complication 即时编译), 是 Python 和 C++ 的桥梁,我们可以使用 Python 训练模型,然后通过 JIT 将模型转为语言无关的模块,从而让 C++ 可以非常方便得调用。

torch.jit 模型保存:

model.eval()
input = torch.ones([1, 1, 64, 64]).to(DEVICE)
traced_script_module = torch.jit.trace(model, input)
traced_script_module.save("model.pt")

 Libtorch配置 (Cpu-Release)

系统环境变量:

注意事项:如果同时下载了Release版本和Debug版本的Libtorch,或者同时下载了CPU和cuda的版本,注意用哪个版本哪个版本环境变量放在最前面,不然链接器会加载最前面的版本的库目录,导致混淆报错。

项目>>配置 >>VC++目录>>包含目录: 

D:\HeZheng\Env\libtorch\include

D:\HeZheng\Env\libtorch\include\torch\csrc\api\include

项目>>配置 >>VC++目录>>库目录:

D:\HeZheng\Env\libtorch\lib

项目>>配置>>链接器>>输入>>附加依赖项:

libprotobuf.lib   (如果是Debug改为 libprobufd.lib)

dnnl.lib

torch.lib

torch_cpu.lib

c10.lib

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

torch::jit::script::Module model = torch::jit::load("model_path/model.pt");
//加载模型路径
torch::DeviceType device_type = at::kCPU;

void main()
{
	cv::Mat imgResult_cov;

	cv::Mat img = cv::imread("test.jpg");
	//opencv format H*W*C
	cv::resize(img, imgResult_cov, cv::Size(64, 64));
	//裁剪图片大小最好放在数据处理的第一步
	cv::cvtColor(imgResult_cov, imgResult_cov, CV_BGR2GRAY);
	//转为灰度图像

	imgResult_cov.convertTo(imgResult_cov, CV_32F, 1.0f / 255.0f);
	//normalization
	auto input_tensor = torch::from_blob(imgResult_cov.data, { 1,1 , 64, 64 }, torch::kF32);
	//将图从Mat类型转为tensor类型
	std::vector inputs;
	inputs.emplace_back(input_tensor.to(device_type));

	at::Tensor output = model.forward(inputs).toTensor();
	//推理

	cout << output << endl;
	//打印输出
	std::tuple max_classes = torch::max(output, 1);

	auto get_max = std::get<0>(max_classes);
	double max = torch::Tensor(get_max).item();
	//得到最大值

	auto get_max_index = std::get<1>(max_classes);
	int max_index = torch::Tensor(get_max_index).item();
	//得到最大值索引

	cout << "最大值" << max << endl;
	cout << "最大值索引" << max_index << endl;
}

输出结果打印:

 -4.3639  -8.4727  13.2539  -1.5945  -2.1677  -1.9636
[ CPUFloatType{1,6} ]
最大值13.2539
最大值索引2

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号