YOLO学习笔记(一)

不错的yolo的介绍:https://blog.csdn.net/m0_37192554/article/details/81092514

https://blog.csdn.net/Dongjiuqing/article/details/84763430

https://www.cnblogs.com/fariver/p/7446921.html

https://blog.csdn.net/u014380165/article/details/72616238 

计算机视觉的任务:

语义分割;单目标检测;多目标检测;实例分割

yolov1是一个快速的one-stage目标检测器,独树一帜的用划分网格的策略实现目标检测。在YOLO算法中把物体检测(object detection)问题处理成回归问题,用一个卷积神经网络结构就可以从输入图像直接预测bounding box和类别概率。

yolo算法的全称是You Only Look Once: Unified, Real-Time Object Detection,这个题目基本上把Yolo算法的特点概括全了:You Only Look Once说的是只需要一次CNN运算,Unified指的是这是一个统一的框架,提供end-to-end的预测,而Real-Time体现是Yolo算法速度快。

YOLO算法的优点:

1、YOLO的速度非常快。在Titan X GPU上的速度是45 fps(frames per second),加速版的YOLO差不多是150fps。

2、YOLO是基于图像的全局信息进行预测的。这一点和基于sliding window以及region proposal等检测算法不一样。与Fast R-CNN相比,YOLO在误检测(将背景检测为物体)方面的错误率能降低一半多。

3、YOLO可以学到物体的generalizable representations。可以理解为泛化能力强。

4、准确率高,有实验证明。

算法结构图如下:结构上主要的特点就是 unified detection,不再是原来许多步骤组成的物体检测,这使得模型的运行速度快,可以直接学习图像的全局信息,且可以end-to-end训练。

滑动窗口

采用滑动窗口的目标检测算法可以将检测问题转化为了图像分类问题。其基本原理就是采用不同大小和比例(宽高比)的窗口在整张图片上以一定的步长进行滑动,然后对这些窗口对应的区域做图像分类,这样就可以实现对整张图片的检测了。但是这个方法有致命的缺点,就是你并不知道要检测的目标大小是什么规模,所以你要设置不同大小和比例的窗口去滑动,而且还要选取合适的步长。但是这样会产生很多的子区域,并且都要经过分类器去做预测,这需要很大的计算量,所以你的分类器不能太复杂,因为要保证速度。解决思路之一就是减少要分类的子区域,这就是R-CNN的一个改进策略,其采用了selective search方法来找到最有可能包含目标的子区域(Region Proposal),其实可以看成采用启发式方法过滤掉很多子区域,这会提升效率。

如果你使用的是CNN分类器,那么滑动窗口是非常耗时的。但是结合卷积运算的特点,我们可以使用CNN实现更高效的滑动窗口方法。这里要介绍的是一种全卷积的方法,简单来说就是网络中用卷积层代替了全连接层,如图4所示。输入图片大小是16x16,经过一系列卷积操作,提取了2x2的特征图,但是这个2x2的图上每个元素都是和原图是一一对应的,如图上蓝色的格子对应蓝色的区域,这不就是相当于在原图上做大小为14x14的窗口滑动,且步长为2,共产生4个字区域。最终输出的通道数为4,可以看成4个类别的预测概率值,这样一次CNN计算就可以实现窗口滑动的所有子区域的分类预测。这其实是overfeat算法的思路。之所可以CNN可以实现这样的效果是因为卷积操作的特性,就是图片的空间位置信息的不变性,尽管卷积过程中图片大小减少,但是位置对应关系还是保存的。说点题外话,这个思路也被R-CNN借鉴,从而诞生了Fast R-cNN算法。

Yolo算法的设计理念

整体来看,Yolo算法采用一个单独的CNN模型实现end-to-end的目标检测。首先将输入图片resize到448x448,然后送入CNN网络,最后处理网络预测结果得到检测的目标。相比R-CNN算法,其是一个统一的框架,其速度更快,而且Yolo的训练过程也是end-to-end的。

具体来说,Yolo的CNN网络将输入的图片分割成,其中前4个表征边界框的大小与位置,而最后一个值是置信度。

