【OpenVINO™】使用 OpenVINO™ C++ 异步推理接口部署YOLOv8 ——在Intel IGPU 上实现80+FPS视频推理

news2024/12/26 0:32:14

​ OpenVINO Runtime支持同步或异步模式下的推理。Async API的主要优点是,当设备忙于推理时,应用程序可以并行执行其他任务(例如,填充输入或调度其他请求),而不是等待当前推理首先完成。 当我们使用异步API时,第二个请求的传输与第一个推理的执行重叠,这防止了任何硬件空闲时间。

  本文章中,我们以YOLOv8模型为例,对比了OpenVINO分别使用同步推理接口以及异步推理接口的推理速度情况。其中同步推理一帧平均推理时间为43.02毫秒,而异步接口一帧平均推理时间仅为11.37毫秒,异步接口一秒钟平均可以实现87.98FPS的推理,是同步推理的3.78倍,速度快到飞起!!

  下面是异步推理与同步推理对比效果演示视频:

YOLOv8在集成显卡可实现80+FPS推理——使用 OpenVINO™ C++ 异步推理接口部署YOLOv8 实现视频推理

1. OpenVINO™ 工具套件

  英特尔发行版 OpenVINO™ 工具套件基于 oneAPI 而开发,可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,适用于从边缘到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界结果部署到生产系统中。通过简化的开发工作流程,OpenVINO™ 可赋能开发者在现实世界中部署高性能应用程序和算法。

03b06c0aec22e58235cd01fa6d9b6db4

  2024年4月25日,英特尔发布了开源 OpenVINO™ 2024.1 工具包,用于在各种硬件上优化和部署人工智能推理。更新了更多的 Gen AI 覆盖范围和框架集成,以最大限度地减少代码更改。同时提供了更广泛的 LLM 模型支持和更多的模型压缩技术。通过压缩嵌入的额外优化减少了 LLM 编译时间,改进了采用英特尔®高级矩阵扩展 (Intel® AMX) 的第 4 代和第 5 代英特尔®至强®处理器上 LLM 的第 1 令牌性能。通过对英特尔®锐炫™ GPU 的 oneDNN、INT4 和 INT8 支持,实现更好的 LLM 压缩和改进的性能。最后实现了更高的可移植性和性能,可在边缘、云端或本地运行 AI。

2. OpenVINO™ 异步接口

  OpenVINO Runtime支持同步或异步模式下的推理。Async API的主要优点是,当设备忙于推理时,应用程序可以并行执行其他任务(例如,填充输入或调度其他请求),而不是等待当前推理首先完成。 在同步模式下,我们等待第一次推理的结果,然后再发送下一个请求。在发送请求时,硬件处于空闲状态。当我们使用异步API时,第二个请求的传输与第一个推理的执行重叠,这防止了任何硬件空闲时间。如下图所示,该图展示了同步推理与异步推理流程情况以及时间安排:

async分析

  可以看出,通过异步接口,我们可以实现模型推理和数据前处理以及后处理并行执行,这将会大大压缩模型推理全流程的时间。下面简单介绍一下在C++中,同步推理以及异步推理接口:

2.1 创建推断请求

  可以从以下位置创建:ov::InferRequestov::CompiledModel

auto infer_request = compiled_model.create_infer_request();

ov::InferRequest可以运行推理,支持同步和异步模式进行推理。

2.2 同步模式

ov::InferRequest::infer可以使用来阻止应用程序执行,以同步模式下进行模型推理。

infer_request.infer();

2.3 异步模式

  异步模式可以提高应用程序的整体帧速率,方法是使其在加速器繁忙时在主机上工作,而不是等待推理完成。要在异步模式下推断模型,需要使用ov::InferRequest::start_async接口。

infer_request.start_async();

  异步模式支持应用程序等待推理结果的两种方式:

ov::InferRequest::wait_for:指定阻止方法的最大持续时间(以毫秒为单位)。该方法将被阻止,直到指定的时间过去,或者结果变得可用,以先到者为准。

infer_request.wait_for(std::chrono::milliseconds(10));

  ov::InferRequest::wait:等到推理结果可用

infer_request.wait();

  其中这两种等待推理结果的方法都是线程安全的。

3. 项目环境

  • 推理设备:OpenVINO IGPU
  • CPU: Intel Core i7-1165G7
  • IGPU: Intel Iris Xe Graphics
  • 推理模型: YOLOv8s
  • 视频分辨率:1920×1080

4. 代码实现

