Quantcast
Channel: Sam的技术Blog
Viewing all articles
Browse latest Browse all 158

Yolo简介及其推理

$
0
0
作者:Sam (甄峰)  sam_code@hotmail.com

0.目标检测算法:
目标检测算法两个分支,单阶段和两阶段目标检测



Yolo(You Only Look Once)是目标检测单阶段模型。它是一个精度尚可,速度很快的模型。即精度速度性价比很高的模型。

1. Yolo的思路
如何可以只Look一次呢? 就是将目标检测当作一个单一的回归任务。

1.1:核心思路:
A. 将图像划分为SxS个网格。
B. 物体的真实框中心落在哪个网格,就由该网格对应的Anchor负责检测该物体。

1.2:模型输出
输出W x H x C:
W 和H,代表划分的网格数(S x S). 例如13x13.
C通道上,则存储 x, y, h, w, project, classification(one-hot).

1.3:模型特点:
骨干网络使用DarkNet. YoloV3采用了DarkNet53 
采用全卷积网络结构: Conv+Batch Norm.
Kmeans聚类产生9个Anchor.
多尺度训练。跨尺度特征融合。 
分类使用sigmoid激活,支持目标多分类。

2. 模型详解:
2.1:Yolo模型结构:


骨干网络采用Darknet53, 分5个阶段,每个阶段使用倍数为2的下采样。
最后分别输出32倍,16倍,8倍下采样。共3个特征图。


2.2:模型的输入和输出:



输入:shape为[N, 3, 416, 416].
N 为batch size.
3: RGB三通道
416, 416:输入图像的H,W.


共输出三个特征图,分别对应32,16,8倍下采样。
416/8=52,  416/16=26  416/32=13.
所以对应的特征图的w和h 分别是13x13,  26x26, 52x52.
每个特征图分配3个锚框。

2.3:锚框(Anchor)和它存在的理由:


锚框,Anchor:就是用KMeans聚类,在训练集上聚类出的一些框,给定HW. 这些框,表示了物体最有可能出现的长宽。是一个先验框。

Yolo把最大的三个Anchor分配和视野最大的一个特征图,把最小的三个Anchor分配和视野最小的一个特征图。
所以,Yolo的每个输出特征图,都会分配3个Anchor.  这样预测框仅需要在锚框的基础上微调,就可以更快的找到和表达真实框。

2.4:从锚框(Anchor)到预测框:
在特征图的每个网格中(SxS), 都放入分配给它的锚框--通常是3个。
例如:13x13的网格中,每个网格都分配给3个较大的Anchor.

所以,预测框的数量为:
网格数 x 分配给它的锚框数 --->13x13 x3

每个预测框的数据包括:x, y, h, w , p + class_num 
5 + class_num 




3. Yolo的预测流程:


获得了(13x13 + 26x26 + 52x52) *3个 class, score, x, y, w, h后。再做NMS, 把重复的预测框去掉。



即先按class分类, 再按score排序, 之后从score高的到score低的计算IoU,如果高于某个阈值,则表明它们意见相同,表示的是同一个真实框,则把score低的去掉。

最后保留下来的就是预测的真实框。


4. YoloV3-Ting:
对于速度要求较高的项目,可以选择YoloV3_tiny.
它在Yolo基础上去掉了一些特征图,只保留了两个独立的预测分支。
N, 255, 13, 13
N, 255, 26, 26
其中255是class_num=80时计算的。实际情况根据class_num计算。



5. 使用OpenCV DNN推理
可以使用OpenCV DNN 来推理Yolo模型。

5.1:打开模型:
因为骨干网络是darknet
auto net = cv::dnn::readNetFromDarknet(models_cfg, models_weights);

这是Yolo的特殊点:
std::vector vecOutNames =  net.getUnconnectedOutLayersNames();


5.2:准备数据:
matInputBlob = cv::dnn::blobFromImage(matFrame, 1 / 255.F, cv::Size(416, 416), cv::Scalar(), true, false);
可以看到,归一化的mean={0, 0, 0}
scale=1/255.
输入Mat resize成  416x416.

5.3:指定数据:
net.setInput(matInputBlob);

5.4:推理:
net.forward(vecOutMat, vecOutNames);
Yolo输出就在vecOutMat中。

后面就要根据Yolo的输出特征图格式,来解析输出数据,得到推理出来的预测框了。

5.5:输出特征图的数据分析:
vecOutMat.size(), 有多少个输出分支,它的size就多大。如果采用Yolo,则有3个分支。如果采用Yolo_tiny, 则有两个分支。

vecOutMat[i].rows, vecOutMat[i].cols:
分别表示这个分支上预测框的个数,以及每个预测框的具体信息。
vecOutMat[i].rows--此分支上预测框个数。 按之前所说: 网格数 x 分配给它的锚框数 --->13x13 x3
则表明这个分支上预测框个数为: 13x13x3.
vecOutMat[i].cols:每个预测框的内容。其中包括: x, y, w, h, p + class_id(one-hot)
例如:如果是个4分类的模型,则有5+4共9 位。

NMS:
cv::dnn::NMSBoxes(vecBoxesRect, vecConfidences, 0.5, 0.2, vecIndices);
把所有符合条件的预测框填入vecBoxesRect, 对应的Score填入vecConfidences. 进行NMS. 
NMS结果会填入最后一个参数。参数中是索引值。


6. 使用Tengine_Lite推理














 

Viewing all articles
Browse latest Browse all 158

Trending Articles