目标检测学习--YoLov1

论文地址:

《You Only Look Once: Unified, Real-Time Object Detection》

官方代码地址:

GitHub链接地址 

目标检测是一件比较实际的且具有挑战性的计算机视觉任务,其可以看成图像分类与定位的结合,给定一张图片,目标检测系统要能够识别出图片的目标并给出其位置,由于图片中目标数是不定的,且要给出目标的精确位置,目标检测相比分类任务更复杂。

对于一张图片有多个目标的目标检测任务主要有以下难点:

  • 物体位置不确定
  • 物体视觉大小不确定,不是指物体大小,而是指物体在图片中的大小(近大远小)
  • 物体的种类不确定

目标检测回顾: 

(1). deformable parts models (DPM)

利用滑动窗口的思路,可以直观地理解为通过一个窗口在图片上滑动着一步一步检测,这种方法直观,但缺陷也十分明显:注意到物体在图中的位置和大小本身都是不确定的,此时移动的步长,起始位置,框的大小等都有很多的可能,因此计算量巨大,如果一个物体正好出现在一个滑窗中,那么我们就可以把这个滑窗的位置认为是这个物体所在的位置;

如何保证物体正好出现在一个滑窗中呢,可以通过设置滑窗每次滑动的距离叫做步长,如果把步长设置的特别小,如仅为一个像素点,那么就一定可以保证物体可以正好出现在某个窗口中了;

如何保证不同大小的物体能正好在滑窗内呢,可以通过设计不同大小的滑窗,我们可以设计几十种不同大小的滑窗口,让他们按照最小的步长滑动,把滑窗里的所有图片都放入分类器中;

问题:使用DPM滑窗法可能最后会得到几十万个滑动窗口,计算量巨大;

扫描二维码关注公众号,回复: 16246878 查看本文章

(2). R-CNN系列

R-CNN系列算法(R-CNN、SPPNet、Fast R-CNN、Faster R-CNN)均是采用two-stage的方法步骤为首先提取region proposal然后分类+边框回归:

先生成多个候选区域,使用启发式方法(selective search)或者CNN网络(RPN)产生Region Proposal,然后再在Region Proposal上做分类与回归,大概2000个左右,然后对每个候选区进行目标识别;总体来说,R-CNN系列依然是两阶段处理模式:即先提出候选区,再识别候选区中的对象;

问题:R-CNN系列速度较慢,比较耗时,本身候选区域较多时带来的大量的特征数据很占存储,使用单一网络CNN生成region proposal也会比较耗时,在region propoal上需要对每个候选区域进行物体分类也会比较耗时;

(3). YOLO系列

YOLO的全称是you only look once,指只需要浏览一次就可以识别出图中的物体的类别和位置,因为只需要看一次,YOLO被称为Region-free方法,相比于Region-based方法,YOLO不需要提前找到可能存在目标的Region,YOLO这样的Region-free方法只需要一次扫描,也被称为单阶段(1-stage)模型,Region-based方法方法也被称为两阶段(2-stage)方法;

思路:将目标检测问题转化为一个回归问题进行求解,也就是说将图像的像素数据作为输入,直接输出物体的位置和所属于的类别的置信度(以一个向量形式表示),属于端到端的模型形式;

由于仅使用一个neural network同时预测bounding box的位置和类别,由于不需提取region proposal,而是直接在整幅图像上进行检测,因此YOLOv1可以联系上下文信息和特征,减少将背景检测为物体的错误(false positive),检测速度较快

其中YOLOv1学习到的是目标的泛化表示(generalizable representations),泛化能力非常强,更容易应用于新的领域或输入,例如模型训练认识了类别猫,能够以更好的泛化性能同时认出来别的图片里的不太一样的猫;

YOLOv1原理:

物体检测的目的是在一张图片中找出物体,并给出它的类别和位置。目标检测是基于监督学习的,每张图片的监督信息是它所包含的N个物体,每个物体的信息有五个,分别是物体的中心位置(x,y)和它的高(h)宽(w),最后是它的类别;YOLO的预测是基于整个图片的,并且它会一次性输出所有检测到的目标信息,包括类别和位置;

YOLOv1检测流程:

a51ca3255f26d1d7df25a23edbcc2a1b.png