4.1 定义YOLOv8数据处理方法

  首先定义了一下YOLOv8模型前后处理的方法,包括输入数据处理接口pre_process(cv::Mat* img, int length, float* factor, std::vector<float>& data)以及预测结果处理接口std::vector<DetResult> post_process(float* result, float factor, int outputLength) ,具体不做过多讲解,代码如下所示:

struct DetResult {
    cv::Rect bbox;
    float conf;
    int lable;
    DetResult() {}
    DetResult(cv::Rect bbox, float conf, int lable) :bbox(bbox), conf(conf), lable(lable) {}
};

void draw_bbox(cv::Mat& img, std::vector<DetResult>& res) {
    for (size_t j = 0; j < res.size(); j++) {
        cv::rectangle(img, res[j].bbox, cv::Scalar(255, 0, 255), 2);
        cv::putText(img, std::to_string(res[j].lable) + "-" + std::to_string(res[j].conf),
            cv::Point(res[j].bbox.x, res[j].bbox.y - 1), cv::FONT_HERSHEY_PLAIN,
            1.2, cv::Scalar(0, 0, 255), 2);
    }
}
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);
    }
}
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++)
    {
        for (int j = 4; j < 4 + 80; j++)
        {
            float source = result[outputLength * j + i];
            int label = j - 4;
            if (source > 0.2)
            {
                float maxSource = source;
                float cx = result[outputLength * 0 + i];
                float cy = result[outputLength * 1 + i];
                float ow = result[outputLength * 2 + i];
                float oh = result[outputLength * 3 + i];
                int x = (int)((cx - 0.5 * ow) * factor);
                int y = (int)((cy - 0.5 * oh) * factor);
                int width = (int)(ow * factor);
                int height = (int)(oh * factor);

                cv::Rect box(x, y, width, height);

                position_boxes.push_back(box);
                class_ids.push_back(label);
                confidences.push_back(maxSource);
            }
        }
    }
    std::vector<int> indices;
    cv::dnn::NMSBoxes(position_boxes, confidences, 0.2f, 0.5f, indices);
    std::vector<DetResult> re;
    for (int i = 0; i < indices.size(); i++)
    {
        int index = indices[i];
        DetResult det(position_boxes[index], confidences[index], class_ids[index]);
        re.push_back(det);
    }
    return re;
}

4.2 异步推理实现

  异步推理在实现时,需要创建两个以上的推理通道ov::InferRequest,首先读取第一帧数据并将其添加在第一个推理通道上,并开启异步推理;然后读取下一帧视频数据,并加载到另一个推理通道上;接着等待上一帧数据推理是否结束,如果结束,便会读取推理结果,进行结果处理;接着读取下一帧数据,并将推理结果加载到图里玩的通道上,依次往复,便可以实现视频数据的异步推理。

void yolov8_async_infer() {
    std::string video_path = "E:\\ModelData\\NY.mp4";
    std::string model_path = "E:\\Model\\yolo\\yolov8s.onnx";
    ov::Core core;
    auto model = core.read_model(model_path);
    auto compiled_model = core.compile_model(model, "GPU");
    std::vector<ov::InferRequest>requests = { compiled_model.create_infer_request(), compiled_model.create_infer_request() };
    cv::VideoCapture capture(video_path);
    if (!capture.isOpened()) {
        std::cerr << "ERROR: 视频无法打开" << std::endl;
        return;
    }
    float factor = 0;
    requests[0].get_input_tensor().set_shape(std::vector<size_t>{1, 3, 640, 640});
    requests[1].get_input_tensor().set_shape(std::vector<size_t>{1, 3, 640, 640});
    cv::Mat frame;
    capture.read(frame);
    std::vector<float> inputData(640 * 640 * 3);
    pre_process(&frame, 640, &factor, inputData);
    memcpy(requests[0].get_input_tensor().data<float>(), inputData.data(), 640 * 640 * 3);
    requests[0].start_async();
    while (true)
    {
        cv::Mat next_frame;
        if (!capture.read(next_frame)) {
            break;
        }
        pre_process(&next_frame, 640, &factor, inputData);
        memcpy(requests[1].get_input_tensor().data<float>(), inputData.data(), 640 * 640 * 3);
        requests[1].start_async();
        requests[0].wait();
        float* output_data = requests[0].get_output_tensor().data<float>();
        std::vector<DetResult> result = post_process(output_data, factor, 8400);
        draw_bbox(frame, result);
        imshow("读取视频", frame);
        cv::waitKey(1);	//延时30
        frame = next_frame;
        std::swap(requests[0], requests[1]);
    }
    cv::destroyAllWindows();
    return;
}

  上面已经展示了该项目实现的全部代码,如果想获取项目文件,通过下面链接进行下载:OpenVINOC++异步推理接口部署YOLOv8代码资源

