发布时间:2022-08-19 12:18
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下载:Libtorch官方下载链接
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