windows10+CPU基于openVINO高速部署yolov5

通常,我们部署yolo系列的模型,都是以GPU或者其他专用的NPU硬件作为部署平台,进行模型加速。如果我们手头没有合适的硬件平台,但是,我们由于实时推理的需求的时候,那么,使用OpenVINO进行部署是我们可以选择的方案之一,也是首选。下面,将详细介绍,部署流程和细节。
部署相关的模型、代码资料均已上传,下载地址
我的部署硬件环境和系统环境如下:
在这里插入图片描述
在这里插入图片描述

一、OpenVINO

OpenVINO(Open Visual Inference and Neural Network Optimization)是英特尔推出的一款开源工具套件,旨在优化和部署深度学习模型,支持从云端到边缘的高效推理。它通过兼容主流框架(如TensorFlow、PyTorch、ONNX等)的模型转换工具,提供模型优化、量化和压缩等功能,加速深度学习推理。OpenVINO支持多种英特尔硬件(如CPU、GPU、FPGA等),并提供丰富的工具和API,帮助开发者轻松实现跨平台部署,提升应用性能。

二、yoloV5

YOLOv5是一种先进的单阶段目标检测算法,由Ultralytics团队开发,是YOLO(You Only Look Once)系列第一个大规模工业落地的版本。YOLOv5在速度和准确性上均有显著提升,采用创新的网络架构和优化策略,支持快速实时检测,适用于智能交通、工业检测、农业监控等广泛领域。其轻量化设计和多版本(如YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x)满足不同场景需求,尤其适合对推理速度和计算资源有限制的应用。YOLOv5凭借高效简洁的设计,成为目标检测任务中的首选模型之一。
在这次部署实验中,我们采用yolov5s进行部署实验。

三、OpenVINO的C++环境配置

请参考我的另外一篇博文,VS2022+OpenVINO的开发环境配置

四、模型部署

4.1 部署流程

部署流程主要包含模型转化、模型加载、前后处理等步骤,流程示意图如下:
在这里插入图片描述

4.2 转onnx

使用yolov5的export.py脚本,导出yolov5s的onnx模型即可。

4.3 模型加载

创建openVINO的运行对话对象,加载模型,并创建模型对应的前后处理对象。

ov::Core core;
//1、导入模型
std::shared_ptr<ov::Model> model = core.read_model("./model/yolov5s.onnx");
//2、创建模型的前后处理器
ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(model);

4.4 预处理

预处理主要是完成输入图像的尺寸缩放和补边,还有数值归一化。代码如下:

//3、设定模型输入的图像格式为NHWC的U8,颜色顺序为BGR
ppp.input().tensor().set_element_type(ov::element::u8).set_layout("NHWC").set_color_format(ov::preprocess::ColorFormat::BGR);
//4、设定预处理管道:先进行浮点化处理、再调换BGR为RGB、最归一化到0-1之间
ppp.input().preprocess().convert_element_type(ov::element::f32).convert_color(ov::preprocess::ColorFormat::RGB).scale({ 255., 255., 255. });
	

4.5 输出

设定输出的数据格式和数据类型。

//5、设定模型的输入格式为NCHW
ppp.input().model().set_layout("NCHW");
//6、设定模型的输出为浮点数
ppp.output().tensor().set_element_type(ov::element::f32);

4.6 模型推理

OpenVINO的模型推理就简单的两行代码。

	//推理
	ov::InferRequest infer_request = mCompiledModel.create_infer_request();
	infer_request.set_input_tensor(input_tensor);
	infer_request.infer();

4.6 后处理

后处理主要是从模型的输出解析出目标检测结果,以及,进行非极大值抑制处理(NMS)。NMS的主要作用是去除与当前边界框重叠度较高的边界框,保留最可能正确的边界框。通过抑制与当前边界框重叠度较高的边界框,可以有效减少冗余检测框,提高检测效率的同时也提升了检测的准确性。在这里,我们之间调用opencv的dnn模块提供的API进行实现。

