opencv dnn模块 示例(20) 目标检测 object_detection 之 yolor

news2025/2/26 19:02:12

文章目录

  • 1、论文介绍
    • 1.1、YOLOR思想动机
    • 1.2、隐式知识学习
      • 1.2.1、隐式知识如何工作
      • 1.2.2、隐式知识统一网络建模
    • 1.3、实验
    • 1.4、总结
  • 2、测试
    • 2.1、opencv dnn
      • 2.1.1、代码
      • 2.1.2、结果
    • 2.2、测试效率

YOLOR出自论文You Only Learn One Representation: Unified Network for Multiple Tasks,受人类学习方式(使用五官,通过常规和潜意识学习,总结丰富的经验并编码存储,进而处理已知或未知的信息)的启发,论文提出了一个统一的网络来同时编码显式知识和隐式知识,在网络中执行了kernel space alignment(核空间对齐)、prediction refinement(预测细化)和 multi-task learning(多任务学习),同时对多个任务形成统一的表示。结果表明神经网络中引入隐式知识有助于所有任务的性能提升,进一步的分析发现隐式表示之所以能带来性能提升,是因为其具备了捕获不同任务的物理意义的能力。

1、论文介绍

paper: https://arxiv.org/abs/2105.04206
code: https://github.com/WongKinYiu/yolor

1.1、YOLOR思想动机

图1:人可以根据同一幅输入图像回答不同问题,本文也旨在训练一个单一的神经网络来服务于多个任务

如图1所示,人可以从多个角度来分析同一个目标,然而通常训练CNN时只给予了一个角度,也就是说针对某一个任务得到的CNN特征很难适用于其他问题。作者认为造成上述问题的原因主要是模型只提取了神经元特征而丢弃了隐式知识的学习运用,然而就像人脑一样隐式知识对分析各种各样的任务是非常有用的。

人类对隐式知识的学习通常通过潜意识,然而并没有系统的定义怎样学习和获得隐式知识。对于神经网络而言,一般将浅层特征定义为显式知识,深层特征定义为隐式知识。本文将直接可观察的知识定义为显式知识,隐藏在神经网络中且无法观察的知识定义为隐式知识

图2:多目的神经网络架构。(a)不同任务对应不同模型;(b)不同任务共享骨干网络,使用不同的输出头;(c)本文提出的统一网络:融合显式知识和隐式知识的一个表征服务多个任务。

如图2所示,提出了一个统一的网络来集成显式知识和隐式知识,通过学习统一的表达,使得各个子表示能够适用于不同任务。基于前人工作的理论基础,本文结合压缩感知和深度学习来构建统一网络。

本文主要贡献如下:

  1. 提出了一个可同时完成多种任务的统一网络,它通过融合显式知识和隐式知识学习一个可以完成多个任务的统一表征,提出的网络可以有效的提升模型的表现,仅增加千分之一不到的计算成本;

  2. 通过 kernel space alignment(核空间对齐)、prediction refinement(预测细化)和 multi-task learning(多任务学习)来完成隐式知识的学习,并验证了其有效性;

  3. 分别讨论了隐式知识的建模方式,包括向量、神经网络、矩阵分解,并验证了这些方式的有效性;

  4. 证实了所提出的内隐表征学习方法能够准确地对应于特定的物理特征,并以视觉的方式进行了呈现;还证实了如果算子符合目标的物理意义,它可以用来整合隐式知识和显式知识,并会产生乘数效应;

  5. 与SOTA比较,YOLOR能够实现和目标检测Scaled-YOLOv4-P7一样的精度,但是推理速度快了88%。

1.2、隐式知识学习

1.2.1、隐式知识如何工作

流形空间约简
核空间对齐
更多功能和处理方式

1.2.2、隐式知识统一网络建模

隐式知识的表示
Unified Networks:
隐式知识的建模
向量/矩阵/张量
矩阵分解
训练
推理

1.3、实验

3.1 实验设置

3.2 FPN特征对齐
3.3 目标检测预测细化

3.4 多任务规范表征

3.5 隐式知识建模不同算子比较

3.6 隐式知识建模不同方式比较

3.7 隐式知识模型分析

3.8 隐式知识提升目标检测

1.4、总结

2、测试

这里以 yolor-p6-640-640 进行测试。网络模型可以看到,输出一共有4个,实际是4个尺度上的结果,最终通过reshape和concat合并成一个输出(输出格式与yolov5一致)。
在这里插入图片描述

2.1、opencv dnn

2.1.1、代码

