YOLOv8-Openvino和ONNXRuntime推理【CPU】

1 环境:

CPU:i5-12500

2 安装Openvino和ONNXRuntime

2.1 Openvino简介

Openvino是由Intel开发的专门用于优化和部署人工智能推理的半开源的工具包,主要用于对深度推理做优化。

Openvino内部集成了Opencv、TensorFlow模块,除此之外它还具有强大的Plugin开发框架,允许开发者在Openvino之上对推理过程做优化。

Openvino整体框架为:Openvino前端→ Plugin中间层→ Backend后端
Openvino的优点在于它屏蔽了后端接口,提供了统一操作的前端API,开发者可以无需关心后端的实现,例如后端可以是TensorFlow、Keras、ARM-NN,通过Plugin提供给前端接口调用,也就意味着一套代码在Openvino之上可以运行在多个推理引擎之上,Openvino像是类似聚合一样的开发包。

2.2 ONNXRuntime简介

ONNXRuntime是微软推出的一款推理框架,用户可以非常便利的用其运行一个onnx模型。ONNXRuntime支持多种运行后端包括CPU,GPU,TensorRT,DML等。可以说ONNXRuntime是对ONNX模型最原生的支持。

虽然大家用ONNX时更多的是作为一个中间表示,从pytorch转到onnx后直接喂到TensorRT或MNN等各种后端框架,但这并不能否认ONNXRuntime是一款非常优秀的推理框架。而且由于其自身只包含推理功能(最新的ONNXRuntime甚至已经可以训练),通过阅读其源码可以解深度学习框架的一些核心功能原理(op注册,内存管理,运行逻辑等)
总体来看,整个ONNXRuntime的运行可以分为三个阶段,Session构造,模型加载与初始化和运行。和其他所有主流框架相同,ONNXRuntime最常用的语言是python,而实际负责执行框架运行的则是C++。

2.3 安装

pip install openvino -i  https://pypi.tuna.tsinghua.edu.cn/simple
pip install onnxruntime -i  https://pypi.tuna.tsinghua.edu.cn/simple

3 准备YOLOv8s.onnx文件

YOLOv8官网
.pt文件转.onnx文件示例代码【注意自己转需要安装YOLOv8的环境】:

from ultralytics import YOLO
model = YOLO("yolov8s.pt")  # load a pretrained model
path = model.export(format="onnx", dynamic=True)  # export the mode l to ONNX format

4 Openvino和ONNXRuntime推理脚本

4.1 预处理

注:其中pad部分去除能减少预处理时间,且推理精度几乎一致。

def preprocess(image, img_h, img_w):'''Yolo系列算法通用预处理'''image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)scale = max(image.shape[0] / img_h, image.shape[1] / img_w)image = cv2.resize(image, (int(image.shape[1] / scale), int(image.shape[0] / scale)))wpad = img_w - image.shape[1]hpad = img_h - image.shape[0]image_pad = np.ones((image.shape[0]+hpad, image.shape[1]+wpad, 3)) * 114.0image_pad[:image.shape[0], :image.shape[1], :] = imageimage_array = image_padimage_array = image_array / 255.0image_array = image_array.transpose((2, 0, 1))image_array = image_array.astype(np.float32)input_array = np.ascontiguousarray(np.expand_dims(image_array, 0))return input_array, scale, image.shape[0], image.shape[1]

4.2 后处理

注:尝试多种后处理写法,该种写法速度最快。

