前言:最近新入了目标检测的坑,查阅了一些相关的资料,整理一下笔记,和大家分享一下。这篇文章的内容非常基础,有很多深度学习的相关概念,都随手标注解释,所以篇幅可能会很长,可能读起来分不清主线,先这样写着,后面慢慢整理。
主要分为以下两个内容:
yolo:you only look once
下图是一些经典的(Object Dectection model)目标检测模型EfficientDet(D0-D4), ASFF, ATSS, YOLO, CenterMark在MS COCO数据集上的表现,给出的几个模型都是目前性能比较好的,可以发现yolov4 在视频中的目标检测性能要远大于其他的模型,特别是针对于yolov3有接近两倍的速度提升,这使得有充分的理由去学习yolo的算法原理。
这里图片的纵横坐标分析:
FPS:视频的帧率,每秒可以处理视频流中的图片的个数。
AP: (Average Precision),AP就是平均精准度,是主流的目标检测模型的评价指标。简单来说就是对PR曲线上的Precision值求均值。对于pr曲线来说,我们使用积分来进行计算:
如果想理解这个公式,需要知道IoU,Precision & Recall,PR曲线等概念
1. IoU(Intersection over union):交并比IoU衡量的是两个区域的重叠程度,是两个区域重叠部分面积占二者总面积(的比例。如下图,两个矩形框的IoU是交叉面积(中间图片红色部分)与合并面积(右图红色部分)面积之比。
通常在目标检测任务中,如果模型输出的矩形框与人工标注的矩形框的IoU值大于某个阈值时(通常为0.5)即认为模型输出了正确的结果。
2. (Precision & Recall)
Precision 和 Recall最早是信息检索中的概念,用来评价一个信息检索系统的优劣。Precision 就是检索出来的条目中(比如:文档、网页等)有多大比例是需要的,Recall就是所有需要的网页的条目有多大比例被检索出来了。用到目标检测领域,假设有一组图片,里面有若干待检测的目标,Precision就代表模型检测出来的目标有多打比例是真正的目标物体,Recall就代表所有真实的目标有多大比例被的模型检测出来了。换个更通俗的例子,10个花生和15个黄豆和25个玉米撒在一起,小明的妈妈让小明把他们都捡起来,说先让把玉米挑出来,小明嫌麻烦随便抓了一把,里面有5个花生、6个黄豆、7个玉米和8个小石子。
那么Precision = (5+6+7)/(5+6+7+8) Recall = 7/(5+6+7+8)
在目标检测中通常是这样使用的,如下图所示:(通常将IOU大于0.5的视为正确的,将IOU小于0.5的视为错误)
TP,即原本正确的,预测值也是正确的 v
FP,即原本错误的,预测值却是正确的 x
TN,即原本错误的,预测值也是错误的 v
FN,即原本正确的,预测值却是错误的 x
(1)TP就是【True P】;FP就是【False P】。都是站在预测的角度来描述的。
(2)P代表的是Positive【正类】; N表示的是Negative【负类】,站在标签的角度讲的。
3. PR曲线
检测的结果P越高越好,R也越高越好,但事实上这两者在某些情况下是矛盾的。比如极端情况下,只检测出了一个结果,且是准确的,那么Precision就是100%,但是Recall就很低;而如果我们把所有结果都返回,那么必然Recall必然很大,但是Precision很低。
因此在不同的场合中需要判断希望P比较高还是R比较高。如果是做实验研究,可以绘制Precision-Recall曲线来帮助分析。
下面详细说明一PR曲线如何绘制,通过阅读上面的文章可以发现,计算P ,R 需要站在预测的角度,首先要解决的问题是什么样的预测值是错误的,什么样的预测值是正确的。此时需要一个阈值作为界限,大于这个阈值的为正确,小于这个阈值的为错误。
给定一个阈值,就能计算一个P值和一个R值,正如所想的那样,通过改变不同的阈值,就会得到不同的预测结果,这样就会得到一系列不同的点对(P, R), 这些不同的点对就组成了PR曲线。
为了更方便的对整体的架构进行梳理,下面的介绍会将yolo v1-v4的内容串在一起
如下图所示(图片来自yolov4),几乎涵盖了目前所有的目标可检测器中含有的内部结构。
一般的目标检测器,都分为四个部分:Input,Backbone,Neek ,Head
Input,可以是一整张图片,可以是一整张图片中的某一小块(针对尺寸相对较大的图片),也可以是图像金字塔(image, Pyramid)
解释一下图像金字塔,如下图所示:
对图像进行一定比例的缩放,有必要的话还得加上 平滑图像的操作(可使用高斯模糊),按照要求对图像进行缩放可以解决图像输入的尺寸问题。
图像金字塔的作用在于解决目标检测中的尺度问题,在比较早的时候,是通过改变滑动窗口的形式来检测图像中大小不一的物体,而目前阶段,更多的是采用滑动窗口规格不变,改变图片大小来检测图像中尺度不一致的物体,金字塔的层级越多,计算量更大,花费的时间会更多,但是,在某种程度上有获得更准确的结果。主要根据自己的应用场景选择合适的比例进行生成图像金字塔
BackBone:常用的有VGG16 ResNet-50,ResNeXt-101,DarkNet53 这些都是网络的一些骨架基本模块,经过实践检验在网络中使用这些模块可以提高模型的性能。
Neek:这个概念实在yolo v4中提出的, 常用的有FPN, PANet,Bi-FPN(这里是找到的三篇文章,先挖个洞随后补一补知识)
Head:(重点内容),几乎所有的关于深度学习项目,Input,backbone,neek基本上套路都是一样的,输入层经过一系列卷积操作,最后来到输出层,用不同的深度学习网络来解决不同的实际问题过程中,这里的不同之处,大部分都是由于这个Head不一样。 不同的实际问题输出的结果不一致,例如目标检测问题输出的是 预测方框,和种类的one-hot变量;语义分割问题输出的是每一个像素点的多分类的one-hot变量;单纯的分类问题输出的是某一类别的one-hot变量。根据不同的输出结果就可以判别网络的全部功能。而控制输出结果的网络结构就是Head
主要分为一下两种类型:(埋个坑)
Dense Prediction:{RPN, YOLO, SSD, RetinaNet, FCOS}
所谓的Dense表示的意思是,最后一层的FeatureMap中的每一个点都要预测出(至少)一个框。这个内容后面在讲YOLO检测器的时候会详细说明,很快就能理解。
Sparse Prediction:{Faster R-CNN, R-RCN}
那么说这么多的内容有什么用呢??所罗列的这几个网络骨架可以当成是深度学习的框架库,之后在做目标检测模型的时候从这里面随便抽几个出来就可以做成一个总的检测模型。
那么本文所讲的YOLO v4 当然也是这样构造出来的:(如下图所示)
where:几个关键词 for backbone:前面讲的四个模块中的一个,Bag of Freebies (免费的赠品) 是说这些技巧的使用不会对模型的推理性能带来影响,并且用了肯定会带来一些模型性能上的提升。
CutMix:就是从A图中随机截取一个矩形区域,用该矩形区域的像素替换掉B图中对应的矩形区域,从而形成一张新的组合图片。同时,把标签按照一定的比例(矩形区域所占整张图的面积)进行线性组合计算损失。如下图所示:
出处这是一篇论文 所以说发论文也没有想象中的这么难 ,有新想法,去做实验得到好的结果就能发表。下面是作者做的一些实验:(从实验的结果来看,确实有效果,想法也很新颖,博主认为能够发表很大程度上是因为想法新颖)
Mosaic data: mosaic数据增强则利用了四张图片,对四张图片进行拼接,每一张图片都有其对应的框框,将四张图片拼接之后就获得一张新的图片,同时也获得这张图片对应的框框,然后我们将这样一张新的图片传入到神经网络当中去学习,相当于一下子传入四张图片进行学习了。yolov4论文中说这极大丰富了检测物体的背景!如下图所示
DropBlock regularization: (论文地址 )
论文主要提出了一种针对卷积层的正则化方法DropBlock,最终在ImageNet分类任务上,使用Resnet-50结构,将精度提升1.6%个点,在COCO检测任务上,精度提升1.6%个点,如下图所示:
(a)原始输入图像
(b)绿色部分表示激活的特征单元,b图表示了随机dropout激活单元,但是这样dropout后,网络还会从drouout掉的激活单元附近学习到同样的信息
(c)绿色部分表示激活的特征单元,c图表示本文的DropBlock,通过dropout掉一部分相邻的整片的区域(比如头和脚),网络就会去注重学习狗的别的部位的特征,来实现正确分类,从而表现出更好的泛化。
Class label smoothing: (主要是用来抑制过拟合现象的)
一般在分类训练任务中,输入图片经过卷积网络的计算,会输出一个当前图片所属类别的置信度分数,之后经过softmax进行归一化处理,最终得到当前输入图片所属某个类别的概率。
接着可以使用交叉熵来计算损失值:
最终在训练网络时,最小化 (预测概率和标签真实概率) 的交叉熵,从而得到最优的预测概率分布。在此过程中,为了达到最好的拟合效果,最优的预测概率分布为
网络会驱使自身往正确标签和错误标签差值大的方向学习,在训练数据不足以表征所有的样本特征的情况下,这就会导致网络过拟合。label smoothing的提出就是为了解决上述问题。最早是在Inception v2中被提出,是一种正则化的策略。其通过"软化"传统的one-hot类型标签,使得在计算损失值时能够有效抑制过拟合现象。更详细的解释 点下这里 某乎上的大佬解释的很详细
Bag of Specials(BOS): 特价餐, 意思说有一些方法的使用可以在付出很小的代价下是模型的性能得到很大的提升
for detector:强调的是 Heda 和训练的部分
1. CIoU-loss: (详细)CIOU-loss yolo3是该论文《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》提出来的。该文章于2019年11月正式发表出来,文章题目是DIOU Loss,其实它提出了两个IOU Loss:DIOU和CIOU,C是指能包含predict box和Ground Truth box的最小box
2. CmBN:(搬运)(搬运) BN -> CBN -> CMBN(Cross mini-Batch Normalization)
3.DropBlock Regularization: (搬运)
一句话概括各种dropout方法:
Dropout [1]:完全随机扔
SpatialDropout [2]:按channel随机扔
Stochastic Depth [3]:按res block随机扔
DropBlock [4]:每个feature map上按spatial块随机扔
Cutout [5]:在input层按spatial块随机扔
DropConnect [6]:只在连接处扔,神经元不扔。
........下一个在哪扔?
4. Mosaic data augmentation:(搬运) 马赛克数据增强,参见本文前文的 Mosaic data,
在深度学习中,当数据量不够大时候,常常采用下面4中方法:
1. 人工增加训练集的大小. 通过平移, 翻转, 加噪声等方法从已有数据中创造出一批"新"的数据.也就是Data Augmentation
2. Regularization. 数据量比较小会导致模型过拟合, 使得训练误差很小而测试误差特别大. 通过在Loss Function 后面加上正则项
可以 抑制过拟合的产生. 缺点是引入了一个需要手动调整的hyper-parameter. 详见 https://www.wikiwand.com /en/Regularization_(mathematics)
3. Dropout. 这也是一种正则化手段. 不过跟以上不同的是它通过随机将部分神经元的输出置零来实现. 详见 http://www.cs.toronto.edu/~hinton/absps/JMLRdropout.pdf
4. Unsupervised Pre-training. 用Auto-Encoder或者RBM的卷积形式一层一层地做无监督预训练, 最后加上分类层做有监督的Fine-Tuning. 参考 http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207.1102&rep=rep1&type=pdf
5. Self-Adversarial Training : 自对抗训练,(搬运)
直观上来讲,可以打个比方,有时候学一个知识点,会做一些简单的题目,你以为自己会了,可是题目难度上来一点,就发现其实没理解。深度学习方法中的一大问题是损失函数太“肤浅”,只能衡量一些很表面的误差,就像那些简单的题目。比如交叉熵,实际就是衡量鹦鹉学舌的能力。而对抗学习,以及GAN,实际上都是度量学习的思想,既然现在的损失函数不好用,那么利用神经网络学习出一个更好用,更深刻的损失函数来,类似于加大题目难度,从多角度评价对知识点的理解。就像厨师只有懂得如何而评判什么菜是好吃的,才能作出好吃的菜来。
6. Eliminate grid sensitivity:(网格消除敏感)
7. Using multiple anchors for a single ground truth
8. Cosine annealing scheduler: 模拟余弦退火, 学习率
9. Optimal hyper-parameters
10. Random training shapes
11. Mish activation, SPP-block, SAM-block, PAN path-aggregation block, DIoU-MMS
这里也有一篇文章写得很不错,可以参考了 一下 只不过 和博主写文章的 侧重点不一样
Yolo v4的前生:
1. yolo v4使用的是 yolov3的检测器头,使用的是三个尺度的检测头,分别负责大小不同的三个尺度的框,
它所使用的darknet53 是基于resblock构建的
学习一个模型,一般分为一下三个部分:
1. 前向计算部分【90%】一般要搞清楚,一个数据输出进来,经过怎样的计算,得到一个怎样的结果,在各个结果是如何表达的
2. 损失函数: mean square error:MSE【9%】
3. 反向传播部分(一般)
分类模型的输入和输出:
输入: image 实质上还是一个矩阵
输出:Onehot 向量
一个简单的前向过程: img3->cbrp16->cbrp32-cbrp64-cbrp128-[...]->fc256->fc[10]
cbrp:Conv,BN,Relu,Pooling
fc[10]:就是假设要分的是10类,对应的输出为【p0, p1, p2, p3, p4, p5, p6, p7, p8, p9】一共10个概率,概率最大的隶属那一类
简单的loss函数: loss = , 其实就是设计一个函数计算预测值和目标值之间的差值
反向传播过程:是根据loss函数对网络中的卷基层的权重进行求倒数。
上文的分析可以知道,网络的功能是通过网络的输出层来体现的,对于一个纯分类的问题,最终的输出是one-hot向量,
而对于目标检测来讲,输出的不仅仅是分类的类别,还需要得到的是目标检测输出的外围坐标。所以实现这样的功能的网络该如何实现呢?
下面介绍一下yolo v1的具体做法。
在揭晓答案之前可以思考这个几个问题:
1. 目标检测问题的输出是什么呢? 怎么用数字进行表示?
2. 分类模型的设计方法,是否能用到检测上?
回答这两问题:
1. 检测问题的输入是: image 是一个矩阵 可以直接用矩阵表示
输出是:想要得到目标的位置 和目标的类别 可以考虑使用一个向量来表示:
[x, y, w, h, p1, p2, p3, p4] or[Cx, Cy, w, h] or angle 等等 可以代表目标位置的方法 加上 目标的判别 one-hot变量
关于目标的位置描述方法,一般采用矩形窗,如下图所示:
矩形窗设计和描述都比较简单,或给出左上角点的坐标和矩形窗的偏执,或给出矩形窗中心的坐标和偏执,
但是会发现,对于那些相对于水平线倾斜的目标矩形窗检测就不是最好的方案了,这里不拓展讲,只是简单思索一下。
2.这个问题:
若果掌握了分类的设计方法,那么检测问题如何解决呢?
遍历性的分类,按照一定大小的窗口遍历图像所有的位置,每一个位置都会输出一个one-hot变量,设置阈值将数据进行全局比较,然后对剩下的数据进行内部的比较,便可以得到相应的类别和预测的概率值,同时也获得了目标框的位置。
这样的分析也存在一个问题: 遍历所有的位置也就是每个像素都要遍历,其次目标的框的大小不能够知道或者差距很大, 这样的不确定可能或造成循环的时间很长,特别是目标框的大小不确定,那么就不知道要测试多少个大小不同的框。