使用和yolov5相同的测试代码。

#pragma once

#include "opencv2/opencv.hpp"


#include <fstream>
#include <sstream>

#include <random>


using namespace cv;
using namespace dnn;

float inpWidth;
float inpHeight;
float confThreshold, scoreThreshold, nmsThreshold;
std::vector<std::string> classes;
std::vector<cv::Scalar> colors;


bool letterBoxForSquare = true;

cv::Mat formatToSquare(const cv::Mat &source);

void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& out, Net& net);

void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(100, 255);

int testYoloR()
{
    // 根据选择的检测模型文件进行配置 
    confThreshold = 0.25;
    scoreThreshold = 0.45;
    nmsThreshold = 0.5;
    float scale = 1 / 255.0;  //0.00392
    Scalar mean = {0,0,0};
    bool swapRB = true;
    inpWidth = 640;
    inpHeight = 640;

    String modelPath = R"(E:\DeepLearning\yolor\yolor-p6-640-640.onnx)";
    String configPath;

    String framework = "";

    //int backendId = cv::dnn::DNN_BACKEND_OPENCV;
    //int targetId = cv::dnn::DNN_TARGET_CPU;

    int backendId = cv::dnn::DNN_BACKEND_CUDA;
    int targetId = cv::dnn::DNN_TARGET_CUDA;  

    String classesFile = std::string(R"(\data\coco.names)");


    // Open file with classes names.
    if(!classesFile.empty()) {
        const std::string& file = classesFile;
        std::ifstream ifs(file.c_str());
        if(!ifs.is_open())
            CV_Error(Error::StsError, "File " + file + " not found");
        std::string line;
        while(std::getline(ifs, line)) {
            classes.push_back(line);
            colors.push_back(cv::Scalar(dis(gen), dis(gen), dis(gen)));
        }
    }
    // Load a model.
    Net net = readNet(modelPath, configPath, framework);
    net.setPreferableBackend(backendId);
    net.setPreferableTarget(targetId);

    //std::vector<String> outNames = net.getUnconnectedOutLayersNames();
    std::vector<String> outNames{"output"};
    {
        int dims[] = {1,3,inpHeight,inpWidth};
        cv::Mat tmp = cv::Mat::zeros(4, dims, CV_32F);
        std::vector<cv::Mat> outs;

        net.setInput(tmp);
        for(int i = 0; i<10; i++)
            net.forward(outs, outNames); // warmup
    }

    // Create a window
    static const std::string kWinName = "Deep learning object detection in OpenCV";

    cv::namedWindow(kWinName, 0);

    // Open a video file or an image file or a camera stream.
    VideoCapture cap;
    cap.open(R"(E:\DeepLearning\yolov5\data\images\bus.jpg)");

    cv::TickMeter tk;
    // Process frames.
    Mat frame, blob;

    while(waitKey(1) < 0) {

        //tk.reset();
        //tk.start();

        cap >> frame;
        if(frame.empty()) {
            waitKey();
            break;
        }

        // Create a 4D blob from a frame.
        cv::Mat modelInput = frame;
        if(letterBoxForSquare && inpWidth == inpHeight)
            modelInput = formatToSquare(modelInput);

        blobFromImage(modelInput, blob, scale, cv::Size2f(inpWidth, inpHeight), mean, swapRB, false);

        // Run a model.
        net.setInput(blob);

        std::vector<Mat> outs;
        //tk.reset();
        //tk.start();

        auto tt1 = cv::getTickCount();
        net.forward(outs, outNames);
        auto tt2 = cv::getTickCount();

        tk.stop();
        postprocess(frame, modelInput.size(), outs, net);
        //tk.stop();

         Put efficiency information.
        //std::vector<double> layersTimes;
        //double freq = getTickFrequency() / 1000;
        //double t = net.getPerfProfile(layersTimes) / freq;
        //std::string label = format("Inference time: %.2f ms  (%.2f ms)", t, /*tk.getTimeMilli()*/ (tt2 - tt1) / cv::getTickFrequency() * 1000);
        std::string label = format("Inference time: %.2f ms", (tt2 - tt1) / cv::getTickFrequency() * 1000);

        cv::putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));

        cv::imshow(kWinName, frame);
    }
    return 0;
}


cv::Mat formatToSquare(const cv::Mat &source)
{
    int col = source.cols;
    int row = source.rows;
    int _max = MAX(col, row);
    cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
    source.copyTo(result(cv::Rect(0, 0, col, row)));
    return result;
}

