YOLO详解

1. YOLO的创新点

YOLO将物体检测作为回归问题求解。基于一个单独的end-to-end网络,完成从原始图像的输入到物体位置类别的输出。
从网络设计上,YOLO与two steps的目标检测方法如RCNN、Fast RCNN和Faster RCNN的区别如下:

  • YOLO训练和检测均是在一个单独网络中进行
    YOLO没有显示地求取region proposal的过程。而rcnn/fast rcnn 采用分离的模块(独立于网络之外的selective search方法)求取候选框(可能会包含物体的矩形区域),训练过程因此也是分成多个模块进行。Faster rcnn使用RPN(region proposal network)卷积网络替代rcnn和fast rcnn的selective
    search模块,将RPN集成到fast rcnn检测网络中,得到一个统一的检测网络。尽管RPN与fast rcnn共享卷积层,但是在模型训练过程中,需要反复训练RPN网络和fast rcnn网络(注意这两个网络核心卷积层是参数共享的)。(这段话不大懂)
  • YOLO将物体检测作为一个回归问题进行求解,输入图像经过一次inference,便能得到图像中所有物体的位置和其所属类别及相应的置信概率。而rcnn、fast rcnn和faster rcnn将检测结果分为两部分求解:物体类别(分类问题),物体位置即bounding box(回归问题)
    YOLO详解

2. 核心思想

2.1 网络定义

YOLO检测网络包括24个卷积层和2个全连接层,如下图所示。需要说明的是,YOLO的网络借鉴了GoogleNet分类网络结构,论文中给出的网络结构如下:
YOLO详解
有个更好看的版本,如下:
YOLO详解
从上图可以看到,YOLO的网络结构采取了GoogleNet的前20层网络,但是是经过modification的,具体是不采用inception module,而是采用1x1卷积层(此处1x1卷积层的存在是为了跨通道信息整合)+3x3卷积层简单替代。然后后面四层的卷积层是他自己加的,最后2个全连接层,最后再reshape成7x7x30的tensor。另注意,由于最后采用了全连接层,所以训练的图片和测试的图片大小要一样,都是448x448x3的彩色图。

YOLO论文中,作者还给出一个更轻快的检测网络fast YOLO,它只有9个卷积层和2个全连接层。使用titan x GPU,fast YOLO可以达到155fps的检测速度,但是mAP值也从YOLO的63.4%降到了52.7%,但却仍然远高于以往的实时物体检测方法(DPM)的mAP值。

2.2 输出表示定义

本部分给出YOLO全连接输出层的定义

YOLO将输入图像分成SxS个格子(grid),每个格子(grid)负责检测‘落入’该格子的物体。若某个物体的中心位置的坐标落入到某个格子,那么这个格子就负责检测出这个物体。如下图所示,图中物体狗的中心点(红色原点)落入第5行、第2列的格子内,所以这个格子负责预测图像中的物体狗。
YOLO详解
每个格子(grid)输出B个bounding box(包含物体的矩形区域)信息,也就是(x,y,w,h,confidence),以及C个物体属于某种类别的概率信息。
Bounding box信息包含5个数据值,分别是x,y,w,h,和confidence。其中x,y是指当前格子预测得到的物体的bounding box的中心位置的坐标。w,h是bounding box的宽度和高度。注意:实际训练过程中,w和h的值使用图像的宽度和高度进行归一化到[0,1]区间内;x,y是bounding box中心位置相对于当前格子位置的偏移值,并且被归一化到[0,1]。

confidence反映当前bounding box是否包含物体以及物体位置的准确性, 请注意,是bounding box,不是所在格子(grid),这一点很重要。confidence的计算方式如下:
confidence=Pr(Object)IOUpredtruthconfidence = Pr(Object) * IOU_{pred}^{truth}
其中,如果bounding box包含物体,则Pr(Object)=1Pr(Object)=1,否则Pr(Object)=0Pr(Object)=0IOUIOU(intersection of union)为预测的bounding box与物体真实区域的交集面积,这个值也是在[0,1]之间的。

除了confidence之外,每一个格子(gird)还输出C个该物体属于某种类别的概率信息。也就是说,在给出Pr(Object)Pr(Object)的前提下,去求得该物体属于什么类别的概率,也就是条件概率,公式如下:
Pr(ClassiObject)Pr(Class_i|Object)
这个概率值一共有C个。


因此,YOLO网络最终的全连接层的输出维度是 S×S×(B×5 + C)。YOLO论文中,作者训练采用的输入图像分辨率是448x448,S=7,B=2;采用VOC 20类标注物体作为训练数据,C=20。因此输出向量为7×7×(20+2×5)=1470维。

上面是训练的阶段,测试阶段在最后预测的时候有些许不同。在测试的时候,将每一个bounding box的confidence与相对应的格子(grid)的C个Pr(ClassiObject)Pr(Class_i|Object)分别相乘,便得到每一个bounding box对应的类别分数,再用NMS进行迭代,便得到预测结果。


