YOLO v1学习笔记
YOLO v1
论文:https://arxiv.org/abs/160.400640
代码:https://github.com/pjreddie/darknet
创新点:
- 将整张图片作为网络的输入,直接在输出层对BBox的位置和类别进行回归。
简介
YOLO意思是You Only Look Once,创造性的将候选区和对象识别这两个阶段合二为一,属于one-stage的检测模型。
整体上来说,首先将图片resize到448×448,送入到CNN网络之后,经过进一步预测得到检测的结果。YOLO是用了一个单独的CNN模型来实现了end2end的检测,它是一个统一的框架,而且检测是实时的迅速的,所以论文的全称就是:You Only Look Once: Unified, Real-Time Object Detection。
设计理念
实际上,YOLO并没有真正去掉候选区,而是采用了预定义的候选区。YOLO首先将resize之后的图片分为了 S × S S\times S S×S个grid cell,每个小网格的任务就是去检测那些——中心落在其中的object。
具体地可以参照上图来理解,比如图中白色轿车的中心落在了第二行倒数第二列的单元格中,那么这个单元格就负责来预测这辆车。
对于所有的小单元格,它会预测 B B B个bbox,和bbox的置信度(confidence score),输出为 ( x , y , w , h , c ) (x,y,w,h,c) (x,y,w,h,c)。
其中 ( x , y ) (x,y) (x,y)是边界框的中心坐标,而 w w w和 h h h是边界框的宽与高。还有一点要注意,中心坐标的预测值 ( x , y ) (x,y) (x,y)是相对于每个单元格左上角坐标点的偏移值,并且单位是相对于单元格大小的,而边界框的 w w w和 h h h预测值是相对于整个图片的宽与高的比例,这样理论上4个元素的大小应该在[0, 1]范围。
置信度的含义在MAL笔记中解释过,它是每个bbox输出的一个重要参数,它的定义有两重:
- bbox内有对象的概率,注意,是对象,不是某个类别的对象,也就是说只能分别background和object。如果这个bbox是背景,那么 P r ( o b j e c t ) = 0 Pr(object)=0 Pr(object)=0。而当该边界框包含目标时, P r ( o b j e c t ) = 1 Pr(object)=1 Pr(object)=1。
- 网络预测的bbox与真实区域的IoU
用公式来表示置信度就是 C i j = P r ( O b j e c t ) ∗ I o U p r e d t r u t h C_{i}^{j} = Pr(Object) * IoU_{pred}^{truth} Cij=Pr(Object)∗IoUpredtruth。综合来说,一个bounding box的置信度Confidence意味着它是否包含对象且位置准确的程度。置信度高表示这里存在一个对象且位置比较准确,置信度低表示可能没有对象或者即便有对象也存在较大的位置偏差。
除此之外,每个单元格还要给出预测的结果,输出的是 C C C个类别的概率值,这些概率值其实是在各个边界框置信度下的条件概率,即 P r ( c l a s s i ∣ o b j e c t ) Pr(class_i|object) Pr(classi∣object)。在这里,YOLO的一个缺点是,不管一个单元格预测多少个边界框,其只预测一组类别概率值。在后来的改进版本中,Yolo9000是把类别概率预测值与边界框是绑定在一起的。
由此,在bbox内有object的条件下,我们可以计算出类别的置信度 P r ( c l a s s i ∣ o b j e c t ) ∗ P r ( O b j e c t ) ∗ I o U p r e d t r u t h = P r ( c l a s s i ) ∗ I o U p r e d t r u t h Pr(class_i|object)*Pr(Object) * IoU_{pred}^{truth}=Pr(class_i) * IoU_{pred}^{truth} Pr(classi∣object)∗Pr(Object)∗IoUpredtruth=Pr(classi)∗IoUpredtruth。
边界框类别置信度,表征的是该边界框中目标属于各个类别的可能性大小,以及边界框匹配目标的好坏。之后设置阈值,过滤掉得分低的bbox,对剩下的部分进行NMS,得到最终的检测结果。
总结一下,每个单元格需要预测(B*5+C) 个值。如果将输入图片划分为S*S网格,那么最终预测值为S*S*(B*5+C)大小的张量。整个模型的预测值结构如下图所示。对于PASCAL VOC数据,其共有20个类别,如果使用 S=7, B=2,那么最终的预测结果就是 7*7*30大小的张量。
网络结构
YOLO使用卷积层来提取特征,然后使用全连接层来得到预测的结果。具体在PASCAL VOC上来看,主要是使用了1x1卷积来做channle reduction,然后紧跟3x3卷积,做max pooling。对于卷积层和全连接层,采用Leaky ReLU**函数,但是最后一层采用线性**函数。最终输出一个7×7×30的tensor。
来看看这个30维的向量都包含哪些信息。
具体来看每个部分:
- 20个对象分类的概率
因为YOLO支持识别20种不同的对象(人、鸟、猫、汽车、椅子等),所以这里有20个值表示该网格位置存在任一种对象的概率。
- 2个bounding box的位置
也就是 ( x , y , w , h ) (x,y,w,h) (x,y,w,h)的编码。对于边界框为什么把置信度c和 ( x , y , w , h ) (x,y,w,h) (x,y,w,h)都分开排列,而不是按照 ( x , y , w , h , c ) (x,y,w,h,c) (x,y,w,h,c)这样排列,其实纯粹是为了计算方便,因为实际上这30个元素都是对应一个单元格,其排列是可以任意的。但是分离排布,可以方便地提取每一个部分。
- 2个bounding box的置信度
bounding box的置信度
C
o
n
f
i
d
e
n
c
e
=
P
r
(
O
b
j
e
c
t
)
∗
I
o
U
p
r
e
d
t
r
u
t
h
Confidence=Pr(Object) * IoU_{pred}^{truth}
Confidence=Pr(Object)∗IoUpredtruth
P
r
(
O
b
j
e
c
t
)
Pr(Object)
Pr(Object)是bounding box内存在对象的概率,区别于上面第①点的
P
(
C
i
∣
O
b
j
e
c
t
)
P(C_i|Object)
P(Ci∣Object)。
P
r
(
O
b
j
e
c
t
)
Pr(Object)
Pr(Object)并不管是哪个对象,它体现的是有或没有对象的概率。第①点中的
P
(
C
i
∣
O
b
j
e
c
t
)
P(C_i|Object)
P(Ci∣Object)意思是假设已经有一个对象在网格中了,这个对象具体是哪一个。
还要说明的是,虽然有时说"预测"的bounding box,但这个IOU是在训练阶段计算的。等到了测试阶段(Inference),这时并不知道真实对象在哪里,只能完全依赖于网络的输出,这时已经不需要(也无法)计算IOU了。
每个30维向量中只有一组(20个)对象分类的概率,也就只能预测出一个对象。所以输出的 7*7=49个 30维向量,最多表示出49个对象。
网络训练
预训练的的分类模型,采用了GoogleNet的前20层,然后添加一个average-pool层和全连接层。
预训练之后,在预训练得到的20层卷积层之上加上随机初始化的4个卷积层和2个全连接层。
损失函数
在实现中,最主要的就是怎么设计损失函数,让这个三个方面得到很好的平衡。Yolo算法将目标检测看成回归问题,所以采用的是均方差损失函数。但是对不同的部分采用了不同的权重值。作者简单粗暴的全部采用了sum-squared error loss来做这件事。
第一项是边界框中心坐标的误差预测, 1 i j o b j 1_{ij}^{obj} 1ijobj表示第i个单元格是否存在目标,该单元格中的第j个边界框负责预测该目标。
第二项是边界框的高与宽的误差项,并采用了较大的权重5。宽度和高度先取了平方根,因为如果直接取差值的话,大的对象对差值的敏感度较低,小的对象对差值的敏感度较高,所以取平方根可以降低这种敏感度的差异,使得较大的对象和较小的对象在尺寸误差上有相似的权重。
第三项是包含目标的边界框的置信度误差, 1 i o b j 1_{i}^{obj} 1iobj指的是第i个单元格是否存在目标。对于置信度 C i C_i Ci,如果是不存在目标,此时由于 P r ( o b j e c t ) = 0 Pr(object)=0 Pr(object)=0,那么 C i = 0 C_i=0 Ci=0。如果存在目标, P r ( o b j e c t ) = 1 Pr(object)=1 Pr(object)=1,此时需要确定IOU,当然你希望最好的话,可以将IOU取1,这样 C i = 1 C_i=1 Ci=1。实际的复现中,也是经常直接取为1,这个带来的影响应该不是很大。
第四项是不包含目标的边界框的置信度误差,采用较小的权重值0.5。
第五项是对类别的预测,但前提也是框中有目标。
所以,对于不存在对应目标的边界框,其误差项就是只有置信度,坐标项误差是没法计算的。而只有当一个单元格内确实存在目标时,才计算分类误差项,否则该项也是无法计算的。
同时,在训练时,如果该单元格内确实存在目标,那么只选择与ground truth的IOU最大的那个边界框来负责预测该目标,而其它边界框认为不存在目标。这样设置的一个结果将会使一个单元格对应的边界框更加专业化,但如果一个单元格内存在多个目标,这时候Yolo算法就只能选择其中一个来训练,这也是Yolo算法的缺点之一。
总结
优点:
- 快速,实时性强-pipline简单,训练与预测都是end2end
- 背景误检率低-对整张图片做卷积,所以其在检测目标有更大的视野
- 通用性强
缺点:
-
对于小物体的检测较差,尤其是一些聚集在一起的小对象。
对边框的预测准确度不是很高,总体预测精度略低于Fast RCNN。主要是因为网格设置比较稀疏,而且每个网格只预测两个边框,另外Pooling层会丢失一些细节信息,对定位存在影响。
参考:
https://zhuanlan.zhihu.com/p/46691043
https://zhuanlan.zhihu.com/p/136382095
https://zhuanlan.zhihu.com/p/32525231