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

yolov8 模型部署--TensorRT部署-c++服务化部署

写目录

  • yolov8 模型部署--TensorRT部署
    • 1、模型导出为onnx格式
    • 2、模型onnx格式转engine 部署

yolov8 模型部署–TensorRT部署

1、模型导出为onnx格式

  • 如果要用TensorRT部署YOLOv8,需要先使用下面的命令将模型导出为onnx格式:

    yolo export model=yolov8n.pt format=onnx 
    
  • YOLOv8的3个检测头一共有80x80+40x40+20x20=8400个输出单元格,每个单元格包含x,y,w,h这4项再加80个类别的置信度总共84项内容,所以通过上面命令导出的onnx模型的输出维度为1x84x8400

  • 模型输出维度
    在这里插入图片描述

  • 这样的通道排列顺序有个问题,那就是后处理的时候会造成内存访问不连续。

  • 为了解决这个问题,我们可以修改一下代码,具体做法是把ultralytics/nn/modules.py文件中的代码做如下修改,交换一下张量y的通道顺序:

    def forward(self, x):shape = x[0].shape  # BCHWfor i in range(self.nl):x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)if self.training:return xelif self.dynamic or self.shape != shape:self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))self.shape = shapex_cat = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)if self.export and self.format in ('saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs'):  # avoid TF FlexSplitV opsbox = x_cat[:, :self.reg_max * 4]cls = x_cat[:, self.reg_max * 4:]else:box, cls = x_cat.split((self.reg_max * 4, self.nc), 1)dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.stridesy = torch.cat((dbox, cls.sigmoid()), 1)# 修改模型输出维度y=y.permute(0,2,1)return y if self.export else (y, x)

在这里插入图片描述

  • 这样修改后再执行上面的模型导出命令,模型的输出维度变为1x8400x84
    在这里插入图片描述

