【OpenVINO™】YOLOv10在CPU上也能实现50+FPS推理—利用OpenVINO C++部署YO
英特尔发行版 OpenVINO™ 工具套件基于 oneAPI 而开辟,可以加速高性能计算机视觉和深度学习视觉应用开辟速度工具套件,适用于从边沿到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界结果部署到生产系统中。YOLOv10是清华大学研究人员近期提出的一种实时目标检测方法,通过消除NMS、优化模型架构和引入创新模块等策略,在保持高精度的同时显著降低了计算开销,为实时目标检测领域带来了新的突破。在本文中,我们将演示如何利用Intel OpenVINO™ C++ API 部署YOLOv10目标检测模型,并利用 OpenVINO™ 异步推理接口实现模型推理加速。下面看一下YOLOv10模型在OpenVINO™上的运行效果吧:
【B站】YOLOv10在CPU上也能轻松实现50+FPS推理—利用OpenVINO C++部署YOLOv10实现异步推理
1. 前言
英特尔发行版 OpenVINO™ 工具套件基于 oneAPI 而开辟,可以加速高性能计算机视觉和深度学习视觉应用开辟速度工具套件,适用于从边沿到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界结果部署到生产系统中。通过简化的开辟工作流程,OpenVINO™ 可赋能开辟者在实际世界中部署高性能应用程序和算法。
https://img2024.cnblogs.com/blog/2933426/202407/2933426-20240704191341519-1563081337.png
2024年4月25日,英特尔发布了开源 OpenVINO™ 2024.1 工具包,用于在各种硬件上优化和部署人工智能推理。更新了更多的 Gen AI 覆盖范围和框架集成,以最大限度地淘汰代码更改。同时提供了更广泛的 LLM 模型支持和更多的模型压缩技能。通过压缩嵌入的额外优化淘汰了 LLM 编译时间,改进了采取英特尔®高级矩阵扩展 (Intel® AMX) 的第 4 代和第 5 代英特尔®至强®处理器上 LLM 的第 1 令牌性能。通过对英特尔®锐炫™ GPU 的 oneDNN、INT4 和 INT8 支持,实现更好的 LLM 压缩和改进的性能。最后实现了更高的可移植性和性能,可在边沿、云端或本地运行 AI。
YOLOv10是清华大学研究人员近期提出的一种实时目标检测方法,该方法在Ultralytics Python包的基础上进行了多项创新和改进,主要有以下特点
[*]消除非极大值克制(NMS):YOLOv10通过引入一致的双重分配策略,在练习时利用一对多的标签分配来提供丰富的监视信号,在推理时利用一对一的匹配,从而消除了对NMS的依赖。这一改进在保持高精度的同时,淘汰了推理耽误和计算量。
[*]全面优化的模型架构:YOLOv10从推理服从和准确性的角度出发,全面优化了模型的各个组成部分。这包括采取轻量级分类头、空间通道去耦下采样和等级引导块设计等,以淘汰计算冗余并进步模型性能。
[*]引入大核卷积和部分自注意模块:为了进步性能,YOLOv10在不增长大量计算成本的前提下,引入了大核卷积和部分自注意模块。
[*]多种模型尺寸可选:官方发布了从N到X各种型号的模型,以满足差别应用的需求。这些模型包括超小型版本YOLOv10-N(用于资源极其有限环境)、小型版本YOLOv10-S(分身速度和精度)、中型版本YOLOv10-M(通用)、平衡型版本YOLOv10-B(宽度增长,精度更高)、大型版本YOLOv10-L(精度更高,但计算资源增长)以及超大型版本YOLOv10-X(可实现最高的精度和性能)。
通过广泛的实验验证,YOLOv10在多个模型尺度上实现了卓越的精度-耽误权衡。比方,在COCO数据集上,YOLOv10-S在相似精度下比其他实时目标检测方法更快,同时参数和浮点运算量也大幅淘汰。综上所述,YOLOv10通过消除NMS、优化模型架构和引入创新模块等策略,在保持高精度的同时显著降低了计算开销,为实时目标检测领域带来了新的突破。
https://img2024.cnblogs.com/blog/2933426/202407/2933426-20240704191342377-340309270.png
2. 项目开辟环境
下面简单先容一下项目标开辟环境,开辟者可以根据自己的设备情况进行配置:
[*]系统平台:Windows 11
[*]Intel Core i7-1165G7
[*]开辟平台:Visual Studio 2022
[*]OpenVINO™:2024.1.0
[*]OpenCV:4.8.0
此处代码开辟平台利用的是C++,因此在项目配置时,需要配置第三方依赖库,分别是 OpenVINO™和OpenCV两个个依赖库,其配置方式此处不做详述。
3. 模型获取与INT8量化
为了提升模型的推理速度,我们此处利用 OpenVINO™ 进行推理加速,并利用OpenVINO™NNCF 工具对模型进行一个INT8量化。量化的具体流程可以参考下面notebooks,该notebooks记录了YOLOv10利用OpenVINO™量化的具体流程,链接如下所示:
openvino_notebooks/notebooks/yolov10-optimization
模型量化完成后,我们对比了一下量化前后模型变化,如下图所示:
https://img2024.cnblogs.com/blog/2933426/202407/2933426-20240704191341139-806920674.png
4. 定义YOLOv10 Process
4.1 数据预处理
数据预处理此处通过OpenCV实现,将输入的图片数据转为模型需要的数据情况,代码如下所示:
void pre_process(cv::Mat* img, int length, float* factor, std::vector<float>& data) {
cv::Mat mat;
int rh = img->rows;
int rw = img->cols;
int rc = img->channels();
cv::cvtColor(*img, mat, cv::COLOR_BGR2RGB);
int max_image_length = rw > rh ? rw : rh;
cv::Mat max_image = cv::Mat::zeros(max_image_length, max_image_length, CV_8UC3);
max_image = max_image * 255;
cv::Rect roi(0, 0, rw, rh);
mat.copyTo(cv::Mat(max_image, roi));
cv::Mat resize_img;
cv::resize(max_image, resize_img, cv::Size(length, length), 0.0f, 0.0f, cv::INTER_LINEAR);
*factor = (float)((float)max_image_length / (float)length);
resize_img.convertTo(resize_img, CV_32FC3, 1 / 255.0);
rh = resize_img.rows;
rw = resize_img.cols;
rc = resize_img.channels();
for (int i = 0; i < rc; ++i) {
cv::extractChannel(resize_img, cv::Mat(rh, rw, CV_32FC1, data.data() + i * rh * rw), i);
}
} 在调用时也相对简单,将相干变量传入即可,代码如下所示:
Mat frame = new frame();
std::vector<float> input_data(640 * 640 * 3);
float factor = 0;
pre_process(&frame, 640, &factor, input_data);4.2 结果后处理
首先此处定义了一个结果类:
struct DetResult {
cv::Rect bbox;
float conf;
int lable;
DetResult(cv::Rect bbox,float conf,int lable):bbox(bbox),conf(conf),lable(lable){}
}; 然后定义模型的结果处理方式,代码如下所示:
std::vector<DetResult> post_process(float* result, float factor, int outputLength) {
std::vector<cv::Rect> position_boxes;
std::vector <int> class_ids;
std::vector <float> confidences;
// Preprocessing output results
for (int i = 0; i < outputLength; i++)
{
int s = 6 * i;
if ((float)result > 0.2)
{
float cx = result;
float cy = result;
float dx = result;
float dy = result;
int x = (int)((cx)*factor);
int y = (int)((cy)*factor);
int width = (int)((dx - cx) * factor);
int height = (int)((dy - cy) * factor);
cv::Rect box(x, y, width, height);
position_boxes.push_back(box);
class_ids.push_back((int)result);
confidences.push_back((float)result);
}
}
std::vector<DetResult> re;
for (int i = 0; i < position_boxes.size(); i++)
{
DetResult det(position_boxes, confidences, class_ids);
re.push_back(det);
}
return re;
} 最后为了让结果可视化,定义了结果绘制方法,代码如下所示:
void draw_bbox(cv::Mat& img, std::vector<DetResult>& res) {
for (size_t j = 0; j < res.size(); j++) {
cv::rectangle(img, res.bbox, cv::Scalar(255, 0, 255), 2);
cv::putText(img, std::to_string(res.lable) + "-" + std::to_string(res.conf),
cv::Point(res.bbox.x, res.bbox.y - 1), cv::FONT_HERSHEY_PLAIN,
1.2, cv::Scalar(0, 0, 255), 2);
}
} 上述方式调用依旧十分容易,利用代码如下所示:
std::vector<float> output_data(300 * 6);
std::vector<DetResult> result = post_process(output_data.data(), factor, 300);
draw_bbox(frame, result);5. 模型推理实现
5.1 根本推理实现
首先实现一下常规的同步推理代码,如下面所示:
void yolov10_infer_without_process() { std::string videoPath = "E:\\Text_dataset\\car_test.mov"; std::string model_path = "E:\\Text_Model\\yolov10s_openvino_model\\yolov10s.xml"; ov::Core core; auto model = core.read_model(model_path); auto compiled_model = core.compile_model(model, "CPU");ov::InferRequest request =compiled_model.create_infer_request(); cv::VideoCapture capture(videoPath); if (!capture.isOpened()) { std::cerr
页:
[1]