opencv dnn模块 示例(19) 目标检测 object_detection 之 yolox

文章目录

  • 0、前言
  • 1、网络介绍
    • 1.1、输入
    • 1.2、Backbone主干网络
    • 1.3、Neck
    • 1.4、Prediction预测输出
      • 1.4.1、Decoupled Head解耦头
      • 1.4.2、Anchor-Free
      • 1.4.3、标签分配
      • 1.4.4、Loss计算
    • 1.5、Yolox-s、l、m、x系列
    • 1.6、轻量级网络研究
      • 1.6.1、轻量级网络
      • 1.6.2、数据增强的优缺点
    • 1.7、Yolox的实现成果
      • 1.7.1、精度速度对比
      • 1.7.2、Autonomous Driving竞赛
    • 1.8、网络训练
  • 2、测试
    • 2.1、官方脚本测试
      • 2.1.1、torch 模型测试
      • 2.1.2、onnx 模型测试
      • 2.1.3、opencv dnn测试
    • 2.2、测试汇总对比

0、前言

YOLOX是旷视科技在2021年发表,对标YOLO v5。YOLOX中引入了当年的黑科技主要有三点,decoupled head、anchor-free以及advanced label assigning strategy(SimOTA)。YOLOX的性能如何呢,可以参考原论文图一如下图所示。YOLOX比当年的YOLO v5略好一点,并且利用YOLOX获得当年的Streaming Perception Challenge第一名。在这里插入图片描述

那这里可能有人会问了,在自己的项目中在YOLO v5和YOLOX到底应该选择哪个(后面还有yolov7,yolov8…)。如果数据集图像分辨率不是很高,比如640x640,那么两者都可以试试。如果分辨率很高,比如1280x1280,那么使用YOLO v5。因为YOLO v5官方仓库有提供更大尺度的预训练权重,而YOLOX当前只有640x640的预训练权重(YOLOX官方仓库说后续会提供更大尺度的预训练权重,目前一年多也毫无音讯)。

主要的模型内容:

  • ​对Yolov3 baseline基准模型,添加各种trick,比如Decoupled Head、SimOTA等,得到​Yolox-Darknet53​版本​;
    ​- 对Yolov5的四个版本,采用这些有效的trick,逐一进行改进,得到​Yolox-s、Yolox-m、Yolox-l、Yolox-x四个版本;​
    ​- 设计了​Yolox-Nano、Yolox-Tiny轻量级网络​,并测试了一些trick的适用性;

1、网络介绍

以Yolox-Darknet53为例,给出​网络结构

在这里插入图片描述

为了便于分析改进点,我们对Yolox-Darknet53网络结构进行拆分,变为四个板块:

  • 输入端:​Strong augmentation数据增强​
  • BackBone主干网络:​主干网络没有什么变化,还是Darknet53。​
  • Neck:​没有什么变化,Yolov3 baseline的Neck层还是FPN结构。​
  • Prediction:​Decoupled Head、End-to-End YOLO、Anchor-free、Multi positives。​

​在经过一系列的改进后,Yolox-Darknet53最终达到​AP47.3的效果。

1.1、输入

​在网络的输入端,Yolox主要采用了​Mosaic、Mixup两种数据增强方法。​而采用了这两种数据增强,直接将Yolov3 baseline,提升了2.4个百分点。

有两点需要注意:​(1)在训练的​最后15个epoch​,这两个数据增强会被关闭掉。而在此之前,Mosaic和Mixup数据增强,都是打开的,这个细节需要注意。​(2)由于采取了更强的数据增强方式,作者在研究中发现,​ImageNet预训练将毫无意义​,因此,所有的模型,均是从头开始训练的。

1.2、Backbone主干网络

Yolox-Darknet53和原本的Yolov3 baseline的主干网络都是采用Darknet53的网络结构。

1.3、Neck

Yolox-Darknet53和Yolov3 baseline的Neck结构都是采用​FPN的结构​进行融合。​
如下图所示,​FPN自顶向下​,将高层的特征信息,通过上采样的方式进行传递融合,得到进行预测的特征图。
在这里插入图片描述

1.4、Prediction预测输出

​在输出层中,主要从四个方面进行讲解:​Decoupled Head​、Anchor Free、标签分配、Loss计算。

