当前位置: 首页 > news >正文

【深度学习】【onnxruntime】C++调用onnx

【深度学习】【onnxruntime】C++环境搭建

提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论

文章目录

  • 【深度学习】【onnxruntime】C++环境搭建
  • 前言
  • Windows平台安装onnxruntime
  • Windows平台安装OpenCV
  • onnxruntime调用onnx模型
      • 简单验证
      • 调用onnx模型
  • 总结


前言

本章将讲述如何使用搭建c++下onnxruntime的运行环境,将pytorch中训练好的模型使用ONNX导出,再使用onnxruntime直接进行加载使用,不再依赖再使用opencv中的dnn模块直接进行加载使用,因为opencv的dnn模块在执行速度上受限。

读者可以通过学习【onnx部署】部署系列学习文章目录的快速入门 的内容,快速入门上手。


Windows平台安装onnxruntime

官网下载安装文件地址,根据自己的情况选择合适的版本,博主使用ONNX Runtime v1.15.0版本。

在assert下选择onnxruntime-win-x64-gpu-1.15.0.zip下载

双击运行解压后即可:

打开VS 2019:新建新项目---->空项目---->配置项目---->项目路径以及勾选“将解决方案和项目放在同一目录中---->点击创建。
在解决方案–>源文件–>右键添加新建项。这里暂时可以默认空着不做处理。

设置onnxruntime路径:项目---->属性。假设没有新建cpp文件,空项目的属性页就不会存在C/C++这一项目。

添加附加包含目录:Release | x64---->C/C+±—>常规---->附加包含目录。

D:\C++_demo\onnxruntime-win-x64-gpu-1.15.0\include

链接器:Release | x64---->链接器---->常规---->附加库目录。

D:\C++_demo\onnxruntime-win-x64-gpu-1.15.0\lib

链接器:Release | x64---->链接器---->输入---->附加依赖项。

在D:\C++_demo\onnxruntime-win-x64-gpu-1.15.0\lib下找到附加依赖项的文件。

onnxruntime.lib
onnxruntime_providers_cuda.lib
onnxruntime_providers_shared.lib

Windows平台安装OpenCV

官网下载安装文件地址,博主使用opencv-4.8.0-windows.exe版本

双击运行解压后即可,博主重命名为opencv4.8.0:

添加附加包含目录:Release | x64---->C/C+±—>常规---->附加包含目录。

D:\C++_demo\opencv4.8.0\build\include

链接器:Release | x64---->链接器---->常规---->附加库目录。

D:\C++_demo\opencv4.8.0\build\x64\vc16\lib

链接器:Release | x64---->链接器---->输入---->附加依赖项。

opencv_world480.lib

onnxruntime调用onnx模型

在Release x64模式下测试,将onnxruntime的onnxruntime.dll、onnxruntime_providers_cuda.dll和onnxruntime_providers_shared.dll,以及opencv的opencv_world480.dll文件复制到自己项目的Release下。

没有Release目录时,需要在Release | x64模式下运行一遍代码,代码部分在下面提供,读者可以先行新建文件复制代码。

D:\C++_demo\onnxruntime-win-x64-gpu-1.15.0\lib
D:\C++_demo\opencv4.8.0\build\x64\vc16\bin
===>
D:\C++_demo\onnxruntime_onnx\x64\Release

简单验证

这里简单验证一下onnxruntime和opencv是否安装成功,适用于包括博主在内的许多对c++不熟悉的人来说,代码完成了简单的图像的读取与显示。

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {Mat src = imread("./animal-1.jpg");//没有图像输入if (src.empty()) {printf("....\n");return -1;}//namedWindow("输入窗口", WINDOW_FREERATIO);imshow("输入窗口", src);waitKey(0);destroyAllWindows();return 0;
}

调用onnx模型

将PFNet.onnx拷贝到项目路径下。
将python版本的onnxruntime转化成对应的c++版本的,发现输出的效果完全一致,onnx模型可以作为c++的接口来供其他应用调用。