void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& outs, Net& net)
{
    // yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c])
    auto tt1 = cv::getTickCount();

    float x_factor = inputSz.width / inpWidth;
    float y_factor = inputSz.height / inpHeight;

    std::vector<int> class_ids;
    std::vector<float> confidences;
    std::vector<cv::Rect> boxes;

    int rows = outs[0].size[1];
    int dimensions = outs[0].size[2];

    float *data = (float *)outs[0].data;

    for(int i = 0; i < rows; ++i) {
        float confidence = data[4];

        if(confidence >= confThreshold) {
            float *classes_scores = data + 5;

            cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);
            cv::Point class_id;
            double max_class_score;

            minMaxLoc(scores, 0, &max_class_score, 0, &class_id);

            if(max_class_score > scoreThreshold) {
                confidences.push_back(confidence);
                class_ids.push_back(class_id.x);

                float x = data[0];
                float y = data[1];
                float w = data[2];
                float h = data[3];

                int left = int((x - 0.5 * w) * x_factor);
                int top = int((y - 0.5 * h) * y_factor);
                int width = int(w * x_factor);
                int height = int(h * y_factor);

                boxes.push_back(cv::Rect(left, top, width, height));
            }
        }

        data += dimensions;
    }

    std::vector<int> indices;
    NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, indices);

    auto tt2 = cv::getTickCount();
    std::string label = format("NMS time: %.2f ms", (tt2 - tt1) / cv::getTickFrequency() * 1000);
    cv::putText(frame, label, Point(0, 30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));


    for(size_t i = 0; i < indices.size(); ++i) {
        int idx = indices[i];
        Rect box = boxes[idx];
        drawPred(class_ids[idx], confidences[idx], box.x, box.y,
                 box.x + box.width, box.y + box.height, frame);
    }
}

void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
{
    rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 255, 0));

    std::string label = format("%.2f", conf);
    Scalar color = Scalar::all(255);
    if(!classes.empty()) {
        CV_Assert(classId < (int)classes.size());
        label = classes[classId] + ": " + label;
        color = colors[classId];
    }

    int baseLine;
    Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

    top = max(top, labelSize.height);
    rectangle(frame, Point(left, top - labelSize.height),
              Point(left + labelSize.width, top + baseLine), color, FILLED);
    cv::putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, Scalar());
}

2.1.2、结果

测试如图,发现误识别了一个 traffic light。对比源py测试脚本,修改 bool letterBoxForSquare = false; 将等比缩放关闭后检测正常。

在这里插入图片描述

2.2、测试效率

RTX-1080ti,i7-7700k

opencv cpu:630ms
opencv gpu :52ms
opencv gpu (fp16):793ms

以下统计时间包含: 预处理+推理+后处理
openvino(cpu):274ms
onnxruntime(gpu):30ms
tensorrt:23ms

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

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

相关文章

【mfc/VS2022】计图实验:绘图工具设计知识笔记3

实现类对串行化的支持 如果要用CArchive类保存对象的话&#xff0c;那么这个对象的类必须支持串行化。一个可串行化的类通常有一个Serialize成员函数。要想使一个类可串行化&#xff0c;要经历以下5个步骤&#xff1a; 1、从CObject派生类 2、重写Serialize成员函数 3、使用DE…

【计算机网络 】传输层——UDP

目录 传输层传输层概念再谈端口号协议号和端口号端口号区域常见端口号pidof UDPUDP协议格式UDP协议的特点UDP的缓冲区UDP传输数据注意事项 传输层 传输层概念 在学习HTTP等应用层协议时&#xff0c;为了便于理解&#xff0c;可以简单的认为HTTP协议是将请求和响应直接发送到了…

​​​​​​​为什么你的Word文件无法移动到U盘

为什么你的Word文件无法移动到U盘 你是否遇到过这样的情况&#xff1a;你在苹果电脑上编辑了一个Word文档&#xff0c;想要把它拷贝到一个U盘上&#xff0c;但是却发现无法操作。你可能会感到很奇怪&#xff0c;为什么你的Word文件无法移动到U盘呢&#xff1f;这是因为苹果电脑…

ESM蛋白质语言模型系列

模型总览 第一篇《Biological structure and function emerge from scaling unsupervised learning to 250 million protein sequences 》ESM-1b 第二篇《MSA Transformer》在ESM-1b的基础上作出改进&#xff0c;将模型的输入从单一蛋白质序列改为MSA矩阵&#xff0c;并在Tran…

TensorRT量化实战课YOLOv7量化:pytorch_quantization介绍