下面参考deepsystems.io的slides,详细解读一下inference过程。

  1. 首先输入图像进入网络,得到7x7x30的tensor。注意图片的左下角,因为我们的图片也是分成7x7的,所以最后的tensor和我们的图片的格子就对应起来。
    YOLO详解

  2. 我们现在是分析7x7x30的tensor,然后说明这个tensor的值在图片中表示什么。以红色格子为例,7x7x30的tensor也对应到这个位置的格子,那么图片对应到的就是图中的狗那里,图中也标了红框。具体来说是第5行,第2列。取这一行的tensor出来,就有1x30维度的tensor了。前5个数的含义图中有,然后对应到原图像的黄框。
    YOLO详解

  3. 接下来看后5个数字,也是代表一个bounding box的x,y,w,h和confidence。
    YOLO详解
    也就是前面每5个值对应一个bounding box,一共有两个bouding box。
    YOLO详解

  4. 后面还剩20个值,代表就是这个格子中每个类别的概率,当然这个是条件概率,是给出Pr(Object)Pr(Object)前提下的类别概率。如下图:
    YOLO详解

  5. 然后因为我们要得到每个bounding box对应类别的分数,论文里也说了,要把confidence和Pr(ClassiObject)Pr(Class_i|Object)相乘,得到最后的分数。于是将后面20个值与前面的两个bounding box的confidence分别相乘,得到两个长度为20x1的tensor。先乘第一个bounding box的confidence:
    YOLO详解
    然后乘于第二个:
    YOLO详解

  6. 对每一个格子这样操作,每一个格子就有两个20x1的tensor,
    YOLO详解
    第二个:
    YOLO详解
    最后得到7x7x2 = 98个这样的bboxes:
    YOLO详解

  7. 当我们有了这么多个bboxes,其实上面说的是每个bounding box的分数,当然也是那么多个bounding box,因为每一个分数都对应一个bonding box。
    有了98个bboxes之后,先获取每个bbox第一类别的分数,
    YOLO详解
    然后设置一个阈值threah1=0.2, 如果分数小于thresh1的话,就把这个bounding box的分数设为0;然后按照分数从大到小逆序排列;最后用NMS算法将冗余的bounding box的分数也设为0,如下图所示。
    YOLO详解
    那NMS算法是怎么执行的呢?
    在上一步经过将分数排序,得到分数从大到小顺序的bbox,如下图:
    YOLO详解
    每一个bbox就代表一个框,这里可以具体看看其他的框是怎么样的:
    score为0.3的框:
    YOLO详解
    score为0.2的框:
    YOLO详解
    到最后一个bbox:
    YOLO详解
    然后取分数最大的bbox,记为"bbox_max":
    YOLO详解
    将其他的bbox与bbox_max进行比较,其他的bbox记为"bbox_cur",如果IoU(bbox_max, bbox_cur) > 0.5,那么将bbox_cur的分数设为0。
    YOLO详解
    上图的两个框的IoU>0.5,因此将bbox_cur的分数设为0,如下图:
    YOLO详解
    下一个的框的IoU<0.5,所以bbox_cur的score不变:
    YOLO详解
    经过这样的一次迭代,完成了第一次的遍历。然后我们选择第二大分数的bbox,并设为"bbox_max",进行和之前一样的操作,只不过不和分数第一大的bbox比较而已:
    YOLO详解
    比较:
    YOLO详解
    按照相同的方式进行遍历,最后类别为狗的,分数不是0的bbox,只剩下2个:
    YOLO详解
    然后我们按照同样的方式,对其他19类进行同样的操作:
    YOLO详解

  8. 经过上面的操作,每一个类别对应的bbox的分数就会有很多0,然后我们就可以通过bbox选取最大的score,从而确定类别,最后画框了。如下图:
    YOLO详解
    这里要注意判断score是否大于0,因为有些bbox什么都没标到,这样它所有类别的score都为0,因此不画框,下面bb1这个就是不画框的:
    YOLO详解
    最后的结果如下:
    YOLO详解

注:
虽然每个格子可以预测B个bounding box,但是最终只选择只选择IOU最高的bounding box作为物体检测输出,即每个格子最多只预测出一个物体。当物体占画面比例较小,如图像中包含畜群或鸟群时,每个格子包含多个物体,但却只能检测出其中一个。这是YOLO方法的一个缺陷。

2.3 Loss函数定义

YOLO使用均方和误差(sum-squared error)作为loss函数来优化模型参数,即网络输出的SxSx(Bx5 + C)维向量与真实图像的对应SxSx(Bx5 + C)维向量的均方和误差。如下式所示。其中,coordErroriouErrorclassErrorcoordError、iouError和classError分别代表预测数据与标定数据之间的坐标误差IOU误差分类误差
loss=i=0S2coordErroe+iouError+classErrorloss = \sum_{i=0}^{S^2} coordErroe + iouError + classError