const ov::Tensor& output_tensor = infer_request.get_output_tensor();
ov::Shape output_shape = output_tensor.get_shape();
float* detections = output_tensor.data<float>();
std::vector<cv::Rect> boxes;
std::vector<int> class_ids;
std::vector<float> confidences;
//系数倒数
float normal_scale = 1.0f / scale;
//边界
cv::Rect frm_box(0, 0, frame.cols, frame.rows);
for (int i = 0; i < output_shape[1]; i++)//遍历所有框
{
	float* detection = &detections[i * output_shape[2]];//bbox(x y w h obj cls)

	float confidence = detection[4];//当前bbox的obj
	if (confidence >= 0.25) //判断是否为前景
	{
		float* classes_scores = &detection[5];
		cv::Mat scores(1, output_shape[2] - 5, CV_32FC1, classes_scores);
		cv::Point class_id;
		double max_class_score;
		cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id);//返回最大得分和最大类别

		if (max_class_score * confidence > confi_thr)//满足得分
		{
			float x = detection[0] * normal_scale;
			float y = detection[1] * normal_scale;
			float w = detection[2] * normal_scale;
			float h = detection[3] * normal_scale;
			float xmin = x - (w / 2);
			float ymin = y - (h / 2);
			//越界目标
			cv::Rect box = frm_box & cv::Rect(xmin, ymin, w, h);
			//极小目标不可信
			if (cv::min(box.width, box.height) > 5)
			{
				boxes.push_back(box);
				confidences.push_back(confidence);
				class_ids.push_back(class_id.x);
			}
		}
	}
}

std::vector<int> nms_result;
cv::dnn::NMSBoxes(boxes, confidences, 0.25, nms_thr, nms_result);
std::vector<TargetInfo> output;
for (int i = 0; i < nms_result.size(); i++)
{
	TargetInfo result;
	int idx = nms_result[i];
	result.cls = class_ids[idx];
	result.score = confidences[idx];
	result.box = boxes[idx];
	output.push_back(result);
}
return output;

五、接口封装

为方便后续使用,将OpenVINO部署yolov5进行类封装,可以对任意尺寸的图像进行推理。接口设计如下:

#ifndef DETECTOR_H
#define DETECTOR_H
#include <string>
#include "opencv2/opencv.hpp"
#include "openvino/openvino.hpp"
#include "utils.h"

class Detector
{
public:
    Detector();
    virtual ~Detector();
    void initialize(const std::string& model_path);
    std::vector<TargetInfo> run(cv::Mat& frame, const float& confi_thr = 0.25f, const float& nms_thr = 0.4f);
private:
    ov::CompiledModel mCompiledModel;
};

#endif // DETECTOR_H

六、测试

编写一个简单的测试代码,读取一幅图像,进行100次推理,打印耗时,以及绘制检测结果。

cv::Mat input_image = cv::imread("test.png", cv::IMREAD_COLOR);
Detector detector;
detector.initialize("./model/yolov5s.onnx");
std::vector<TargetInfo> result;
for (int j = 0; j < 100; j++)
{
	int64 start_time = cv::getTickCount();
	result = detector.run(input_image);
	int64 end_time = cv::getTickCount();
	printf("cost time:%f ms\n", (end_time - start_time) / (float)cv::getTickFrequency() * 1000.0f);
}

for (int i = 0; i < result.size(); i++)
{
	cv::rectangle(input_image, result[i].box, cv::Scalar(0, 255, 0), 2);
}
cv::imshow("openvino", input_image);
cv::waitKey();
return 0;

在这里插入图片描述

7、小结

在我的电脑配置下,640*640的yolov5s模型使用OpenVINO进行部署后,无任何的量化、剪枝操作,推理耗时在60ms左右,基本达到了预期。后续,将测试OpenVINO的量化部署,进一步减少耗时,达到真正地实时运行推理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深图智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值