1.4.1、Decoupled Head解耦头

目前在很多一阶段网络中都有类似应用,比如​RetinaNet、FCOS等​。而在Yolox中,作者增加了三个Decoupled Head。

基准网络中,​Yolov3 baseline的AP值为38.5。​作者想继续改进,比如输出端改进为End-to-end的方式(即无NMS的形式)后的AP值​只有34.3​。在对FCOS改进为无NMS时,在COCO上,达到了与有NMS的FCOS,相当的性能。为什么在Yolo上改进,会下降这么多?​在偶然间,作者将End-to-End中的Yolo Head,修改为Decoupled Head的方式。

在这里插入图片描述

测试发现,End-to-end Yolo的AP值,​从34.3增加到38.8。作者又将Yolov3 baseline 中Yolo Head,也修改为Decoupled Head,发现AP值,从​38.5​,增加到39.6。还发现,不单单是​精度上的提高,网络的收敛速度也加快了。结论:目前Yolo系列使用的检测头,表达能力可能有所欠缺,没有Decoupled Head的表达能力更好。​对比曲线如下
在这里插入图片描述
曲线表明:Decoupled Head的收敛速度更快,且精度更高一些。​但是需要注意的是:​将检测头解耦,会增加运算的复杂度。​因此作者经过速度和性能上的权衡,最终使用 1个1x1 的卷积先进行降维,并在后面两个分支里,各使用了 2个3x3 卷积,最终调整到仅仅增加一点点的网络参数。而且这里解耦后,还有一个更深层次的重要性:Yolox的网络架构,可以和很多算法任务,进行一体化结合。比如:​(1)YOLOX + Yolact/CondInst/SOLO ,​实现端侧的实例分割。​(2)YOLOX + 34 层输出,实现端侧人体的 ​17 个关键点检测。

Yolox-Darknet53的decoupled detection head的细节如图,对于预测Cls.、Reg.以及IoU参数分别使用三个不同的分支,将三者进行解耦。注意一点,在YOLOX中对于不同的预测特征图采用不同的head,即参数不共享。第一个Head 输出长度为20*20。Concat前总共有​三个分支​:Concat前总共有​三个分支​:

(1)cls_output:​主要对目标框的类别,预测分数。因为COCO数据集总共有80个类别,且主要是N个二分类判断,因此经过Sigmoid激活函数处理后,变为20*20*80大小。​
(2)obj_output:​主要判断目标框是前景还是背景,因此经过Sigmoid处理好,变为20*20*1大小。​
(3)reg_output:​主要对目标框的坐标信息(x,y,w,h)进行预测,因此大小为20*20*4。​

最后三个output,经过Concat融合到一起,得到20*20*85的特征信息。​当然,这只是​Decoupled Head①​的信息,再对Decoupled Head②和③进行处理。

在这里插入图片描述
Decoupled Head②输出特征信息,并进行​Concate,得到404085特征信息。​Decoupled Head③输出特征信息,并进行​Concate,得到808085特征信息​。再对①②③三个信息,进行Reshape操作,并进行总体的Concat,得到​8400*85的预测信息。

1.4.2、Anchor-Free

目前行业内,主要有Anchor Based和Anchor Free两种方式,在Yolov3、Yolov4、Yolov5中,通常都是采用​Anchor Based的方式​,来提取目标框,进而和标注的groundtruth进行比对,判断两者的差距。

① Anchor Based方式

比如输入图像,经过Backbone、Neck层,最终将特征信息,传送到输出的Feature Map中。​这时,就要设置一些Anchor规则,​将预测框和标注框进行关联。​从而在训练中,计算两者的差距,即损失函数,再更新网络参数。比如在下图的,最后的三个Feature Map上,基于每个单元格,都有三个不同尺寸大小的锚框。
在这里插入图片描述
输入为416*416时,网络最后的三个特征图大小为​13*13,26*26,52*52。每个特征图上的格点都预测三个锚框。当采用COCO数据集,即有80个类别时。基于每个锚框,都有x、y、w、h、obj(前景背景)、class(80个类别),共85个参数。​因此会产生3*(13*13+26*26+52*52)*85=​904995个预测结果。​如果输入为640*640,最后的三个特征图大小为​20*20,40*40,80*80,​则会产生3*(20*20+40*40+80*80)*85=​2142000个预测结果。