2、模型onnx格式转engine 部署

  • 配置好TensorRTNVIDIA环境
  • 使用trtexec 转换格式
    trtexec --onnx=coco/best.onnx --saveEngine=coco/best.onnx.engine --workspace=32 
    
  • 模型部署部分代码-c++
    #ifndef MyController_hpp
    #define MyController_hpp#include <ctime>
    #include <chrono>
    #include <sstream>
    #include <iomanip>#include <iostream>
    #include <numeric>
    #include <vector>#include "oatpp/web/server/api/ApiController.hpp"
    #include "oatpp/core/macro/codegen.hpp"
    #include "oatpp/core/macro/component.hpp"#include "opencv2/opencv.hpp"
    #include "../dto/DTOs.hpp" // 定义数据格式,用于在不同组件之间传输数据#include "../yoloApp/simple_yolo.hpp"
    #include "../byteTrackApp/logging.h"
    #include "../byteTrackApp/BYTETracker.h"// high performance
    #include "../yoloHighPer/cpm.hpp"
    #include "../yoloHighPer/infer.hpp"
    #include "../yoloHighPer/yolo.hpp"#	include <dirent.h>
    #	include <sys/types.h>
    #	include <sys/stat.h>
    #	include <unistd.h>
    # include <stdarg.h>using namespace std;
    using namespace cv;#include OATPP_CODEGEN_BEGIN(ApiController) //<-- Begin Codegenstatic bool exists(const string& path){#ifdef _WIN32return ::PathFileExistsA(path.c_str());
    #elsereturn access(path.c_str(), R_OK) == 0;
    #endif
    }static std::vector<std::string> cocolabels = {"car", "excavator", "loader", "dumpTruck", "person"
    };class InferInstance{
    public:InferInstance(std::string onnx_model_path, std::string trt_model_path){onnx_model = onnx_model_path;trt_model = trt_model_path;startup();}bool startup(){// if(!exists(trt_model)){// 	SimpleYolo::compile(// 		SimpleYolo::Mode::FP32,                 // FP32、FP16、INT8// 		SimpleYolo::Type::V8, // 		1,            // max batch size// 		onnx_model,                  // source // 		trt_model,                   // save to// 		1 << 30,// 		"inference"// 	);// }infer_ = yolo::load(trt_model, yolo::Type::V8);return infer_ != nullptr;}int inference(const Mat& image_input, yolo::BoxArray& boxarray){if(infer_ == nullptr){// INFOE("Not Initialize.");return 1;}if(image_input.empty()){// INFOE("Image is empty.");return 1;}boxarray = infer_->forward(cvimg(image_input));return 0;}private:yolo::Image cvimg(const cv::Mat &image) { return yolo::Image(image.data, image.cols, image.rows);}private:std::string onnx_model = "best.onnx";std::string trt_model = "best.onnx.engine";shared_ptr<yolo::Infer> infer_;
    };///
    std::string onnx_model = "coco/best.onnx";
    std::string engine_label = "coco/best.onnx.engine";
    std::unique_ptr<InferInstance> infer_instance1(new InferInstance(onnx_model, engine_label));int frame_rate = 10;
    int track_buffer = 30;
    std::unique_ptr<BYTETracker> tracker_instance1(new BYTETracker(frame_rate, track_buffer));////*** 建议使用 Api 控制器,而不是使用裸 HttpRequestHandler 为每个新端点创建新的请求处理程序。* API 控制器通过为您生成样板代码,使添加新端点的过程变得更加容易。 它还有助于组织您的端点,* 将它们分组到不同的 API 控制器中。*//*** Sample Api Controller.*/
    class MyController : public oatpp::web::server::api::ApiController {
    protected:/*** Constructor with object mapper.* @param objectMapper - default object mapper used to serialize/deserialize DTOs.*/MyController(const std::shared_ptr<ObjectMapper>& objectMapper): oatpp::web::server::api::ApiController(objectMapper){}public:  static std::shared_ptr<MyController> createShared(OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)){return std::shared_ptr<MyController>(new MyController(objectMapper));}// TODO Insert Your endpoints here !!!/--data--// 多目标追踪ENDPOINT_ASYNC("POST", "/car1", tracker1){ENDPOINT_ASYNC_INIT(tracker1)Action act() override {return request->readBodyToStringAsync().callbackTo(&tracker1::returnResponse);}Action returnResponse(const oatpp::String& body_){auto response = tracker_inference(*infer_instance1, *tracker_instance1, body_, controller);return _return(response);}};//public:// 多目标追踪static std::shared_ptr<OutgoingResponse> tracker_inference(InferInstance& infer_, BYTETracker& track_infer, std::string body_, auto* controller){auto base64Image = base64_decode(body_);if(base64Image.empty()){return controller->createResponse(Status::CODE_400, "The image is empty!");}std::vector<char> base64_img(base64Image.begin(), base64Image.end());cv::Mat image = cv::imdecode(base64_img, 1);// 获取程序开始时间点auto start_time = std::chrono::high_resolution_clock::now();// 推理yolo::BoxArray boxarray;CV_Assert(0 == infer_.inference(image, boxarray));// 获取程序结束时间点auto end_time = std::chrono::high_resolution_clock::now();// 计算运行时间auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);// 打印运行时间(以微秒为单位)// std::cout << "程序运行时间: " << duration.count() << " 毫秒" << std::endl;// 结果处理vector<Objects> objects;objects.resize(boxarray.size());int index = 0;for(auto& box : boxarray) {objects[index].rect.x = box.left;;objects[index].rect.y = box.top;objects[index].rect.width = box.right - box.left;objects[index].rect.height = box.bottom - box.top;objects[index].prob = box.confidence;objects[index].label = box.class_label;index++;std::cout << "left: " << box.left << ", top: " << box.top<< ", right: " << box.right << ", bottom: " << box.bottom<< ", confidence: " << box.confidence << ", class_label: " << box.class_label << std::endl;}auto yoloDto = TrackYoloDto::createShared();auto boxList = TrackBoxList::createShared();std::vector<STrack> output_stracks = track_infer.update(objects);for (int i = 0; i < output_stracks.size(); i++){auto trackBoxDto = TrackerBboxes::createShared();vector<float> tlwh = output_stracks[i].tlwh; // 方框的位置trackBoxDto->class_id = cocolabels[output_stracks[i].class_id];trackBoxDto->track_id = output_stracks[i].track_id;trackBoxDto->x        = tlwh[0];trackBoxDto->y        = tlwh[1];trackBoxDto->width    = tlwh[2];trackBoxDto->height   = tlwh[3];boxList->push_back(trackBoxDto);}output_stracks.clear();yoloDto->data = boxList;yoloDto->status = "successful";yoloDto->time = currentDateTime();return controller->createDtoResponse(Status::CODE_200, yoloDto);}static std::string currentDateTime(){auto now = std::chrono::system_clock::now();auto now_c = std::chrono::system_clock::to_time_t(now);auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;std::stringstream ss;ss << std::put_time(std::localtime(&now_c), "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << now_ms.count();return ss.str();}static unsigned char from_b64(unsigned char ch){/* Inverse lookup map */static const unsigned char tab[128] = {255, 255, 255, 255,255, 255, 255, 255, /*  0 */255, 255, 255, 255,255, 255, 255, 255, /*  8 */255, 255, 255, 255,255, 255, 255, 255, /*  16 */255, 255, 255, 255,255, 255, 255, 255, /*  24 */255, 255, 255, 255,255, 255, 255, 255, /*  32 */255, 255, 255, 62,255, 255, 255, 63, /*  40 */52,  53,  54,  55,56,  57,  58,  59, /*  48 */60,  61,  255, 255,255, 200, 255, 255, /*  56   '=' is 200, on index 61 */255, 0,   1,   2,3,   4,   5,   6, /*  64 */7,   8,   9,   10,11,  12,  13,  14, /*  72 */15,  16,  17,  18,19,  20,  21,  22, /*  80 */23,  24,  25,  255,255, 255, 255, 255, /*  88 */255, 26,  27,  28,29,  30,  31,  32, /*  96 */33,  34,  35,  36,37,  38,  39,  40, /*  104 */41,  42,  43,  44,45,  46,  47,  48, /*  112 */49,  50,  51,  255,255, 255, 255, 255, /*  120 */};return tab[ch & 127];}static std::string base64_decode(const std::string& base64){if(base64.empty())return "";int len = base64.size();auto s = (const unsigned char*)base64.data();unsigned char a, b, c, d;int orig_len = len;int dec_len = 0;string out_data;auto end_s = s + base64.size();int count_eq = 0;while(*--end_s == '='){count_eq ++;}out_data.resize(len / 4 * 3 - count_eq);char *dst = const_cast<char*>(out_data.data());char *orig_dst = dst;while (len >= 4 && (a = from_b64(s[0])) != 255 &&(b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&(d = from_b64(s[3])) != 255) {s += 4;len -= 4;if (a == 200 || b == 200) break; /* '=' can't be there */*dst++ = a << 2 | b >> 4;if (c == 200) break;*dst++ = b << 4 | c >> 2;if (d == 200) break;*dst++ = c << 6 | d;}dec_len = (dst - orig_dst);// dec_len必定等于out_data.size()return out_data;}
    };#include OATPP_CODEGEN_END(ApiController) //<-- End Codegen#endif /* MyController_hpp */
  • 启动模型
    在这里插入图片描述
  • 请求接口进行推理