目录 前言1. 课程介绍2. pytorch_quantization2.1 initialize函数2.2 tensor_quant模块2.3 TensorQuantizer类2.4 QuantDescriptor类2.5 calib模块 总结 前言 手写 AI 推出的全新 TensorRT 模型量化实战课程&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 该…

分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测(自注意力机制)

分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1…

【MySQL--->内外连接】

文章目录 [TOC](文章目录) 一、内连接二、左外连接三、右外连接 一、内连接 内连接就是将两个表连接进行笛卡尔积查询 显示SMITH的名字和部门名称 二、左外连接 左外连接就是以左面的表为主&#xff0c;即便是右边的表没有而左边表项中有的&#xff0c;依然显示 查询所有学…

HTML基础总结——速通知识点

一、基础知识点 Web标准构成&#xff1a; HTML页面的固定结构 <html><head><title>网页的标题</title> </head> <body>网页的主体内容 </body> </html>二、语法 2.1注释 在vscode中&#xff1a;将光标置于需要注释的行&a…

引入个性化标签的协同过滤推荐算法研究_邢瑜航

第3章 引入个性化标签的I-CF推荐算法 3.2.2 相似性度量方法 3.2.3 改进后的算法步骤与流程

IntelliJ IDEA 把package包展开和压缩

想要展开就把对勾取消&#xff0c;想要压缩就勾上

【多线程面试题十二】、阻塞线程的方式有哪些?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;阻塞线程的方式有哪些&a…

【LeetCode力扣】42. 接雨水

目录 1、题目介绍 2、解题思路 2.1、暴力破解法 2.2、双指针法 1、题目介绍 原题链接&#xff1a; 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]输出&#xff1a;6解释&#xff1a;上面是由…

Python打包成.exe文件直接运行

文章目录 前言pyinstaller.exe文件具体步骤第一步&#xff1a;安装pyinstaller第二步&#xff1a;进入要打包文件的目录第三步&#xff1a;执行文件第四步&#xff1a;发给好友 拓展尾声 前言 很多小伙伴在阅读了博主的文章后都积极与博主交流&#xff0c;在这里博主很感谢大家…

scrapy-redis分布式爬虫(分布式爬虫简述+分布式爬虫实战)

一、分布式爬虫简述 &#xff08;一&#xff09;分布式爬虫优势 1.充分利用多台机器的带宽速度 2.充分利用多台机器的ip地址 &#xff08;二&#xff09;Redis数据库 1.Redis是一个高性能的nosql数据库 2.Redis的所有操作都是原子性的 3.Redis的数据类型都是基于基本数据…

LED数码管的静态显示与动态显示(Keil+Proteus)

前言 就是今天看了一下书上的单片机实验&#xff0c;发现很多的器件在Proteus中都不知道怎么去查找&#xff0c;然后想做一下这个实验&#xff0c;尝试能不能实现&#xff0c;LED数码管的两个还可以实现&#xff0c;但是用LED点阵显示器的时候他那个网络标号不知道是什么情况&…

GZ035 5G组网与运维赛题第7套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第7套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

python自动化测试(六):唯品会商品搜索-练习

目录 一、配置代码 二、操作 2.1 输入框“运动鞋” 2.2 点击搜索按钮 2.3 选择品牌 2.4 选择主款 2.5 适用性别 2.6 选择尺码 2.7 选择商品&#xff1a;&#xff08;通过css的属性去匹配&#xff09; 2.8 点击配送地址选项框 一、配置代码 # codingutf-8 from selen…

基于萤火虫算法的无人机航迹规划-附代码

基于萤火虫算法的无人机航迹规划 文章目录 基于萤火虫算法的无人机航迹规划1.萤火虫搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用萤火虫算法来优化无人机航迹规划。 1.萤火虫…

Mysql数据库基本概念和Sql语言

一、数据库基本概念 1.1 数据库概述 数&#xff1a;数字信息 据&#xff1a;属性 数据&#xff1a;对一系列对象的具体属性的描述的集合 数据库&#xff1a;数据库就是用来组织(各个数据之间是有关联的&#xff0c;按照规则组织起来的)、存储和管理(对数据的增、删、改、查)的…

JavaEE-博客系统1(数据库和后端的交互)

本部分内容包括网站设计总述&#xff0c;数据库和后端的交互&#xff1b; 数据库操作代码如下&#xff1a; -- 编写SQL完成建库建表操作 create database if not exists java_blog_system charset utf8; use java_blog_system; -- 建立两张表&#xff0c;一个存储博客信息&am…