5. 时间测试

写完代码后,对同步接口以及异步推理接口进行了时间测试,如下表所示:

APIPrePocessInferencePostProcessTotalFPS
Sync9.83 ms33.18 ms0.1 ms43.02 ms23.25
Async11.27 ms0.02 ms0.08 ms11.37 ms87.98

  其中同步推理一帧平均推理时间为43.02毫秒,而异步接口一帧平均推理时间仅为11.37毫秒,异步接口一秒钟平均可以实现87.98FPS的推理,是同步推理的3.78倍,速度快到飞起!!

6. 总结

  在该项目中,我们实现了OpenVINO异步模式下的推理,并和同步推理进行了对比,异步推理速度提升了3.78倍,并且在没有进行任何优化掉前提下,使用集成显卡中便实现了视频的快速推理。

  最后如果各位开发者在使用中有任何问题,欢迎大家与我联系。

个人账号 - 2

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

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

相关文章

使用pnpm创建vue3项目

https://pnpm.io/zh/ 全局安装&#xff1a; npm install -g pnpm 检查版本&#xff1a; pnpm -v 创建vue3项目&#xff1a; pnpm create vuelatest 项目装包&#xff1a; pnpm install 运行项目&#xff1a; pnpm dev 命令行&#xff1a; https://pnpm.io/zh/pnpm-cli pnpm …

django学习入门系列之第二点《浏览器能识别的标签3》

文章目录 列表表格往期回顾 列表 无序列表 <!-- <ul </ul> 无序列表 --> <ul><li> 内容1 </li><li> 内容2 </li><li> 内容3 </li><li> 内容4 </li> </ul>有序列表 <!-- <ol> &…

Python | Leetcode Python题解之第150题逆波兰表达式求值

题目&#xff1a; 题解&#xff1a; class Solution:def evalRPN(self, tokens: List[str]) -> int:op_to_binary_fn {"": add,"-": sub,"*": mul,"/": lambda x, y: int(x / y), # 需要注意 python 中负数除法的表现与题目不一…

【车载音视频电脑】嵌入式AI分析车载DVR,支持8路1080P

产品特点 采用H.265 & H.264编解码&#xff0c;节约存储空间、传输流量&#xff1b; 高分辨率&#xff1a;支持8路1080P*15FPS/4路1080P*30FPS、720P、D1等编解码&#xff1b; 支持1张SATA硬盘&#xff0c;取用方便&#xff0c;满足大容量存储要求&#xff1b; 支持1个…

对抗攻击论文阅读—AAAI2022—CMUA-Watermark

文章目录 CMUA-Watermark: A Cross-Model Universal Adversarial Watermark for Combating Deepfakes背景1、什么是对抗攻击1.1 主动防御与被动防御 2、整体思路3、方法3.1 整体流程3.2 如何破坏单个面部修改模型 G G G论文中代码 3.3 对抗扰动融合3.4 基于TPE的自动步长调整 4…

【Linux文件篇】软硬链接与动静态库链接的实用指南

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 目录 文件的软硬链接 动静态库 回归动静态库 创建动静态库 生成静态库 生成动态库 库搜索路径 文件的软硬链接 上篇文章中我们讲述了文件系统从硬件到软件&#xff0c;理解了如何创建一个文件的具体流程&#xff…

AI数字人的开源解决方案

目前&#xff0c;国内外已经涌现出一些优秀的数字人开源解决方案&#xff0c;这些解决方案为开发者提供了构建数字人应用的工具和基础设施。以下是一些比较知名的数字人开源解决方案。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1…

java Springboot网上音乐商城(源码+sql+论文)

1.1 研究目的和意义 随着市场经济发展&#xff0c;尤其是我国加入WTO &#xff0c;融入经济全球化潮流&#xff0c;已进入国内外市场经济发展新时期&#xff0c;音乐与市场联系越来越紧密&#xff0c;我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场&#xff0…

5.7 Python内置函数

文章目录 1. 内置模块Aabs()all()any()ascii() Bbin()bool()bytearra()bytes() Ccallable()chr()classmethod()compile()complex() Ddelattr()dict()dir()divmod() Eenumerate()eval()exec()execfile() Ffile()filter()float()format()frozenset() Ggetattr()globals() Hhasatt…