由于不需提取region proposal,则YOLOv1的检测流程很简单:

  • Resize image:由于CNN中用全连接层进行分类回归,所以需要将输入图片resize到448x448;
  • Run ConvNet:使用CNN提取特征,FC层输出分类和回归结果;
  • Non-max Suppression:非极大值抑制筛选出最终的结果;

 YOLOv1检测步骤:

(1). 分割图片,图片分割为gif.latex?s%5E%7B2%7D(7*7)个grid,每个grid的大小相等,如下图所示:

964fd82761cfa484ea8685cd33e836a8.png

如果我们让每个框只能识别出一个物体,且要求这个物体必须在这个框之内,这与滑窗法基本没有区别,而YOLOv1的一大创新点在于物体的中心落在grid中,则使用该grid来分类该目标,如上图中大红框中心点所在的小红框处,同时需要注意的是,grid需要预测每个目标的类别,需要用one_hot进行编码

(2).生成bbox, gif.latex?s%5E%7B2%7D个框每个都预测出B个bounding box,每个bbox都有5个变量:物体的中心位置(x,y)和它的高(h)宽(w),以及这次预测的置信度confidence

下图为每个框生成2个bbox,用以得到物体的位置:

275c329216873eb7e971dc930e369482.png

bbox可以锁定物体的位置,即输出四个关于位置的值分别是x、y、h和w;在处理输入的图片的时候想让图片的大小任意,但是,如果输出的位置坐标是一个任意的正实数,模型很可能在大小不同的物体上泛化能力有很大的差异,所以需要对数据进行归一化,让连续数据的值位于0和1之间;对于x和y而言,只要让真实的x除以grid的宽度,让真实的y除以grid的高度就可以;因为一个物体很可能远大于grid的大小,预测物体的高和宽很可能大于bbox的高h和宽w,则w除以bbox的宽度,h除以bbox的高度依旧不在0和1之间,所以是让w除以整张图片的宽度h除以整张图片的高度,这样处理后的数据就可以在0和1之间

下图为一448*448的图片,整张图片分割为3*3的grid,下图为计算x,y,w,h的真实值(ground truth)的过程:

42bef1586dda4fc98140e0dfbf5e35a1.png

每一个grid设定了B个可能的候选框bbox,并计算每一个可能的候选框bbox的得分,即置信度,置信度是一个这个bbox里确实框住了某一个物体该bbox和真实的目标检测框的重合程度的综合度量指标,置信度confidence的计算公式是: 

gif.latex?C%3DPr%28obj%29*IOU_%7Btruth%7D%5E%7Bpred%7D

gif.latex?Pr%28obj%29是指一个grid有物体的概率,在有物体的时候为1,没有物体的时候为0;

gif.latex?IOU_%7Btruth%7D%5E%7Bpred%7D的意思是预测的bounding box和真实的物体位置ground truth的交并比;

同时计算每一个grid对应为第i个类别的概率,记作gif.latex?Pr%28class_%7Bi%7D%5Cmid%20object%29,在测试的时候,则该grid内的所有的B个预测框bbox都对应乘上这个Pr值得到:

gif.latex?confidence%3DPr%28class_%7Bi%7D%5Cmid%20object%29*Pr%28object%29*IOU_%7Btruth%7D%5E%7Bpred%7D

计算得到的confidence也就是每一个预测框框住的是分类i的物体的一个综合置信度得分概率;

那么如果一个物体较大,被多个grid识别应该怎么处理呢?怎么判断这几个grid识别的是同一个物体呢?如下图B1、B2、B3、B4所示:55165d6324dc4170b19314194f047ba9.png

理论上只用gif.latex?Pr%28obj%29就可以选出负责识别物体的grid,但是可能会不太精确, 因此置信度confidence需要引入gif.latex?IOU_%7Btruth%7D%5E%7Bpred%7D,因为bbox是用物体中点坐标+宽高表示的,每个grid预测的bbox都要求其中心在这个grid内,那么如果不是包含目标中心的grid,其他的grid的IOU自然而言就比较低,因此其相应的confidence就降下来了,这样就可以选择出置信度最高的bbox,因此就可以选择出包含有目标物体中心的grid;

那么怎么判断出这几个bbox识别的是同一个物体呢?