#include "onnxruntime_cxx_api.h"
#include <opencv2/opencv.hpp>
#include <fstream>
cv::Mat transformation(const cv::Mat& image, const cv::Size& targetSize, const cv::Scalar& mean, const cv::Scalar& std) {cv::Mat resizedImage;//图片尺寸缩放cv::resize(image, resizedImage, targetSize, 0, 0, cv::INTER_AREA);cv::Mat normalized;resizedImage.convertTo(normalized, CV_32F);cv::subtract(normalized / 255.0, mean, normalized);cv::divide(normalized, std, normalized);return normalized;
}int main(int argc, char** argv) {cv::Scalar mean(0.485, 0.456, 0.406); // 均值cv::Scalar std(0.229, 0.224, 0.225);  // 标准差cv::Mat frame = cv::imread("D:/C++_demo/onnxruntime_onnx/animal-1.jpg");std::string onnxpath = "D:/C++_demo/onnxruntime_onnx/PFNet.onnx";std::wstring modelPath = std::wstring(onnxpath.begin(), onnxpath.end());Ort::SessionOptions session_options;Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "PFNet.onnx");// 设定单个操作(op)内部并行执行的最大线程数,可以提升速度session_options.SetIntraOpNumThreads(20);session_options.SetGraphOptimizationLevel(ORT_ENABLE_EXTENDED);std::cout << "onnxruntime inference try to use GPU Device" << std::endl;// 是否使用GPUOrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0);Ort::Session session_(env, modelPath.c_str(), session_options);int input_nodes_num = session_.GetInputCount();int output_nodes_num = session_.GetOutputCount();std::vector<std::string> input_node_names;std::vector<std::string> output_node_names;Ort::AllocatorWithDefaultOptions allocator;int input_h = 0;int input_w = 0;// 获得输入信息for (int i = 0; i < input_nodes_num; i++) {auto input_name = session_.GetInputNameAllocated(i, allocator);input_node_names.push_back(input_name.get());auto inputShapeInfo = session_.GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape();int ch = inputShapeInfo[1];input_h = inputShapeInfo[2];input_w = inputShapeInfo[3];std::cout << "input format: " << ch << "x" << input_h << "x" << input_w << std::endl;}// 获得输出信息 多输出for (int i = 0; i < output_nodes_num; i++) {auto output_name = session_.GetOutputNameAllocated(i, allocator);output_node_names.push_back(output_name.get());auto outShapeInfo = session_.GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape();int ch = outShapeInfo[1];int output_h = outShapeInfo[2];int output_w = outShapeInfo[3];std::cout << "output format: " << ch << "x" << output_h << "x" << output_w << std::endl;}// 图象预处理 - 格式化操作int64 start = cv::getTickCount();cv::Mat rgbImage;cv::cvtColor(frame, rgbImage, cv::COLOR_BGR2RGB);cv::Size targetSize(input_w, input_h);// 对原始图像resize和归一化cv::Mat normalized = transformation(rgbImage, targetSize, mean, std);cv::Mat blob = cv::dnn::blobFromImage(normalized);size_t tpixels = input_w * input_h * 3;std::array<int64_t, 4> input_shape_info{ 1, 3, input_h, input_w };auto allocator_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);Ort::Value input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, blob.ptr<float>(), tpixels, input_shape_info.data(), input_shape_info.size());// 输入一个数据const std::array<const char*, 1> inputNames = { input_node_names[0].c_str() };// 输出多个数据const std::array<const char*, 3> outNames = { output_node_names[0].c_str(),output_node_names[1].c_str(),output_node_names[2].c_str() };std::vector<Ort::Value> ort_outputs;try {ort_outputs = session_.Run(Ort::RunOptions{ nullptr }, inputNames.data(), &input_tensor_, inputNames.size(), outNames.data(), outNames.size());}catch (std::exception e) {std::cout << e.what() << std::endl;}// 选择最后一个输出作为最终的maskconst float* mask_data = ort_outputs[2].GetTensorMutableData<float>();auto outShape = ort_outputs[2].GetTensorTypeAndShapeInfo().GetShape();int num_cn = outShape[1];int out_h = outShape[2];int out_w = outShape[3];int step = out_h * out_w;// 逐像素判断是背景还是前景cv::Mat result = cv::Mat::zeros(cv::Size(out_w, out_h), CV_8UC1);for (int row = 0; row < out_h; row++) {for (int col = 0; col < out_w; col++) {float c1 = mask_data[row * out_w + col];if (c1 > 0.5) {result.at<uchar>(row, col) = 255;}else {result.at<uchar>(row, col) = 0;}}}cv::Mat mask, binary;cv::resize(result, mask, cv::Size(frame.cols, frame.rows));cv::threshold(mask, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);float t = (cv::getTickCount() - start) / static_cast<float>(cv::getTickFrequency());std::cout << "Total Testing Time : " << t << std::endl;cv::imshow("mask", binary);cv::waitKey(0);// 释放资源session_options.release();session_.release();return 0;
}

这里只推理一张图片,因此加载GPU比较费时。

session_options.SetIntraOpNumThreads可以有效提升网络的推理速度,这是opencv调用onnx模型进行推理所不具备的优势


总结

尽可能简单、详细的介绍C++下onnxruntime调用ONNX模型的流程。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 三维动画|创意无限,让品牌传播更精彩!
  • 2024年第十五届蓝桥杯青少组国赛撞期GESP认证、放弃那个?
  • C语言:刷题日志(3)
  • Golang | Leetcode Golang题解之第393题UTF-8编码验证
  • 【系统架构设计师-2015年】案例分析-答案及详解
  • 使用Azure+C#+visual studio开发图像目标检测系统
  • 《黑神话.悟空》与人工智能AI重塑经典与探索未来的交织
  • Android内存知识总结
  • JAVA毕业设计173—基于Java+Springboot+vue3的酒店民宿管理系统(源代码+数据库)
  • 浙大数据结构:03-树2 List Leaves
  • 数据库MySQL
  • 源码到class字节码的编译流程 字节码到内存的Java类加载流程
  • 算法提高模板强连通分量tarjan算法
  • AIoTedge边缘计算+边缘物联网平台
  • sed awk 第二版学习(四)—— 基本 sed 命令
  • 收藏网友的 源程序下载网
  • Angular4 模板式表单用法以及验证
  • Golang-长连接-状态推送
  • Protobuf3语言指南
  • Redis 中的布隆过滤器
  • Terraform入门 - 3. 变更基础设施
  • webgl (原生)基础入门指南【一】
  • 爱情 北京女病人
  • 初识 beanstalkd
  • 基于axios的vue插件,让http请求更简单
  • 面试总结JavaScript篇
  • 悄悄地说一个bug
  • 三分钟教你同步 Visual Studio Code 设置
  • 线性表及其算法(java实现)
  • 项目管理碎碎念系列之一:干系人管理
  • 小而合理的前端理论:rscss和rsjs
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 关于Android全面屏虚拟导航栏的适配总结
  • 数据可视化之下发图实践
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • # 数据结构
  • #QT(QCharts绘制曲线)
  • #数据结构 笔记一
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (16)Reactor的测试——响应式Spring的道法术器
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)LINQ之路
  • (转载)利用webkit抓取动态网页和链接
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • ./configure,make,make install的作用(转)
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .NET C# 配置 Options
  • .Net Core中Quartz的使用方法
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况