yolov8 模型部署测试

相关文章:

yolov8 模型部署--TensorRT部署-c++服务化部署

写目录 yolov8 模型部署--TensorRT部署1、模型导出为onnx格式2、模型onnx格式转engine 部署 yolov8 模型部署–TensorRT部署 1、模型导出为onnx格式 如果要用TensorRT部署YOLOv8&#xff0c;需要先使用下面的命令将模型导出为onnx格式&#xff1a; yolo export modelyolov8n.p…...

自适应迭代扩展卡尔曼滤波算法AIEKF估计SOC VS 扩展卡尔曼估计SOC

自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09; 自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09;是一种滤波算法&#xff0c;其目的是通过迭代过程来逐渐适应不同的状态和环境&#xff0c;从而优化滤波效果。 该算法的基本思路是在每一步迭代过程中&a…...

2023-亲测有效-git clone失败怎么办?用代理?加git?

git 克隆不下来&#xff0c;超时 用以下格式&#xff1a; git clone https://ghproxy.com/https://github.com/Tencent/ncnn.git 你的网站前面加上 https://ghproxy.com/ 刷的一下就下完了&#xff01;&#xff01;...

An Empirical Study of GPT-3 for Few-Shot Knowledge-Based VQA

本文是LLM系列文章&#xff0c;针对《An Empirical Study of GPT-3 for Few-Shot Knowledge-Based VQA》的翻译。 GPT-3对基于小样本知识的VQA的实证研究 摘要引言相关工作方法OK-VQA上的实验VQAv2上的实验结论 摘要 基于知识的视觉问答&#xff08;VQA&#xff09;涉及回答需…...

2023高教社杯数学建模B题思路分析 - 多波束测线问题

# 1 赛题 B 题 多波束测线问题 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀 速直线传播&#xff0c; 在不同界面上产生反射&#xff0c; 利用这一原理&#xff0c;从测量船换能器垂直向海底发射声波信 号&#xff0c;并记录从声波发射到…...

02-docker network

Docker网络 Docker网络是什么 Docker 网络是 Docker 容器之间进行通信和连接的网络环境。在 Docker 中&#xff0c;每个容器都有自己的网络命名空间&#xff0c;这意味着每个容器都有自己的网络接口、IP 地址和网络配置 Docker网络启动后&#xff0c;会在宿主机中建立一个名…...

栈和队列经典笔试题

文章目录 栈和队列的回顾&#x1f4bb;栈&#x1fa73;队列&#x1f45f; 栈和队列经典笔试题&#x1f50b;有效的括号&#x1f3b8;用队列实现栈 &#x1f56f;用栈实现队列&#x1f52d;设计循环队列&#x1f9fc; 安静的夜晚 你在想谁吗 栈和队列的回顾&#x1f4bb; 栈&am…...

No5.9:多边形内角和公式

#!/usr/bin/python # -*- coding: UTF-8 -*-#指定了编码&#xff0c;中文就能正常展示 # codingutf-8def calc_degree(n):#n代表边形的总数degree (n - 2) * 180#多边形内角和公式return degreeprint(calc_degree(3))#三角形的内角和 print(calc_degree(4))#四边形的内角和【小…...