非极大值抑制Non-maximal suppression(NMS)

 假设上面的grid中B1,B2,B3和B4的bbox识别出来的都是狗,那么我们保留B1,然后判断B2,B3和B4要不要删除,因此把B1成为极大bbox,计算极大bbox和其他几个bbox的IOU,如果超过一个阈值如0.5,就认为这两个bbox实际上预测的是同一个物体,就把其中confidence比较小的删除;

下面计算一下上图大雁样本的groun truth:

上图有3*3=9个grid,每个grid有2个bbox,每个bbox有5个预测值,假设分类器可以识别出3中物体,那么ground truth的总长度为:

gif.latex?3*3*%285*2+3%29%3D117

我们规定每个grid的ground truth的顺序为confidence, x, y, w, h, c1, c2, c3,其中c1,c2,c3表示一个grid中物体的类别,例如图中没有物体的grid的confidence=0,大雁用one_hot编码表示为100,即c1=1,c2=0,c3=0,中间有物体(大雁)的ground truth应该是:

gif.latex?IOU_%7Btruth%7D%5E%7Bpred%7D, 0.48, 0.28, 0.50, 0.32, 1, 0, 0

例子: 

8ff95977554945d2961c41f2b452851a.png

这里的S=7,也就是将整张图片分为49个grid,对应的每一个grid设定考虑B个不同的候选框,计算共S*S*B个bbox的预测信息,每一个bbox都对应一个五维的向量作为预测值,包括:预测框的中心对应当前的小区域的相对位置;预测框的大小相对于整个图片的相对比值;置信得分=P(物体)* IOU,同时对于一个C分类问题,则每一个grid都有一个长度为C的向量,表示该grid对应的预测框是i分类的概率;也就是说,假设有gif.latex?s%5E%7B2%7D个框,每个框的bbox个数为B,分类器可以识别出C种不同的物体,那么所有整个ground truth的长度为:

gif.latex?S*S*%28B*5+C%29

例如论文中S=7,B=2,C=20,输入图像被划分为7x7的单元格(grid),输出tensor中的7x7对应着输入图像的7x7个单元格,每个单元格对应输出30维的向量,所以整个ground truth的长度为49*30,即共49个grid,每个框生成2个bbox,每个bbox需要生成5个参数,则共有10个参数,分类器可以识别出20个目标类别,下图其概率值是在各个边界框置信度下的条件概率;

1fe33ce3d644d7230391098e20fe8564.png

2个bounding box的位置:使用归一化后的x,y,w,h,这有利于之后的bbox的回归;

2个bounding box的置信度:每一个置信度包含两方面,一是该边界框含有目标的可能性大小,二是该边界框的准确度;

20类对象分类的概率:由有物体的grid负责预测的两个边界框中的目标属于各个类别的概率,注意这些概率值是在各个边界框置信度下的条件概率,即gif.latex?Pr%28class_%7Bi%7D%5Cmid%20obj%29,也就是说不管一个grid预测多少个边界框,该grid只预测一组类别概率值;

损失函数

e1d9ca7662c5a8d7fe10543cd37133dd.png

损失函数由5项误差组成,gif.latex?1_%7Bij%7D%5E%7Bobj%7D表示第i个grid中的第j个bbox是否负责这个object,与object的ground truth box的IOU最大的bbox负责该object,即表示这个grid里有没有物体,如果这个grid没有物体,gif.latex?1_%7Bij%7D%5E%7Bobj%7D%3D0 ,如果这个grid有物体, gif.latex?1_%7Bij%7D%5E%7Bobj%7D%3D1 ;与gif.latex?1_%7Bij%7D%5E%7Bobj%7D相反的为gif.latex?1_%7Bij%7D%5E%7Bnoobj%7D,如果没有物体,gif.latex?1_%7Bij%7D%5E%7Bnoobj%7D%3D0 ,如果有物体,gif.latex?1_%7Bij%7D%5E%7Bnoobj%7D%3D1  ,gif.latex?1_%7Bi%7D%5E%7Bobj%7D判断是否有object的中心落在框i中,包含有物体中心的grid就负责预测该物体的类别概率;

