论文地址:
《You Only Look Once: Unified, Real-Time Object Detection》
官方代码地址:
GitHub链接地址
目标检测是一件比较实际的且具有挑战性的计算机视觉任务,其可以看成图像分类与定位的结合,给定一张图片,目标检测系统要能够识别出图片的目标并给出其位置,由于图片中目标数是不定的,且要给出目标的精确位置,目标检测相比分类任务更复杂。
对于一张图片有多个目标的目标检测任务主要有以下难点:
(1). deformable parts models (DPM)
利用滑动窗口的思路,可以直观地理解为通过一个窗口在图片上滑动着一步一步检测,这种方法直观,但缺陷也十分明显:注意到物体在图中的位置和大小本身都是不确定的,此时移动的步长,起始位置,框的大小等都有很多的可能,因此计算量巨大,如果一个物体正好出现在一个滑窗中,那么我们就可以把这个滑窗的位置认为是这个物体所在的位置;
如何保证物体正好出现在一个滑窗中呢,可以通过设置滑窗每次滑动的距离叫做步长,如果把步长设置的特别小,如仅为一个像素点,那么就一定可以保证物体可以正好出现在某个窗口中了;
如何保证不同大小的物体能正好在滑窗内呢,可以通过设计不同大小的滑窗,我们可以设计几十种不同大小的滑窗口,让他们按照最小的步长滑动,把滑窗里的所有图片都放入分类器中;
问题:使用DPM滑窗法可能最后会得到几十万个滑动窗口,计算量巨大;
(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),泛化能力非常强,更容易应用于新的领域或输入,例如模型训练认识了类别猫,能够以更好的泛化性能同时认出来别的图片里的不太一样的猫;
物体检测的目的是在一张图片中找出物体,并给出它的类别和位置。目标检测是基于监督学习的,每张图片的监督信息是它所包含的N个物体,每个物体的信息有五个,分别是物体的中心位置(x,y)和它的高(h)和宽(w),最后是它的类别;YOLO的预测是基于整个图片的,并且它会一次性输出所有检测到的目标信息,包括类别和位置;
YOLOv1检测流程:
由于不需提取region proposal,则YOLOv1的检测流程很简单:
YOLOv1检测步骤:
(1). 分割图片,图片分割为(7*7)个grid,每个grid的大小相等,如下图所示:
如果我们让每个框只能识别出一个物体,且要求这个物体必须在这个框之内,这与滑窗法基本没有区别,而YOLOv1的一大创新点在于物体的中心落在grid中,则使用该grid来分类该目标,如上图中大红框中心点所在的小红框处,同时需要注意的是,grid需要预测每个目标的类别,需要用one_hot进行编码;
(2).生成bbox, 个框每个都预测出B个bounding box,每个bbox都有5个变量:物体的中心位置(x,y)和它的高(h)和宽(w),以及这次预测的置信度confidence:
下图为每个框生成2个bbox,用以得到物体的位置:
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)的过程:
每一个grid设定了B个可能的候选框bbox,并计算每一个可能的候选框bbox的得分,即置信度,置信度是一个这个bbox里确实框住了某一个物体和该bbox和真实的目标检测框的重合程度的综合度量指标,置信度confidence的计算公式是:
是指一个grid有物体的概率,在有物体的时候为1,没有物体的时候为0;
的意思是预测的bounding box和真实的物体位置ground truth的交并比;
同时计算每一个grid对应为第i个类别的概率,记作,在测试的时候,则该grid内的所有的B个预测框bbox都对应乘上这个Pr值得到:
计算得到的confidence也就是每一个预测框框住的是分类i的物体的一个综合置信度得分概率;
那么如果一个物体较大,被多个grid识别应该怎么处理呢?怎么判断这几个grid识别的是同一个物体呢?如下图B1、B2、B3、B4所示:
理论上只用就可以选出负责识别物体的grid,但是可能会不太精确, 因此置信度confidence需要引入,因为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的总长度为:
我们规定每个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应该是:
, 0.48, 0.28, 0.50, 0.32, 1, 0, 0
例子:
这里的S=7,也就是将整张图片分为49个grid,对应的每一个grid设定考虑B个不同的候选框,计算共S*S*B个bbox的预测信息,每一个bbox都对应一个五维的向量作为预测值,包括:预测框的中心对应当前的小区域的相对位置;预测框的大小相对于整个图片的相对比值;置信得分=P(物体)* IOU,同时对于一个C分类问题,则每一个grid都有一个长度为C的向量,表示该grid对应的预测框是i分类的概率;也就是说,假设有个框,每个框的bbox个数为B,分类器可以识别出C种不同的物体,那么所有整个ground truth的长度为:
例如论文中S=7,B=2,C=20,输入图像被划分为7x7的单元格(grid),输出tensor中的7x7对应着输入图像的7x7个单元格,每个单元格对应输出30维的向量,所以整个ground truth的长度为49*30,即共49个grid,每个框生成2个bbox,每个bbox需要生成5个参数,则共有10个参数,分类器可以识别出20个目标类别,下图其概率值是在各个边界框置信度下的条件概率;
2个bounding box的位置:使用归一化后的x,y,w,h,这有利于之后的bbox的回归;
2个bounding box的置信度:每一个置信度包含两方面,一是该边界框含有目标的可能性大小,二是该边界框的准确度;
20类对象分类的概率:由有物体的grid负责预测的两个边界框中的目标属于各个类别的概率,注意这些概率值是在各个边界框置信度下的条件概率,即,也就是说不管一个grid预测多少个边界框,该grid只预测一组类别概率值;
损失函数
损失函数由5项误差组成,表示第i个grid中的第j个bbox是否负责这个object,与object的ground truth box的IOU最大的bbox负责该object,即表示这个grid里有没有物体,如果这个grid没有物体, ,如果这个grid有物体, ;与相反的为,如果没有物体, ,如果有物体, ,判断是否有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开方后才进行计算;根据下图的函数图像可知,当x较小时,x的一点小的变化都会导致y大的变化,而当x较大的时候,x的一点儿小的变化不会让y的变化太大。 但是该方法只能减弱这个问题,并不能彻底解决这个问题,使用平方根的MSE其实就是像让模型对小尺度的物体更敏感。或者说,对大的和小的物体同样敏感;
置信度误差:损失函数的第三、四项为两类置信度误差,一是有object的grid的置信度计算,另一种是没有object的grid的置信度计算,两种情况都是单元格中所有的bbox都参与计算,两种置信度误差都用误差平方和;对于有object的grid中的bbox的置信度的ground truth就是。需要注意的是这个IOU是在训练过程中不断计算出来的,因为网络在训练过程中每次预测的bbox是变化的,所以bbox和ground truth计算出来的IOU每次也会不一样,而对于没有object的grid中的bbox的置信度的ground truth为,因为不包含物体。
分类误差:损失函数的第五项为对象分类误差,将其当作回归误差来计算,使用误差平方和来计算分类误差,需要注意的是只有包含object的grid才参与分类loss的计算,即有object中心点落入的grid才进行分类loss的计算,而这个grid的ground truth label就是该物体的label;
权重:为了使得三种误差达到平衡,就需要给不同的误差赋予不同的权重:
更重视2个4维的坐标预测,给这些损失前面赋予更大的loss weight, 记为;
对没有object的bbox的confidence loss,赋予小的loss weight,记为;
有object的bbox的confidence loss和分类的loss的loss weight正常取1;
论文中=5和=0.5,也就是放大第一项和第二项的损失函数,缩小第四项的损失函数,这样做的原因是让梯度更稳定,如果grid中不含有物体,它对1,2,3,5项没有影响,如果调节第四项,会让含有物体的grid的confidence发生改变,这可能使其他项的梯度剧烈变化,从而带来模型上的不稳定;
整体的网络设计依赖卷积神经网络的思路,也就是共24层卷积后面跟着两层全连接层输出需要的预测的向量,也就是先卷积提取特征再到全连接层进行预测,如下图所示:
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维的输出代表预测结果,具体如下:
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:
首先,输出的7*7维度对应于输入的7*7网格,输出的30维向量对应于20个对象分类的概率、2个bounding box的位置和2个bounding box的置信度;
训练参数设置
几个原论文给出的参考:
学习率处理:第一个epoch先从逐渐上升到,注意不是一开始用大学习率,会很容易发散
原论文保持又训了75个epoch,再用训练个30epoch,再用训练30个epoch;原论文手动调了学习率可能还是有一定影响的;
缓解过拟合:这里为了缓解过拟合用了dropout,参数为0.5,同时可以配合数据增强的方法,原论文用了随机缩放和平移(大概为 20% 的原图大小)
模型预测
和训练同理,输入一张图片,将输出一个7*7*30的张量(tensor)来表示图片中所有网格包含的对象(概率)以及该对象可能的2个位置(bounding box)和可信程度(置信度),具体会给出S*S*B个框的对应的置信度,同时通过(x,y,w,h)标记好框的位置,注意计算每一个grid的对应的各个类别的概率;
测试
将一张图输入到网络中,然后得到一个7*7*30的预测结果,然后将计算结果中的每个单元格预测的类别信息和每个bbox的置信度信息相乘即可得到每个bbox的class-specific confidence score:
如下图所示:
根据同样的方法可以计算得到7*7*2=98个bbox的confidence score,然后根据confidence score对预测得到的98个bbox进行非极大值抑制,得到最终的检测结果;
等式右边第一项就是每个grid预测的类别信息,第二、三项就是每个bbox预测的confidence,这个乘积即encode了预测的bbox属于某一类的概率,也有该bbox准确度的信息;
对每一个grid的每一个bbox执行同样操作:7*7*2=98 bbox(每个bbox既有对应的class信息又有坐标信息):
得到每个bbox的分类置信度得分以后,设置阈值,滤掉得分低的bbox,对保留的bbox进行NMS处理,就得到最终的检测结果:
总结
一张图片最多可以检测出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;
步骤:
优点
缺点
YOLO v1深入理解
图解YOLO
YOLOv1详解
YOLO介绍
tensorflow代码实现
仅为学习记录,侵删!