EditPlus 配置python 及Anaconda中的python

若不是pycharm vscode 太大&#xff0c;太占内存&#xff0c;谁会想到用Notepad&#xff0c;EdirPlus 配置python呢&#xff01;&#xff01;&#xff01; 话不多说&#xff0c;首先你自己安装好EditPlus。开始 菜单栏 选择 工具 -> 配置自定义工具 组名:python 命令:d:\*…...

linux 编译 llvm + clang

1. 需要下载以下三个压缩包&#xff0c;下载源码&#xff1a;Release LLVM 15.0.7 llvm/llvm-project GitHub clang-15.0.7.src.tar.xzcmake-15.0.7.src.tar.xzllvm-15.0.7.src.tar.xz​​​​​ 2. 解压后将 clang 源码放入 llvm/tools/ 下 3. 将解压后的 cmake-15.0.7…...

Mybatis 框架 ( 四 ) QueryWrapper

4.5.Wrapper条件构造器 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper &#xff1a; Entity 对象封装操作类&#xff0c;不是用lambda语法 UpdateWrapper &am…...

数据结构和算法之二分法查找

二分法查找&#xff0c;也称作二分查找或折半查找&#xff0c;是一种在有序数组中快速查找特定元素的算法。它采用分治法思想&#xff0c;通过将问题划分为规模更小的子问题&#xff0c;并且通过对子问题的查找来解决原问题。 二分法查找的思路是不断地将数组一分为二&#xf…...

系统日期如何在页面展示,框架是react或者vue3

安装插件dayjs或者moment.js 2.使用setInterval&#xff08;useInterval&#xff09;或者requestAnimationFrame react项目中useInterval的代码示例&#xff1a; import React, {useState } from react; import { useInterval } from "ahooks"; import moment fro…...

(二十二)大数据实战——Flume数据采集之故障转移案例实战

前言 本节内容我们完成Flume数据采集的故障转移案例&#xff0c;使用三台服务器&#xff0c;一台服务器负责采集nc数据&#xff0c;通过使用failover模式的Sink处理器完成监控数据的故障转移&#xff0c;使用Avro的方式完成flume之间采集数据的传输。整体架构如下&#xff1a;…...

前端小案例3:Flex弹性布局行内元素宽度自适应

前端小案例3&#xff1a;Flex弹性布局行内元素宽度自适应 项目背景&#xff1a;需要在一行上展示空调设备的三个模式&#xff08;制冷、制热、通风&#xff09;或者两个模式&#xff08;制冷、制热&#xff09;&#xff1b;因为不同产品的模式数量不同&#xff0c;因此需要让模…...

纳尼?小说还要用看的?这可以听!无广!

这是一款听书软件&#xff0c;可以自定义书源&#xff0c;自己设置书架&#xff0c;页面简单易操作&#xff0c;无广告。 支持直接搜索书名&#xff0c;链接&#xff0c;图文&#xff0c;本地文件等方式听书 拥有30多主播声音&#xff0c;分类细致 支持倍速、添加BGM等...

【微服务部署】四、Jenkins一键打包部署NodeJS(Vue)前端项目步骤详解

本文介绍使用Jenkins一键将NodeJS&#xff08;Vue&#xff09;前端项目打包并上传到生产环境服务器&#xff0c;这里使用的是直接打包静态页面&#xff0c;发送到远程服务器Nginx配置目录的方式&#xff0c;首先确保服务器环境配置好&#xff0c;安装Nginx&#xff0c;运行目录…...

【前端】禁止别人调试自己的前端页面代码

无限debugger 前端页面防止调试的方法主要是通过不断 debugger 来疯狂输出断点&#xff0c;因为 debugger 在控制台被打开的时候就会执行由于程序被 debugger 阻止&#xff0c;所以无法进行断点调试&#xff0c;所以网页的请求也是看不到的代码如下&#xff1a; /** * 基础禁止…...

UDP的可靠性传输

UDP系列文章目录 第一章 UDP的可靠性传输-理论篇&#xff08;一&#xff09; 第二章 UDP的可靠性传输-理论篇&#xff08;二&#xff09; 文章目录 UDP系列文章目录前言1.TCP 和UDP格式对比2.UDP分片原理3.UDP 传输层应该注意问题4.MTU5.UDP 分片机制设计重点 一、ARQ协议什么…...

科研笔记:TPAMI submission guideline

1 author information Author Information - IEEE Transactions on Pattern Analysis and Machine Intelligence | IEEE Computer Society Digital Library 1.1 会议期刊extension 当一个TPAMI的提交基于之前的会议论文时&#xff0c;IEEE要求期刊论文是之前出版物的“实质…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...