位置误差:损失函数的第一、二项为坐标位置预测,主要是计算bbox的x,y,w,h和对应的ground truth box的x,y,w,h之间的误差平方和,需要注意的是并不是所有的bbox都参与该loss的计算,必须是第i个grid中存在object,并且该grid中的第j个bbox和ground truth box有最大的IoU值,那么这个bbox j才参与loss的计算,其他的不满足条件的bbox不参与计算;此外,因为误差在小IOU的bbox上体现的更明显,即小位置上的偏差可能对大的bbox影响不是很大,但是对小的bbox的影响就比较明显,所以为了给不同size的bbox的位置loss赋予不同的权重,因此需要对w和h开方后才进行计算;根据下图gif.latex?y%3D%5Csqrt%7Bx%7D的函数图像可知,当x较小时,x的一点小的变化都会导致y大的变化,而当x较大的时候,x的一点儿小的变化不会让y的变化太大。 但是该方法只能减弱这个问题,并不能彻底解决这个问题,使用平方根的MSE其实就是像让模型对小尺度的物体更敏感。或者说,对大的和小的物体同样敏感;

87cd116866ab14ac85779ed199b06c4c.png

置信度误差:损失函数的第三、四项为两类置信度误差,一是有object的grid的置信度计算,另一种是没有object的grid的置信度计算,两种情况都是单元格中所有的bbox都参与计算,两种置信度误差都用误差平方和;对于有object的grid中的bbox的置信度的ground truth就是gif.latex?1*IOU_%7Bpred%7D%5E%7Btruth%7D。需要注意的是这个IOU是在训练过程中不断计算出来的,因为网络在训练过程中每次预测的bbox是变化的,所以bbox和ground truth计算出来的IOU每次也会不一样,而对于没有object的grid中的bbox的置信度的ground truth为gif.latex?0*IOU_%7Bpred%7D%5E%7Btruth%7D%3D0,因为不包含物体。 

分类误差:损失函数的第五项为对象分类误差,将其当作回归误差来计算,使用误差平方和来计算分类误差,需要注意的是只有包含object的grid才参与分类loss的计算,即有object中心点落入的grid才进行分类loss的计算,而这个grid的ground truth label就是该物体的label;

权重:为了使得三种误差达到平衡,就需要给不同的误差赋予不同的权重:

更重视2个4维的坐标预测,给这些损失前面赋予更大的loss weight, 记为gif.latex?%5Clambda%20_%7Bcoord%7D

对没有object的bbox的confidence loss,赋予小的loss weight,记为gif.latex?%5Clambda%20_%7Bnoobj%7D

有object的bbox的confidence loss和分类的loss的loss weight正常取1;

论文中gif.latex?%5Clambda%20_%7Bcoord%7D=5和gif.latex?%5Clambda%20_%7Bnoobj%7D=0.5,也就是放大第一项和第二项的损失函数,缩小第四项的损失函数,这样做的原因是让梯度更稳定,如果grid中不含有物体,它对1,2,3,5项没有影响,如果调节第四项,会让含有物体的grid的confidence发生改变,这可能使其他项的梯度剧烈变化,从而带来模型上的不稳定;

网络设计

整体的网络设计依赖卷积神经网络的思路,也就是共24层卷积后面跟着两层全连接层输出需要的预测的向量,也就是先卷积提取特征再到全连接层进行预测,如下图所示:

a318c7f8952165078fae07d0fb302fe4.png

1.输入:448*448*3,由于网络最后需要接入两个全连接层,全连接层需要固定尺寸的输入,故需要将输入resize成固定大小;

2.Conv+FC:主要使用1*1卷积来做channle reduction,然后紧跟3x3卷积,对于卷积层和全连接层,采用Leaky ReLU激活函数:max(x,0.1x) ,但是最后一层采用线性激活函数;

3.输出:最后一个FC层得到一个1470*1的输出,将这个输出reshap一下,得到7*7*30的一个tensor,即最终每个grid都有一个30维的输出代表预测结果,具体如下:

d78ac901b7aae79319e9caa2aed25685.png

Training 训练 

预训练

预训练在ImageNet 1000-class competition dataset上面进行,将前面的20层卷积拿出来,之后再在这20层后连上4层卷积和2层全连接层进行预训练,前20层是用预训练网络初始化,最后的这6层是随机初始化的并在训练过程中更新权重;后续fine tune的时候最后的4层卷积和2个全连接层都是随机初始化权重的,也就是说这里的预训练只是针对最前面的20层卷积,注意这里最后输出的五维向量中,对应的x,y和w,h都是标准化过的0-1之间的值;