【分布式技术专题】「OceanBase深度解析」 探索OceanBase产品矩阵与核心设计

探索OceanBase产品矩阵与核心设计 OceanBase的六大特性高扩展高可用多租户&#xff08;资源隔离&#xff09;OceanBase架构和功能OceanBase广泛的数据源支持 OceanBase的六大特性 OceanBase以其卓越的产品平台整合方案&#xff0c;充分展现了六大核心特性的卓越与全面。这一方…

进击算法工程师深度学习课程

"进击算法工程师深度学习课程"旨在培养学员在深度学习领域的专业技能和实战经验。课程涵盖深度学习基础理论、神经网络架构、模型优化方法等内容&#xff0c;通过项目实践和算法实现&#xff0c;帮助学员掌握深度学习算法原理和应用&#xff0c;提升在算法工程师领域…

SAP Web IDE 安装使用

For training SAP Web IDE 是基于 Eclipse 内核的在线开发 IDE&#xff0c;可以使用在线的试用版本&#xff0c;但服务器在德国&#xff0c;访问的网速特别慢。也可以使用 Personal Edition&#xff0c;在本机启动和编写代码。 打开官网下载WEBIDE工具包&#xff0c;包含 Tri…

SAP ABAP 之面向对象OO

文章目录 前言一、类的理解二、如何创建ABAP类 a.类的定义与构成 b.类的访问区域 c.特殊方法 d.类的继承 三、类中参数的使用 a.IMPORTING / EXPORTING b.CHANGING c.RETURNING d.EX…

省市县选择三级联动(使用高德API实现)

省市县选择如果自己实现是比较麻烦的&#xff0c;最近发现可以使用高德实现省市县联动选择&#xff0c;实现后来记录一下供大家参考。 文章目录 最终效果&#xff1a;一、准备工作二、完整页面代码 最终效果&#xff1a; 实现单次点击获取省市县名称&#xff0c;选择完成后返回…

复旦微FMQL20SM全国产ARM+FPGA核心板,替代xilinx ZYNQ7020系列

FMQL20SM核心板一款全国产工业核心板。基于复旦微FMQL20S400M四核ARM Cortex-A7&#xff08;PS端&#xff09; FPGA可编程逻辑资源&#xff08;PL端&#xff09;异构多核SoC处理器设计的全国产工业核心板&#xff0c;PS端主频高达1GHz。 核心板简介 FMQL20SM核心板是一款全国…

键盘、鼠标、轴体选购指南

起因 买了块27寸的屏幕msi&#xff0c;一旦入坑爬不起来了。 这不是要配个键盘么。 鼠标的左键也不够灵敏&#xff0c;不知道是电池不足还是使用时间太久&#xff0c;也萌生换的念头。有一个重要原因也是跟电脑和鼠标垫整体不搭。 搜集信息 原本的一个键盘是ikbc国产牌子&am…

【C++】STL中stack和queue(适配器版)的模拟实现

前言&#xff1a;在此之前我们讲到了stack和queue还有deque的常见的使用方法&#xff0c;并且也在数据结构的时候用C语言去实现过栈和队列&#xff0c;今天我们将进一步的用C去模拟实现stack和queue &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; …

Apache Doris 基础 -- 部分数据类型及操作

您还可以使用SHOW DATA TYPES;查看Doris支持的所有数据类型。 部分类型如下&#xff1a; Type nameNumber of bytesDescriptionSTRING/可变长度字符串&#xff0c;默认支持1048576字节(1Mb)&#xff0c;最大精度限制为2147483643字节(2gb)。大小可以通过BE配置string_type_le…

2. Revit API UI 之 IExternalCommand 和 IExternalApplication

2. Revit API UI 之 IExternalCommand 和 IExternalApplication 上一篇我们大致看了下 RevitAPI 的一级命名空间划分&#xff0c;再简单讲了一下Attributes命名空间下的3个类&#xff0c;并从一个代码样例&#xff0c;提到了Attributes和IExternalCommand &#xff0c;前者是指…

Cisco Packet Tracer实验(二)

二、用交换机构建 LAN 构建物件如下&#xff1a; 四个PC 两个交换机 一个Multi Switch多功能拓展控制器 连线必须是这个直线&#xff01;&#xff01;&#xff01;不是虚线 最后实现效果如下&#xff1a; 全部的线是绿的&#xff0c;就表示是通的。 尝试一下&#xff0c;看PC…