整体来看,Yolo算法采用一个单独的CNN模型实现end-to-end的目标检测,整个系统如图5所示:首先将输入图片resize到448x448,然后送入CNN网络,最后处理网络预测结果得到检测的目标。其速度更快,而且Yolo的训练过程也是端到端的。与滑动窗口不同的是,yolo先将图片分成S*S个块每个单元格会预测B个边界框(bounding box)以及边界框的置信度(confidence score)。所谓置信度其实包含两个方面,一是这个框中目标存在的可能性大小,二是这个边界框的位置准确度。前者我们把它记做Pr(obj),若框中没有目标物,则Pr(obj)=0,若含有目标物则Pr(obj)=1 。那么边界框的位置的准确度怎么去判断呢?我们使用了一种叫做IOU(交并比)的方法,意思就是说我预测的框与你真实的框相交的面积和预测的框和真实框合并的面积的比例。我们可以记做IOU(pred),那么置信度就可以定义为这两项相乘。so,现在有了另一个问题,我每个格子预测的边界框应该怎么表示呢?  边界框的大小和位置可以用四个值来表示,(x,y,w,h)注意,不要凭空想象是一个矩形对角两个点的位置坐标,这里面的x,y是指对预测出得边界框的中心位置相对于这个格子的左上角位置的偏移量,而且这个偏移量不是以像素为单位,而是以这个格子的大小为一个单位。如果不明白可以用下面这张图去举个例子。下面这个框的中心点所在的位置,相对于中心点所在的这个格子的x,y差不多是0.3, 0.7,  (不明白的话就仔细琢磨一下)。而这个w,h指的是这个框的大小,占整张图片大小的宽和高的相对比例,想一下,有了中心点的位置,有了框的大小,画出一个框是很容易的对吧。(x,y,w,h,c)这五个值理论上都应该在[0,1]区间上。最后一个c是置信度的意思。一般一个网格会预测多个框,而置信度是用来评判哪一个框是最准确的,我们最想得到的框。我觉得这同一个Cell的B个Box之所以能分别兼顾大小不同的Object,是靠初始化过程中参数的随机差异以及BP训练过程中确定用哪个Box的筛选机制(挑出与GroundTruth IOU最大的那个进行BP传导)导致的,这个就是所谓竞争机制。

框预测好了,接下来就是分类的问题,每个单元格预测出(x,y,w,h,c)的值后,还要给出对于C个类别的概率值。现在重新提一下字母的含义,B是边界框的个数,C是我有多少个类别要分类。S是划分单元格的个数。那么我每个单元格要预测B*5+C个值。如果将输入图片划分为S×S网格,那么最终预测值为S×S×(B∗5+C)大小的张量。整个模型的预测值结构如下图所示。对于PASCAL VOC数据,其共有20个类别,如果使用S=7,B=2S=7,B=2,那么最终的预测结果就是7×7×307×7×30大小的张量。在下面的网络结构中我们会详细讲述每个单元格的预测值的分布位置。
 

网络设计

Yolo采用卷积网络来提取特征,然后使用全连接层来得到预测值。网络结构参考GooLeNet模型,包含24个卷积层和2个全连接层,如下图所示。对于卷积层,主要使用1x1卷积来做channle reduction,然后紧跟3x3卷积。对于卷积层和全连接层,采用Leaky ReLU激活函数:max(x,0.1x)max(x,0.1x)。但是最后一层却采用线性激活函数。
 

可以看到网络的最后输出为7×7×30大小的张量。这和前面的讨论是一致的。这个张量所代表的具体含义如图所示。对于每一个单元格,前20个元素是类别概率值,然后2个元素是边界框置信度,两者相乘可以得到类别置信度,最后8个元素是边界框的(x,y,w,h)。大家可能会感到奇怪,对于边界框为什么把置信度c和(x,y,w,h)都分开排列,而不是按照(x,y,w,h,c)这样排列,其实纯粹是为了计算方便,因为实际上这30个元素都是对应一个单元格,其排列是可以任意的。但是分离排布,可以方便地提取每一个部分。这里来解释一下,首先网络的预测值是一个二维张量PP,其shape为[batch,7×7×30]。采用切片,那么P[:,0:7∗7∗20]就是类别概率部分,而P[:,7∗7∗20:7∗7∗(20+2)]是置信度部分,最后剩余部分P[:,7∗7∗(20+2):]是边界框的预测结果。这样,提取每个部分是非常方便的,这会方面后面的训练及预测时的计算