def postprocess(pred, conf_thres, iou_thres, img_w, img_h):"""Args:pred: np.array([(x, y, w, h, cls1_conf, cls2_conf, cls3_conf, ...), ...]), shape=(-1, 4 + num_cls)conf_thres: 置信度阈值iou_thres: IOU阀值,若两个box的交并比大于该值,则置信度较小的box将会被抑制img_w: 原图w大小img_h: 原图h大小Returns:out: 经过NMS后的值,np.array([(x, y, w, h, conf, cls), ...]), shape=(-1, 4 + 1 + 1)"""pred = np.squeeze(pred).transpose((1, 0))  # (1, 80+4, -1) -> (80+4, -1) -> (-1, 80+4)# 按置信度过滤conf = np.max(pred[..., 4:], axis=-1)mask = conf >= conf_thres# Where the score larger than score_thresholdbox = pred[mask][..., :4]confidences = conf[mask]clsid = np.argmax(pred[mask][..., 4:], axis=1)  # 下面进行非极大抑制NMS处理# 对box进行转换,以及对不同类别分不同区间处理bounding_boxes = np.zeros_like(box)bounding_boxes[:, 0] = (box[:, 0] - box[:, 2] / 2) + clsid * img_w  # xmin + 每个类别分不同区间bounding_boxes[:, 1] = (box[:, 1] - box[:, 3] / 2) + clsid * img_h  # ymin + 每个类别分不同区间bounding_boxes[:, 2] = box[:, 2]  # wbounding_boxes[:, 3] = box[:, 3]  # h# xywh2xyxybounding_boxes[:, 2] += bounding_boxes[:, 0]bounding_boxes[:, 3] += bounding_boxes[:, 1]if bounding_boxes.shape[0] != confidences.shape[0]:raise ValueError("Bounding box 与 Confidence 的数量不一致")if bounding_boxes.shape[0] == 0:return []bounding_boxes, confidences = bounding_boxes.astype(np.float32), np.array(confidences)x1, y1, x2, y2 = bounding_boxes[:, 0], bounding_boxes[:, 1], bounding_boxes[:, 2], bounding_boxes[:, 3]areas = (x2 - x1 + 1) * (y2 - y1 + 1)idxs = np.argsort(confidences)pick = []while len(idxs) > 0:# 因为idxs是从小到大排列的,last_idx相当于idxs最后一个位置的索引last_idx = len(idxs) - 1# 取出最大值在数组上的索引max_value_idx = idxs[last_idx]# 将这个添加到相应索引上pick.append(max_value_idx)xx1 = np.maximum(x1[max_value_idx], x1[idxs[: last_idx]])yy1 = np.maximum(y1[max_value_idx], y1[idxs[: last_idx]])xx2 = np.minimum(x2[max_value_idx], x2[idxs[: last_idx]])yy2 = np.minimum(y2[max_value_idx], y2[idxs[: last_idx]])w, h = np.maximum(0, xx2 - xx1 + 1), np.maximum(0, yy2 - yy1 + 1)iou = w * h / areas[idxs[: last_idx]]# 删除最大的value,并且删除iou > threshold的bounding boxesidxs = np.delete(idxs, np.concatenate(([last_idx], np.where(iou > iou_thres)[0])))out = np.concatenate([box[pick], confidences[pick].reshape(-1, 1), clsid[pick].reshape(-1, 1)], axis=1)return out

4.3 全部代码