训练样本构造

作为监督学习,我们需要先构造好训练样本,才能让模型从中学习,对于一张输入图片,其对应输出7*7*30张量,也就是通常监督学习所说的标签y或者label:

fb82e496409ee8036cc8d82aea205f3f.png

首先,输出的7*7维度对应于输入的7*7网格,输出的30维向量对应于20个对象分类的概率、2个bounding box的位置和2个bounding box的置信度;

训练参数设置

几个原论文给出的参考:

学习率处理:第一个epoch先从gif.latex?10%5E%7B-3%7D逐渐上升到gif.latex?10%5E%7B-2%7D,注意不是一开始用大学习率,会很容易发散
原论文保持gif.latex?10%5E%7B-2%7D又训了75个epoch,再用gif.latex?10%5E%7B-3%7D训练个30epoch,再用gif.latex?10%5E%7B-4%7D训练30个epoch;原论文手动调了学习率可能还是有一定影响的;
缓解过拟合:这里为了缓解过拟合用了dropout,参数为0.5,同时可以配合数据增强的方法,原论文用了随机缩放和平移(大概为 20% 的原图大小)

模型预测

和训练同理,输入一张图片,将输出一个7*7*30的张量(tensor)来表示图片中所有网格包含的对象(概率)以及该对象可能的2个位置(bounding box)和可信程度(置信度),具体会给出S*S*B个框的对应的置信度,同时通过(x,y,w,h)标记好框的位置,注意计算每一个grid的对应的各个类别的概率;

测试

将一张图输入到网络中,然后得到一个7*7*30的预测结果,然后将计算结果中的每个单元格预测的类别信息gif.latex?Pr%28class_%7Bi%7D%5Cmid%20object%29和每个bbox的置信度信息gif.latex?C%3DPr%28obj%29*IOU_%7Btruth%7D%5E%7Bpred%7D相乘即可得到每个bbox的class-specific confidence score:

gif.latex?confidence%3DPr%28class_%7Bi%7D%5Cmid%20object%29*Pr%28object%29*IOU_%7Btruth%7D%5E%7Bpred%7D

如下图所示: 

1c7c47397bb1e6cb965903a9e70ff116.png

根据同样的方法可以计算得到7*7*2=98个bbox的confidence score,然后根据confidence score对预测得到的98个bbox进行非极大值抑制,得到最终的检测结果;

等式右边第一项就是每个grid预测的类别信息,第二、三项就是每个bbox预测的confidence,这个乘积即encode了预测的bbox属于某一类的概率,也有该bbox准确度的信息;

146c455709e54b9eb57a2929b1a7e94e.png

3d9983151f5eb8ce5f220f8a54cdefab.png

对每一个grid的每一个bbox执行同样操作:7*7*2=98 bbox(每个bbox既有对应的class信息又有坐标信息):

cd12749a4023dad46f5d71b092310f00.png

eda6460739bf58d040509c3e0554999b.png

30f2bdfbaff1bd4bbfea0012f5523615.png

得到每个bbox的分类置信度得分以后,设置阈值,滤掉得分低的bbox,对保留的bbox进行NMS处理,就得到最终的检测结果: 

ba9766b0fe2d7381d4fa7ff6a4077745.png

 总结

一张图片最多可以检测出49个对象:每个30维向量中只有一组(20个)对象分类的概率,也就只能预测出一个对象,所以输出的 7*7=49个 30维向量,最多表示出49个对象;

总共有49*2=98个候选区bbox,每个30维向量中有2组bounding box,所以总共是98个候选区;