但YOLO不是完全按照上面来,上面的公式只是一个模板,具体变动如下:

  • 位置相关误差(坐标、IOU)与分类误差对网络loss的贡献值是不同的,因此YOLO在计算loss时,使用λcoord=5\lambda _{coord} =5修正coordErrorcoordError
  • 在计算IOU误差时,包含物体的格子与不包含物体的格子,二者的IOU误差对网络loss的贡献值是不同的。若采用相同的权值,那么不包含物体的格子的confidence值近似为0,变相放大了包含物体的格子的confidence误差在计算网络参数梯度时的影响。为解决这个问题,YOLO 使用λnoobj=0.5\lambda _{noobj} =0.5修正iouErroriouError。(注此处的‘包含’是指存在一个物体,它的中心坐标落入到格子内)。
  • 对于相等的误差值,大物体误差对检测的影响应小于小物体误差对检测的影响。这是因为,相同的位置偏差占大物体的比例远小于同等偏差占小物体的比例。YOLO将物体大小的信息项(w和h)进行求平方根来改进这个问题。(注:这个方法并不能完全解决这个问题)。

    更好的解释:
    对不同大小的bbox预测中,相比于大bbox预测偏一点,小box预测偏一点更不能忍受。而sum-square error loss中对同样的偏移loss是一样。 为了缓和这个问题,作者用了一个比较取巧的办法,就是将box的width和height取平方根代替原本的height和width。 如下图:small bbox的横轴值较小,发生偏移时,反应到y轴上的loss(下图绿色)比big box(下图红色)要大。
    YOLO详解
    来源 https://zhuanlan.zhihu.com/p/24916786

综上,YOLO在训练过程中Loss计算如下面式子所示:
YOLO详解
其中,x,y,w,C,px,y,w,C,p为网络预测值,x^,y^,w^,C^,p^\hat{x},\hat{y},\hat{w},\hat{C},\hat{p}为标注值。Πiobj\Pi _{i}^{obj}表示物体落入格子i中,Πijobj\Pi _{ij}^{obj}Πijnoobj\Pi _{ij}^{noobj} 分别表示物体落入与未落入格子i的第j个bounding box内。
在分类误差的loss中,我们是知道每一个格子所属类别的,如果属于i类别,那么ground truth的pi^=1\hat{p_i} = 1

注:

  • YOLO采用了多个下采样层,网络学到的物体特征并不精细,因此也会影响检测效果。
  • YOLO loss函数中,大物体IOU误差和小物体IOU误差对网络训练中loss贡献值接近(虽然采用求平方根方式,但没有根本解决问题)。因此,对于小物体,小的IOU误差也会对网络优化过程造成很大的影响,从而降低了物体检测的定位准确性。

2.4 训练

YOLO模型训练分为两步:

1)预训练。使用ImageNet
1000类数据训练YOLO网络的前20个卷积层+1个average池化层+1个全连接层,后面的池化层和全连接层是预训练加的。预训练图像的分辨率resize为224x224。
2) 用步骤1)得到的前20个卷积层网络参数来初始化YOLO模型前20个卷积层的网络参数,后面的4层就training from scratch,然后用VOC 20类标注数据进行YOLO模型训练。为提高图像精度,在训练检测模型时,将输入图像分辨率resize到448x448。

3. 效果

下表给出了YOLO与其他物体检测方法,在检测速度和准确性方面的比较结果(使用VOC 2007数据集)。
YOLO详解
论文中,作者还给出了YOLO与Fast RCNN在各方面的识别误差比例,如下图。YOLO对背景内容的误判率(4.75%)比fast rcnn的误判率(13.6%)低很多。但是YOLO的定位准确率较差,占总误差比例的19.0%,而fast rcnn仅为8.6%。
YOLO详解
综上,YOLO具有如下优点:


  • YOLO将物体检测作为回归问题进行求解,整个检测网络pipeline简单。在titan x GPU上,在保证检测准确率的前提下(63.4% mAP,VOC 2007 test set),可以达到45fps的检测速度。
  • 背景误检率低
    YOLO在训练和推理过程中能‘看到’整张图像的整体信息,而基于region proposal的物体检测方法(如rcnn/fast rcnn),在检测过程中,只‘看到’候选框内的局部图像信息。因此,若当图像背景(非物体)中的部分数据被包含在候选框中送入检测网络进行检测时,容易被误检测成物体。测试证明,YOLO对于背景图像的误检率低于fast rcnn误检率的一半。
  • 通用性强
    YOLO对于艺术类作品中的物体检测同样适用。它对非自然图像物体的检测率远远高于DPM和RCNN系列检测方法。

但相比RCNN系列物体检测方法,YOLO具有以下缺点:

  • 识别物体位置精准性差
  • 召回率低,也就是漏检率较高

4.改进

为提高物体定位精准性和召回率,YOLO作者提出了YOLO9000,提高训练图像的分辨率,引入了faster rcnn中anchor box的思想,对各网络结构及各层的设计进行了改进,输出层使用卷积层替代YOLO的全连接层,联合使用coco物体检测标注数据和imagenet物体分类标注数据训练物体检测模型。相比YOLO,YOLO9000在识别种类、精度、速度、和定位准确性等方面都有大大提升。

5. 实践

暂不实践。

6. Reference

  1. YOLO: Unified, Real-Time Object Detection
  2. deepsystem.io
  3. YOLO详解
  4. 图解YOLO
  5. yolo检测算法系列介绍与yolo v3代码阅读(一)