下面是训练损失函数的分析,Yolo算法将目标检测看成回归问题,采用的是均方差损失函数。但是对不同的部分造成的误差采用了不同的权重值。还有一点就是较小的边界框的坐标误差应该要比较大的边界框要更敏感。为了保证这一点,将网络的边界框的宽与高预测改为对其平方根的预测,即预测值变为

为什么呢?因为你想一下比如w和h为0.1或者更小,那么我稍微一点点的幅度,我这个框变化就很明显。比如我从0.1到0.15,这个变化相对于0.1增加很多,但是同样的我预测有误差,而误差是从0.4到0.45,这个增大几乎是看不出来的。因此对于一个小框,如果我偏移大的话,会更加影响框的准确性,有可能因为我这一个小小的偏移,导致我这个物体不再框里面了,所以这就是为什么要让小得边界框的误差比大的边界框误差要更加敏感。通过开根号可以达到这个效果,因为一个小于一的数,开平方会被放大,而且越小,开平方后相比原来的数差别就更大。(如果不理解这一点可以慢慢思考一下,或者跳过也没关系,源自吴恩达老师)

(1) 整个损失函数针对边界框损失(图中1, 2, 3部分)与格子(4部分)主体进行讨论。

(2) 部分1为边界框位置与大小的损失函数,式中对宽高都进行开根是为了使用大小差别比较大的边界框差别减小。例如,一个同样将一个100x100的目标与一个10x10的目标都预测大了10个像素,预测框为110 x 110与20 x 20。显然第一种情况我们还可以失道接受,但第二种情况相当于把边界框预测大了一倍,但如果不使用根号函数,那么损失相同,都为200。但把宽高都增加根号时:

(sqrt(20)−sqrt(10)) 2 =3.43 (sqrt(20)−sqrt(10))2=3.43

(sqrt(110)−sqrt(100)) 2 =0.48 (sqrt(110)−sqrt(100))2=0.48


显然,对小框预测偏差10个像素带来了更高的损失。通过增加根号,使得预测相同偏差与更小的框产生更大的损失。但根据YOLOv2的实验证明,还有更好的方法解决这个问题。

(3) 若有物体落入边界框中,则计算预测边界框含有物体的置信度C i  Ci 和真实物体与边界框IoUC i  ˆ  Ci^ 的损失,我们希望两差值越小损失越低。

(4) 若没有任何物体中心落入边界框中,则C i  ˆ  Ci^ 为0,此时我们希望预测含有物体的置信度C i  Ci 越小越好。然而,大部分边界框都没有物体,积少成多,造成loss的第3部分与第4部分的不平衡,因此,作才在loss的三部分增加权重λ nobj =0.5 λnobj=0.5 

(5) 对于每个格子而言,作者设计只能包含同种物体。若格子中包含物体,我们希望希望预测正确的类别的概率越接近于1越好,而错误类别的概率越接近于0越好。loss第4部分中,若p i (c) ˆ  pi(c)^ 中c为正确类别,则值为1,若非正确类别,则值为0。


非极大值抑制算法(non maximum suppression, NMS)

NMS算法主要解决的是一个目标被多次检测的问题,如图中人脸检测,可以看到人脸被多次检测,但是其实我们希望最后仅仅输出其中一个最好的预测框,比如对于美女,只想要红色那个检测结果。那么可以采用NMS算法来实现这样的效果:首先从所有的检测框中找到置信度最大的那个框,然后挨个计算其与剩余框的IOU,如果其值大于一定阈值(重合度过高),那么就将该框剔除;然后对剩余的检测框重复上述过程,直到处理完所有的检测框。Yolo预测过程也需要用到NMS算法。

总之,NMS是大部分深度学习目标检测网络所需要的,大致算法流程为:

1.对所有预测框的置信度降序排序
2.选出置信度最高的预测框,确认其为正确预测(下次就没有他了,已经被确认了),并计算他与其他预测框的IOU
3.根据2中计算的IOU去除重叠度高的,IOU>threshold就删除
4.剩下的预测框返回第1步,直到没有剩下的为止

YOLO的缺点

1.YOLO对相互靠的很近的物体,还有很小的群体 检测效果不好,这是因为一个网格中只预测了两个框,并且只属于一类。

2.同一类物体出现的新的不常见的长宽比和其他情况时,泛化能力偏弱。

3.由于损失函数的问题,定位误差是影响检测效果的主要原因。尤其是大小物体的处理上,还有待加强。

猜你喜欢

转载自blog.csdn.net/weixin_32888153/article/details/84956482