② Anchor Free方式

Yolox-Darknet53中,则采用Anchor Free的方式。网络的输出不同于Yolov3中的FeatureMap,而是 8400*85 的特征向量。通过计算,8400*85=714000个预测结果,比基于​Anchor Based​的方式,少了2/3的参数量。

Anchor框信息在前面Anchor Based中,我们知道每个Feature map的单元格,都有3个大小不一的锚框。Yolox-Darknet53仍然有,只是巧妙的将前面Backbone中下采样的大小信息引入进来。

在这里插入图片描述
最上面的分支,下采样了5次,​2的5次方为32​,并且Decoupled Head①的输出,为​202085大小。中间的分支,有1600个预测框,所对应锚框的大小​为16*16。最后分支有6400个预测框,所对应锚框的大小,​为8*8。

1.4.3、标签分配

1.4.4、Loss计算

1.5、Yolox-s、l、m、x系列

Yolov5s的网络结构图
在这里插入图片描述
Yolox-s的网络结构:
在这里插入图片描述
​由上面两张图的对比,及前面的内容可以看出,​Yolov5s和Yolox-s主要区别​在于:(1)输入端:​在Mosa数据增强的基础上,增加了Mixup数据增强效果;​(2)Backbone:​激活函数采用SiLU函数;​(3)Neck:​激活函数采用SiLU函数;​(4)输出端:​检测头改为Decoupled Head、采用anchor free、multi positives、SimOTA的方式。​在前面Yolov3 baseline的基础上,以上的tricks,取得了很不错的涨点。

在这里插入图片描述可以看出,在速度增加1ms左右的情况下,AP精度实现了​0.8~2.9的涨点。​且网络结构越轻,比如Yolox-s的时候,涨点最多,达到​2.9的涨点。​随着网络深度和宽度的加深,涨点慢慢降低,最终Yolox-x有​0.8的涨点。

1.6、轻量级网络研究

在对Yolov3、Yolov5系列进行改进后,作者又设计了两个轻量级网络,与Yolov4-Tiny、和Yolox-Nano进行对比。在研究过程中,作者有两个方面的发现,主要从轻量级网络,和数据增强的优缺点,两个角度来进行描述。

1.6.1、轻量级网络

因为实际场景的需要将Yolo移植到边缘设备中。​因此针对Yolov4-Tiny,构建了​Yolox-Tiny网络结构;针对FCOS 风格的NanoDet,构建了​Yolox-Nano网络结构。
在这里插入图片描述
从上表可以看出:​(1)和Yolov4-Tiny相比,Yolox-Tiny在参数量下降1M的情况下,AP值实现了​9个点的涨点。(2)和NanoDet相比,Yolox-Nano在参数量下降,仅有0.91M的情况下,实现了​1.8个点的涨点。(3)因此可以看出,Yolox的整体设计,在轻量级模型方面,依然有很不错的改进点。

1.6.2、数据增强的优缺点

在Yolox的很多对比测试中,都使用了数据增强的方式。​但是不同的网络结构,有的深有的浅,网络的学习能力不同,那么​无节制的数据增强是否真的更好呢?​作者团队,对这个问题也进行了对比测试。
在这里插入图片描述

通过以上的表格有以下发现:

① Mosaic和Mixup混合策略​(1)对于轻量级网络,Yolox-nano来说,当在Mosaic基础上,增加了Mixup数据增强的方式,AP值不增反而降,从​25.3降到24。​(2)而对于深一些的网络,Yolox-L来说,在Mosaic基础上,增加了Mixup数据增强的方式,AP值反而有所上升,从​48.6增加到49.5。​(3)因此不同的网络结构,采用数据增强的策略也不同,比如Yolox-s、Yolox-m,或者Yolov4、Yolov5系列,都可以使用不同的数据增强策略进行尝试。

② Scale 增强策略在Mosaic数据增强中,代码Yolox/data/data_augment.py中的random_perspective函数,生成仿射变换矩阵时,对于图片的缩放系数,会生成一个随机值。

对于Yolox-l来说,随机范围scale设置在[0.1,2]之间,即文章中设置的默认参数;而当使用轻量级模型,比如YoloNano时,一方面只使用Mosaic数据增强,另一方面随机范围scale,设置在[0.5,1.5]之间,弱化Mosaic增广的性能。