import os
import time# openvino速度比onnxruntime快一倍
from openvino.runtime import Core  # pip install openvino -i  https://pypi.tuna.tsinghua.edu.cn/simple
import onnxruntime as rt  # 使用onnxruntime推理用上,pip install onnxruntime
import numpy as np
import cv2def preprocess(image, img_h, img_w):'''Yolo系列算法通用预处理'''image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)scale = max(image.shape[0] / img_h, image.shape[1] / img_w)image = cv2.resize(image, (int(image.shape[1] / scale), int(image.shape[0] / scale)))wpad = img_w - image.shape[1]hpad = img_h - image.shape[0]image_pad = np.ones((image.shape[0]+hpad, image.shape[1]+wpad, 3)) * 114.0image_pad[:image.shape[0], :image.shape[1], :] = imageimage_array = image_padimage_array = image_array / 255.0image_array = image_array.transpose((2, 0, 1))image_array = image_array.astype(np.float32)input_array = np.ascontiguousarray(np.expand_dims(image_array, 0))return input_array, scale, image.shape[0], image.shape[1]def postprocess(pred, conf_thres, iou_thres, img_w, img_h):"""Args:pred: np.array([(x, y, w, h, cls1_conf, cls2_conf, cls3_conf, ...), ...]), shape=(-1, 4 + num_cls)conf_thres: 置信度阈值iou_thres: IOU阀值,若两个box的交并比大于该值,则置信度较小的box将会被抑制img_w: 原图w大小img_h: 原图h大小Returns:out: 经过NMS后的值,np.array([(x, y, w, h, conf, cls), ...]), shape=(-1, 4 + 1 + 1)"""pred = np.squeeze(pred).transpose((1, 0))  # (1, 80+4, -1) -> (80+4, -1) -> (-1, 80+4)# 按置信度过滤conf = np.max(pred[..., 4:], axis=-1)mask = conf >= conf_thres# Where the score larger than score_thresholdbox = pred[mask][..., :4]confidences = conf[mask]clsid = np.argmax(pred[mask][..., 4:], axis=1)  # 下面进行非极大抑制NMS处理# 对box进行转换,以及对不同类别分不同区间处理bounding_boxes = np.zeros_like(box)bounding_boxes[:, 0] = (box[:, 0] - box[:, 2] / 2) + clsid * img_w  # xmin + 每个类别分不同区间bounding_boxes[:, 1] = (box[:, 1] - box[:, 3] / 2) + clsid * img_h  # ymin + 每个类别分不同区间bounding_boxes[:, 2] = box[:, 2]  # wbounding_boxes[:, 3] = box[:, 3]  # h# xywh2xyxybounding_boxes[:, 2] += bounding_boxes[:, 0]bounding_boxes[:, 3] += bounding_boxes[:, 1]if bounding_boxes.shape[0] != confidences.shape[0]:raise ValueError("Bounding box 与 Confidence 的数量不一致")if bounding_boxes.shape[0] == 0:return []bounding_boxes, confidences = bounding_boxes.astype(np.float32), np.array(confidences)x1, y1, x2, y2 = bounding_boxes[:, 0], bounding_boxes[:, 1], bounding_boxes[:, 2], bounding_boxes[:, 3]areas = (x2 - x1 + 1) * (y2 - y1 + 1)idxs = np.argsort(confidences)pick = []while len(idxs) > 0:# 因为idxs是从小到大排列的,last_idx相当于idxs最后一个位置的索引last_idx = len(idxs) - 1# 取出最大值在数组上的索引max_value_idx = idxs[last_idx]# 将这个添加到相应索引上pick.append(max_value_idx)xx1 = np.maximum(x1[max_value_idx], x1[idxs[: last_idx]])yy1 = np.maximum(y1[max_value_idx], y1[idxs[: last_idx]])xx2 = np.minimum(x2[max_value_idx], x2[idxs[: last_idx]])yy2 = np.minimum(y2[max_value_idx], y2[idxs[: last_idx]])w, h = np.maximum(0, xx2 - xx1 + 1), np.maximum(0, yy2 - yy1 + 1)iou = w * h / areas[idxs[: last_idx]]# 删除最大的value,并且删除iou > threshold的bounding boxesidxs = np.delete(idxs, np.concatenate(([last_idx], np.where(iou > iou_thres)[0])))out = np.concatenate([box[pick], confidences[pick].reshape(-1, 1), clsid[pick].reshape(-1, 1)], axis=1)return outdef draw(img, xscale, yscale, pred, color=(255, 0, 0), tmp=True):img_ = img.copy()if len(pred):for detect in pred:caption = str('{:.2f}_{}'.format(detect[4], int(detect[5])))detect = [int((detect[0] - detect[2] / 2) * xscale), int((detect[1] - detect[3] / 2) * yscale),int((detect[0] + detect[2] / 2) * xscale), int((detect[1] + detect[3] / 2) * yscale)]img_ = cv2.rectangle(img, (detect[0], detect[1]), (detect[2], detect[3]), color, 2)# 是否显示置信度类别if tmp:cv2.putText(img, caption, (detect[0], detect[1] - 5), 0, 1, color, 2, 16)return img_class OpenvinoInference(object):def __init__(self, onnx_path):self.onnx_path = onnx_pathie = Core()self.model_onnx = ie.read_model(model=self.onnx_path)self.compiled_model_onnx = ie.compile_model(model=self.model_onnx, device_name="CPU")self.output_layer_onnx = self.compiled_model_onnx.output(0)def predirts(self, datas):predict_data = self.compiled_model_onnx([datas])[self.output_layer_onnx]return predict_dataif __name__ == '__main__':height, width = 640, 640  # 修改1:图像resize大小conf, nms_iou = 0.15, 0.6  # 修改2:置信度阈值与nms的iou阈值openvino_tmp = True  # 修改3:是否进行openvino推理,False为onnxruntime推理onnx_path = 'D:\\C++\\yolov8s.onnx'  # 修改4:onnx文件路径input_path = 'D:\\C++\\bus.jpg'  # 修改5:原图路径output_path = 'D:\\C++\\out.jpg'  # 修改6:图像保存路径img = cv2.imread(input_path)if openvino_tmp:model = OpenvinoInference(onnx_path)else:sess = rt.InferenceSession(onnx_path)t1 = time.time()data, scale, img_w, img_h = preprocess(img, height, width)  # resize_imgprint('预处理时间:{:.3f}s'.format(time.time() - t1))t2 = time.time()if openvino_tmp:pred = model.predirts(data)else:input_name = sess.get_inputs()[0].namelabel_name = sess.get_outputs()[0].namepred = sess.run([label_name], {input_name: data.astype(np.float32)})[0]print('推理时间:{:.3f}s'.format(time.time() - t2))t3 = time.time()result = postprocess(pred, conf, nms_iou, img_w, img_h)print('后处理时间:{:.3f}s'.format(time.time() - t3))ret_img = draw(img, scale, scale, result, color=(0, 255, 0), tmp=True)cv2.imwrite(output_path, ret_img)      