YOLO的bbox并不是Faster RCNN的Anchor:Faster RCNN等一些算法采用每个grid中手工设置n个Anchor(即先验框,预先设置好位置的bbox)的设计,每个Anchor有不同的大小和宽高比,YOLO的bbox看起来很像一个grid中2个Anchor,但不是,YOLO并没有预先设置2个bbox的大小和形状,也没有对每个bbox分别输出一个对象的预测,它仅仅是对一个对象预测出2个bounding box,选择预测得相对比较准的那个;这里采用2个bbox,有点不完全监督算法,而是像进化算法,如果是监督算法,我们需要事先根据样本就能给出一个正确的bbox作为回归的目标,但YOLO的2个bbox事先并不知道会在什么位置,只有经过前向计算,网络会输出2个bbox的信息,这两个bbox与样本中对象实际的bbox计算IOU,这时才能确定,IOU值大的那个bbox作为负责预测该对象的bbox;训练开始阶段,网络预测的bbox可能都是乱来的,但总是选择IOU相对好一些的那个,随着训练的进行,每个bbox会逐渐擅长对某些情况的预测(可能是对象大小、宽高比、不同类型的对象等),所以,这是一种进化或者非监督学习的思想,

在设置训练样本的时候,样本中的每个object且仅归属到一个grid,即便有时object跨越了几个grid,也仅指定其中一个,具体就是计算出该object的bbox的中心位置,这个中心位置落在哪个grid,该grid对应的输出向量中该对象的类别概率是1(该gird负责预测该对象),所有其它grid对该object的预测概率设为0(不负责预测该对象);

可以调整网格数量、bounding box数量:7*7网格,每个grid有2个bbox,对448*448输入图像来说覆盖粒度有点粗,我们也可以设置更多的网格以及更多的bounding box;

步骤:

  1. 首先固定图像输入大小为448*448*3;设定存在C = 20种不同类别的目标,每一个grid都给定C个可能的概率,表示该grid内的预测框bbox对应的目标为第c类目标的概率;
  2. 将整张图片分为S*S的小区域(grid cell),假设S = 7;
  3. 每一个grid设定搜索B个预测框(bounding box),假设B = 2;
  4. 每一个bbox给出一个五维向量(x,y,w,h,conf)作为预测输出,x,y表示预测框中心点相对于当前的小区域(grid cell)的位置,w,h表示预测框的宽高相对于整张图片大小的比例,conf为该搜索框的置信度,由Pr(是否包含object)*IOU(预测框和真实框的交并比)进行计算,一个预测框的置信度是通过模型输出的,通过全连接层预测出一个值;而ground truth=该预测框的真实的置信度,此时真实的bbox的坐标都有,则中心位置可以计算,若中心位置在这个小区域内,则Pr(是否包含obj)=1,得到ground truth后就是训练模型预测的值不断逼近真实值;
  5. 所以最后的输出大小为S*S*(B*5+C)=7*7*30 ,注意是三维的;

优点

  1. 速度更快,YOLO 的检测速度比往常的模型快很多,实验表示即使是精简版的YOLO fast在FPS155的速度下也能达到不错的精度;
  2. 更少出现背景误检的问题,也就是更低的background error,YOLO 的输入是整张图直接扔进去,也就是说会有更多的上下文信息,故相较于其他模型不容易从局部上将背景作误判;
  3. 模型泛化能力比往常的模型要好;

缺点

  1. YOLO中每个grid只预测两个bbox和一个类别,这就限制了能预测重叠或邻近物体的数量,比如说两个物体的中心点都落在这个grid中,但是这个grid只能预测一个类别,即假设强,假设了每一个小区域内的目标不超过B个(原文B=2),同时假设了中心点落在同一个小区域内的所有目标都是同一类的物体,也就是说如果出现很多的目标密集挤在一起,此时YOLO的效果不一定会很好,会识别不全,算是 YOLO 不擅长的一个场景;
  2. 泛化能力还是有限,主要对于长宽比不太一样的情况会表现不佳,比如2:1的瘦狗看多了会认不出1:1的胖狗,原作者将原因归结于提取的用于预测的特征还是比较粗糙,因为本身存在对原图像多次下采样的结构;
  3. 损失函数部分不同大小的框对于损失函数的贡献的区分不明显,相同的差值,大小不同的框对于损失函数的贡献应当是不同的,也就是前面提到了在位置误差的部分(针对w和h),如果是一个大小为10的框预测误差为1还好,但是大小为1的框预测误差为1不合理,使用需要开根号后再进行误差平方差进行计算,但是实验表示这样的处理效果还是有限。

 

参考

YOLO v1深入理解

图解YOLO 

YOLOv1详解 

YOLO介绍 

tensorflow代码实现

仅为学习记录,侵删! 

猜你喜欢

转载自blog.csdn.net/panghuzhenbang/article/details/125371184
今日推荐