1.7、Yolox的实现成果

1.7.1、精度速度对比

前面我们了解了Yolox的各种trick改进的原因以及原理,下面我们再整体看一下各种模型精度速度方面的对比:
在这里插入图片描述
​左面的图片是相对比较​标准的​,网络结构的对比效果,主要从速度和精度方面,进行对比。而右面的图片,则是​轻量级网络​的对比效果,主要对比的是参数量和精度。

​从左面的图片可以得出:​(1)和与Yolov4-CSP相当的​Yolov5-l进行对比,Yolo-l在COCO数据集上,实现AP50%的指标,在几乎相同的速度下超过Yolov5-l 1.8个百分点。(2)而​Yolox-Darknet53和Yolov5-Darknet53相比,实现AP47.3%的指标,在几乎同等速度下,高出3个百分点。

​而从右面的图片可以得出:​(1)和Nano相比,​Yolox-Nano参数量和GFLOPS都有减少,参数量为0.91M,GFLOPS为1.08,但是精度可达到25.3%,超过Nano1.8个百分点。(2)而​Yolox-Tiny和Yolov4-Tiny相比,参数量和GFLOPS都减少的情况下,精度远超Yolov4-Tiny 9个百分点。

1.7.2、Autonomous Driving竞赛

​在CVPR2021自动驾驶竞赛的,​Streaming Perception Challenge赛道​中,挑战的主要关注点之一,是自动驾驶场景下的实时视频流2D目标检测问题。由一个服务器收发图片和检测结果,来模拟视频流30FPS的视频,客户端接收到图片后进行实时推断。​竞赛地址​:​​ ​https://eval.ai/web/challenges/challenge-page/800/overview​

在竞赛中旷视科技采用​Yolox-l作为参赛模型​,同时使用TensorRT进行推理加速,最终获得了full-track和detection-only track,两个赛道比赛的第一。因此Yolox的各种改进方式还是挺不错,值得好好学习,深入研究一下。

1.8、网络训练

参考链接 https://github.com/Megvii-BaseDetection/YOLOX/blob/main/docs/train_custom_data.md

2、测试

首先clone项目并安装

git clone git@github.com:Megvii-BaseDetection/YOLOX.git
cd YOLOX
pip3 install -v -e .  # or  python3 setup.py develop

我们以yolox-m模型为例进行测试,下载链接使用wget工具下载

wget https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_m.pth

2.1、官方脚本测试

2.1.1、torch 模型测试

python tools/demo.py image -n yolox-m -c yolox_m.pth --path assets/dog.jpg --conf 0.25 --nms 0.45 --tsize 640 --save_result --device [cpu/gpu]

针对一个 1080p是视频,分别用 cpu和gpu测试,每一帧推理耗时分别为 650ms、20ms。
在这里插入图片描述

2.1.2、onnx 模型测试

官方提供了模型下载链接 https://ghproxy.com/https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_m.onnx。

或者,通过脚本从 .pth 转换得到

python tools/export_onnx.py --output-name yolox_m.onnx -f exps/default/yolox_m.py -c yolox_m.pth

测试代码

python demo\ONNXRuntime\onnx_inference.py -m yolox_m.onnx -i assets\bus.jpg -o output -s 0.3 --input_shape 640,640

执行后的结果图将保存在 output 文件夹下。

2.1.3、opencv dnn测试

注意输出的后处理流程,yolox的输出为原始输出,需要解码。根据不同特征图大小、偏移和步长,计算映射到输入图像大小上的目标框,最后进行缩放到原图上。

当80类输入640*640时,输出[8400,85], 8400为目标框总个数,85为目标框的信息,格式为

[center_x, center_y, w,h,    obj-score,     cls1-score, cls2-score, ... , cls80-score]

8400个目标框基于anchor free,在三个不同特征图上生成, [80,80],[40,40],[20,20],对应特征图步长为 strides = 8,16, 32。首先是特征图[80,80],存在6400个位置,每个位置对应 80类目标的信息(85维);之后同理,[40,40]存在1600个位置,[20,20]存在400个位置。