5 结果

在这里插入图片描述

具体时间消耗:

预处理时间:0.014s(预处理无Pad为0.007s)
推理时间:0.08s
后处理时间:0.001s
注:640×640下,Openvino和ONNXRuntime推理速度相差不大,1280×1280下,Openvino速度更快。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/691461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端|Day3:CSS基础(黑马笔记)

Day3:CSS基础 目录 Day3:CSS基础一、CSS初体验二、CSS引入方式三、选择器1.标签选择器2.类选择器3.id选择器4.通配符选择器 四、盒子尺寸和背景色五、文字控制属性1.字体大小2.字体样式(是否倾斜)3.行高单行文字垂直居中 4.字体族5.font复合属性6.文本缩…

【JAVA】《接口,抽象方法,抽象类 》之三 、抽象类详解

抽象类 详解 一、接口二、抽象方法三、抽象类3.1、抽象类的概念3.2、抽象类的特点:3.3、抽象类的作用:3.4、抽象类的应用:3.5、抽象类的注意事项: 一、接口 1.1、接口的概念 1.2、接口的作用: 1.3、接口应用&#xff…

自适应网站建站源码系统 带完整的安装代码包以及搭建教程

在当今数字化时代,拥有一个功能全面且能够适应不同设备的网站对于企业和个人来说至关重要。罗峰给大家分享一款全新的自适应网站建站源码系统,它不仅提供了完整的安装代码包,还附带了详细的搭建教程,帮助用户轻松构建出具有响应式…

Atcoder ABC340 C - Divide and Divide

Divide and Divide(分而治之) 时间限制:2s 内存限制:1024MB 【原题地址】 所有图片源自Atcoder,题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【样例…

Windows制作Ubuntu的U盘启动盘

概要: 本篇演示在Windows10中制作Ubuntu22.04的U盘启动盘 一、下载Ubuntu22.04的iso文件 在浏览器中输入https://ubuntu.com去Ubuntu官网下载Ubuntu22.04的iso文件 二、下载Ultraiso 在浏览器中输入https://www.ultraiso.com进入ultraiso官网 点击FREE TRIAL&a…

编程笔记 html5cssjs 085 JavaScript 内置函数

编程笔记 html5&css&js 085 JavaScript 内置函数 一、内置函数二、内置对象三、函数和方法之间的区别 内置函数是JavaScript语言本身提供的,无需定义即可直接使用的函数。它们在全局作用域中可用,并且在处理常见任务时提供了便利。 一、内置函数…

com.alibaba.fastjson.JSONException: toJSON error的原因

问题: 导出接口报错,显示json格式化异常 发现问题: 第一个参数为HttpResponse,转换成json的时候报错 修改方法: 1.调换两个参数的位置 2.在aop判断里边 把ServletAPI过滤掉 Before("excudeWebController()")pub…

洛谷C++简单题小练习day12—寻找最小值小程序

day12--寻找最小值--2.16 习题概述 题目描述 给出 n 和 n 个整数 ai​,求这 n 个整数中最小值是什么。 输入格式 第一行输入一个正整数 n,表示数字个数。 第二行输入 n 个非负整数,表示 1,2…a1​,a2​…an​,以空格隔开。 …

【医学大模型 补全主诉】BioGPT + LSTM 自动补全医院紧急部门主诉

BioGPT LSTM 自动补全医院紧急部门主诉 问题:针对在紧急部门中自动补全主诉的问题子问题1: 提高主诉记录的准确性子问题2: 加快主诉记录的速度子问题3: 统一医疗术语的使用子问题4: 减少打字错误和误解子问题5: 提高非特定主诉的处理能力 解法数据预处理神经网络方…

【软考问题】-- 3 - IT知识 - 信息系统治理

一、基础问题 问题1:IT治理主要目标包括哪三个方面? 1⃣️与业务目标一致2⃣️有效利用信息与数据资源3⃣️风险管理问题2:IT治理的管理层次大致可分为三层是什么? (1)最高管理层(2)执行管理层(3)业务与服务执行层问题3:IT 治理和谐内容有哪些? a.组织职责

力扣145 二叉树的后序遍历 Java版本

文章目录 题目描述递归解法代码 非递归解法思路代码 题目描述 给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。 示例 1: 输入:root [1,null,2,3] 输出:[3,2,1] 示例 2: 输入:root [] 输出…

设计模式(六):模板方法模式(行为型模式)

Template Method,模板方法:定义一个操作中的算法的骨架,而将一 些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即 可以重定义该算法得某些特定步骤。 举例说明 奶茶制作过程,第一步加牛奶&…

计算机就业初调研

对于一个本科生而言,早早就收获了保研资格,那么摆在眼前的就是是否要放弃保研机会?不过看到当今计算机的就业情况,加上本科学历的贬值,想要放弃到手的保研机会,既有些不合理,也有些心疼&#xf…

Linux【动静态库】

目录 1.软硬链接 1.1软硬链接的语法 1.2理解软硬链接 1.3目录文件的硬链接 1.4应用场景 1.5ACM时间 2.动静态库 2.1认识库 3.制作静态库 3.1静态库打包 3.2静态库的使用 4.制作动态库 4.1动态库打包 4.2动态库的链接使用 4.3动态库的链接原理 总结&#xff1…

论文阅读-基于动态权重的一致性哈希微服务负载均衡优化

论文名称:基于动态权重的一致性哈希微服务负载均衡优化 摘要 随着互联网技术的发展,互联网服务器集群的负载能力正面临前所未有的挑战。在这样的背景下,实现合理的负载均衡策略变得尤为重要。为了达到最佳的效率,可以利用一致性…

Dell PowerEdge服务器的iDRAC修复方法与步骤

最近老旧的Dell PowerEdge R720xd服务器罢工了,经检查发现是iDRAC电脑坏了。 iDRAC是戴尔服务器系列中的一种远程管理功能,它允许用户通过网络远程监控和管理戴尔服务器,即使在服务器关机或操作系统崩溃的情况下也可以进行远程管理。主要包括…

【Crypto | CTF】RSA打法 集合

天命:我发现题题不一样,已知跟求知的需求都不一样 题目一:已知 p q E ,计算T,最后求D 已知两个质数p q 和 公钥E ,通过p和q计算出欧拉函数T,最后求私钥D 【密码学 | CTF】BUUCTF RSA-CSDN…

【数据结构】每天五分钟,快速入门数据结构(一)——数组

目录 一.初始化语法 二.特点 三.数组中的元素默认值 四.时间复杂度 五.Java中的ArrayList类 可变长度数组 1 使用 2 注意事项 3 实现原理 4 ArrayList源码 5 ArrayList方法 一.初始化语法 // 数组动态初始化(先定义数组,指定数组长度&#xf…

AUTOSAR CP--chapter7从CAN网络学习Autosar通信

从CAN网络学习Autosar通信 前言缩写词CAN通信在AUTOSAR架构中的传输上位机配置 第六章总结:学习了如何使用工具的自动配置功能,位我们生成系统描述中部分ecu的BSW模块配置,但是自动配置的功能虽然为我们提供了极大的便利,我们仍然…

rtt的io设备框架面向对象学习-软件模拟rtc设备

目录 1.软件rtc设备实现类2.软件rtc设备类的子类3.初始化/构造流程3.1 设备驱动框架层3.3 设备io管理层 4.总结5.使用 硬件rtc和软件rtc设备是互斥的。因为它们的名字都叫"rtc",在对象容器中不允许重名。 软件rtc设备比较特殊,不依赖于任何硬件…