center_x, center_y :表示位于当前特征图的格点位置偏移,例如 在40x40上, 格点(1,2),那么 center_x = 0.12,center_y = 0.08, 那么映射到 输入图上是位置为 [(1+0.12)*16,( 2 + 0.08) *16 ]
w,h :目标框的宽高,映射到输入图上宽高 需要乘以当前目标框所在特征图上的对应步长。
obj-score:存在目标的置信度
cls1-score, cls2-score, … , cls80-score : 每一类的置信度, 实际目标置信度要再乘以 obj-score

以下直接给出代码如下

#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);struct GridAndStride
{int grid0;int grid1;int stride;
};static void generate_grids_and_stride(std::vector<int>& strides, std::vector<GridAndStride>& grid_strides)
{for(auto stride : strides) {int num_grid_y = inpHeight / stride;int num_grid_x = inpWidth / stride;for(int g1 = 0; g1 < num_grid_y; g1++) {for(int g0 = 0; g0 < num_grid_x; g0++) {grid_strides.push_back(GridAndStride{g0, g1, stride});}}}
}std::vector<GridAndStride> grid_strides;int NUM_CLASSES;int testYolo_x()
{// 根据选择的检测模型文件进行配置 confThreshold = 0.25;scoreThreshold = 0.45;nmsThreshold = 0.5;float scale = 1;  // 1 / 255.0;  //0.00392Scalar mean = {0,0,0};bool swapRB = true;inpWidth = 640;inpHeight = 640;String modelPath = R"(E:\DeepLearning\YOLOX\yolox_m.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 = R"(E:\DeepLearning\darknet-yolo3-master\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)));}}NUM_CLASSES = classes.size();std::vector<int> strides = {8, 16, 32};generate_grids_and_stride(strides, grid_strides);// Load a model.Net net = readNet(modelPath, configPath, framework);net.setPreferableBackend(backendId);net.setPreferableTarget(targetId);std::vector<String> outNames = net.getUnconnectedOutLayersNames();{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 windowstatic 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;Mat frame, blob;while(waitKey(1) < 0) {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();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)
{// yolox has an output of shape (batchSize, 8400, 85) (box[x,y,w,h] + confidence[c] + Num classes )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;float *feat_blob = (float *)outs[0].data;const int num_anchors = grid_strides.size();// 后处理部分,可以简化for(int anchor_idx = 0; anchor_idx < num_anchors; anchor_idx++) {const int grid0 = grid_strides[anchor_idx].grid0;const int grid1 = grid_strides[anchor_idx].grid1;const int stride = grid_strides[anchor_idx].stride;const int basic_pos = anchor_idx * (NUM_CLASSES + 5);float box_objectness = feat_blob[basic_pos + 4];for(int class_idx = 0; class_idx < NUM_CLASSES; class_idx++) {float box_cls_score = feat_blob[basic_pos + 5 + class_idx];float box_prob = box_objectness * box_cls_score;if(box_prob > scoreThreshold) {class_ids.push_back(class_idx);confidences.push_back(box_prob);// yolox/models/yolo_head.py decode logicfloat x_center = (feat_blob[basic_pos + 0] + grid0) * stride;float y_center = (feat_blob[basic_pos + 1] + grid1) * stride;float w = exp(feat_blob[basic_pos + 2]) * stride;float h = exp(feat_blob[basic_pos + 3]) * stride;int left = int((x_center - 0.5 * w) * x_factor);int top = int((y_center - 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));}} // class loop}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());
}

后处理中,可以精简,仅处理每个目标框最大概率的类别数据,以提高运行速度,以及能极大的提高NMS的时间。

void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& outs, Net& net)
{....for(int anchor_idx = 0; anchor_idx < num_anchors; anchor_idx++) {const int grid0 = grid_strides[anchor_idx].grid0;const int grid1 = grid_strides[anchor_idx].grid1;const int stride = grid_strides[anchor_idx].stride;const int basic_pos = anchor_idx * (NUM_CLASSES + 5);float *data = feat_blob + basic_pos;float confidence = data[4];if(confidence < confThreshold)continue;cv::Mat scores(1, classes.size(), CV_32FC1, data + 5);cv::Point class_id;double max_class_score;minMaxLoc(scores, 0, &max_class_score, 0, &class_id);float box_prob = confidence * max_class_score;if(box_prob > scoreThreshold) {class_ids.push_back(class_id.x);confidences.push_back(box_prob);// yolox/models/yolo_head.py decode logicfloat x_center = (feat_blob[basic_pos + 0] + grid0) * stride;float y_center = (feat_blob[basic_pos + 1] + grid1) * stride;float w = exp(feat_blob[basic_pos + 2]) * stride;float h = exp(feat_blob[basic_pos + 3]) * stride;int left = int((x_center - 0.5 * w) * x_factor);int top = int((y_center - 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));} }...  // nms + draw
}

测试结果:
cuda 36ms, cpu 420ms, fp16 650ms。

在这里插入图片描述

2.2、测试汇总对比

使用onnx在其他框架上测试的汇总
opencv cuda: 36ms
opencv cpu: 420ms,
opencv cuda fp16: 650ms

以下包含 预处理+推理+后处理
openvino(CPU): 199ms
onnxruntime(GPU):22ms
trt:13ms

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

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

相关文章

【JavaEE】线程安全的集合类 -- 多线程篇(9)

线程安全的集合类 多线程环境使用 ArrayList多线程环境使用队列多线程环境使用哈希表 多线程环境使用 ArrayList 自己使用同步机制 (synchronized 或者 ReentrantLock)Collections.synchronizedList(new ArrayList); synchronizedList 是标准库提供的一个基于 synchronized 进…

nginx的使用

一、nginx下载 1.打开nginx官网http://nginx.org/en/index.html 下载安装链接 nginx&#xff08;NGINX&#xff09;详细下载安装及使用教程&#xff08;非常适合入门&#xff09;_nginx下载-CSDN博客 二、安装nginx # 前往用户根目录 cd ~#下载nginx1.13.7wget http://nginx…

Flink之Window窗口机制

窗口Window机制 窗口概述窗口的分类是否按键分区按键分区窗口非按键分区 按照驱动类型按具体分配规则滚动窗口Tumbling Windows滑动窗口 Sliding Windows会话窗口 Session Windows全局窗口 Global Windows 时间语义窗口分配器 Window Assigners时间窗口计数窗口例子 窗口函数 W…

商品价格区间筛选

列表应用&#xff0c;商品价格区间筛选。 (本笔记适合熟悉python列表及列表的条件筛选的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么…

回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于BP-Adaboost的BP神经网络结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于BP-Adaboost的BP…

嵌入式养成计划-46----QT--简易版网络聊天室实现--QT如何连接数据库

一百一十九、简易版网络聊天室实现 119.1 QT实现连接TCP协议 119.1.1 基于TCP的通信流程 119.1.2 QT中实现服务器过程 使用QTcpServer实例化一个服务器对象设置监听状态&#xff0c;通过listen()函数&#xff0c;可以监听特定的主机&#xff0c;也可以监听所有客户端&#x…

Andriod学习笔记(二)

页面设计的零碎知识 通用属性设置文本大小设置视图宽高设置视图的对齐方式 页面布局LinearLayoutRelativeLayoutGridLayoutScollView 按钮触控ButtonImageViewImageButton 案例&#xff1a;简易计算机 通用属性 设置文本大小 纯数字的setTextSize方法&#xff0c;内部默认字体…

flutter doctor检测环境,出现CocoaPods installed but not working

1. 安装flutter, 地址: 安装和环境配置 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 2. 安装成功后&#xff0c;通过flutter doctor检测环境。以mac为例&#xff0c;出现了CocoaPods installed but not working 错误提示时&#xff0c;以下为解决方案: 2.1 rvm i…

【JavaEE】JUC 常见的类 -- 多线程篇(8)

JUC 常见的类 1. Callable 接口2. ReentrantLock3. 原子类4. 线程池5. 信号量 Semaphore6. CountDownLatch 1. Callable 接口 Callable Interface 也是一种创建线程的方式 Runnable 能表示一个任务 (run方法) – 返回 voidCallable 也能表示一个任务(call方法) 返回一个具体的…

vue重修之自定义项目、ESLint和代码规范修复

文章目录 VueCli 自定义创建项目ESlint代码规范及手动修复代码规范错误 VueCli 自定义创建项目 安装脚手架 (已安装) npm i vue/cli -g创建项目 vue create xxx选项 Vue CLI v5.0.8 ? Please pick a preset:Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint) …

阿里云服务结构--长期更新

CNCF 全称Cloud Native Computing Foundation&#xff08;云原生计算基金会&#xff09;&#xff0c;成立于 2015 年7月21日&#xff08;于美国波特兰OSCON 2015上宣布&#xff09;&#xff0c;其最初的口号是坚持和整合开源技术来让编排容器作为微服务架构的一部分&#xff0…

5256C 5G终端综合测试仪

01 5256C 5G终端综合测试仪 产品综述&#xff1a; 5256C 5G终端综合测试仪主要用于5G终端、基带芯片的研发、生产、校准、检测、认证和教学等领域。该仪表具备5G信号发送功能、5G信号功率特性、解调特性和频谱特性分析功能&#xff0c;支持5G终端的产线高速校准及终端发射机…

集成学习方法(随机森林和AdaBoost)

释义 集成学习很好的避免了单一学习模型带来的过拟合问题 根据个体学习器的生成方式&#xff0c;目前的集成学习方法大致可分为两大类&#xff1a; Bagging(个体学习器间不存在强依赖关系、可同时生成的并行化方法) 流行版本&#xff1a;随机森林(random forest)Boosting(个体…

数据结构和算法——用C语言实现所有树形结构及相关算法

文章目录 前言树和森林基础概念二叉树二叉树的遍历二叉树的构造树和森林与二叉树之间的转化树和森林的遍历 满二叉树完全二叉树线索二叉树线索二叉树的构造寻找前驱和后继线索二叉树的遍历 最优二叉树&#xff08;哈夫曼树&#xff09;哈夫曼树的构造哈夫曼编码 二叉排序树&…

win10专业版驱动开发

我使用的系统版本如何下&#xff1a; 使用的visual studio为VS2019,使用的SDK,WDK如下&#xff1a; 在visual studio单个组件里选择SDK10.0.018362.0 在WDK里面选择版本为&#xff1a; 下载链接如下&#xff1a; 以前的 WDK 版本和其他下载 - Windows drivers | Microsoft Le…

Kubernetes - 一键安装部署 K8S(附:Kubernetes Dashboard)

问题描述 不知道大伙是如何安装 K8s&#xff0c;特别还是集群的时候&#xff0c;我上一次安装搭建的时候&#xff0c;那个恶心到我了&#xff0c;真的是一步一个脚印走完整个搭建流程&#xff0c;爬了不少坑。 于是&#xff0c;才有了今天的文章&#xff0c;到底有没有可以一…

YOLO V8训练自己的数据集并测试

目录 1 YOLOV8部署 2 标注软件labelme安装 3 将labelme转化为YOLOV8支持的数据格式 4 开始训练 5 利用训练结果进行测试 1 YOLOV8部署 我的一篇博客已经提到&#xff0c;这里不再赘述&#xff1a; YOLO V8语义分割模型部署-CSDN博客YOLO V8语义分割模型部署https://blog.cs…

【仙逆】王林用计灭富二代,有长命锁也没用,藤化元一怒请一人出山

【侵权联系删除】【文/郑尔巴金】 仙逆动漫第七集已经更新了。而这一集看下来&#xff0c;可以说非常精彩&#xff0c;全程在打&#xff0c;期间还能看到主角王林用谋&#xff0c;是如何一步步的把敌人藤厉引入陷阱灭杀的&#xff0c;更可以看到王林是如何筑基的。那么多的不说…

Xcode14创建github远程仓库Token

1.点击Create a Token on GitHub 2.在打开的网页中,登陆GitHub 3.点击生成Token 这是不能为空 4.Token创建成功如下: 5.复制Token到Xcode然后点击Sign In登陆 正在创建远程我仓库 正在将本地仓库代码推入远程仓库 创建成功

深入理解算法:从基础到实践

深入理解算法&#xff1a;从基础到实践 1. 算法的定义2. 算法的特性3. 算法的分类按解决问题的性质分类&#xff1a;按算法的设计思路分类&#xff1a; 4. 算法分析5. 算法示例a. 搜索算法示例&#xff1a;二分搜索b. 排序算法示例&#xff1a;快速排序c. 动态规划示例&#xf…