YOLO实时目标检测

  我们可以一眼识别出图片里面的目标和目标的位置以及目标的动作等信息。我们的视觉系统快速且准确,可以让我们几乎不用思考就可以识别复杂的目标。用于物体检测的快速,准确的算法将允许计算机在没有专用传感器的情况下驾驶汽车,使得辅助设备能够实时传送 场景信息给人类用户,并可以用于通用的响应式机器人系统。快速准确的目标检测算法的研究一直没有停下来。

  目前比较流行的目标检测算法可以分为两类:一类是基于Region Proposal的R-CNN系算法(R-CNN,Fast R-CNN, Faster R-CNN),它们是two-stage的,需要先使用启发式方法(selective search)或者CNN网络(RPN)产生Region Proposal,然后再在Region Proposal上做分类与回归。
  另一类是Yolo,SSD这类one-stage算法,其仅仅使用一个CNN网络直接预测不同目标的类别与位置。
  第一类方法是准确度高一些,但是速度慢,但是第二类算法是速度快,但是准确性要低一些。

  下面将要介绍YOLO算法,You Only Look Once: Unified, Real-Time Object Detection。从算法的名字上就可以很容易知道此算法的特点,只需要进行一次CNN运算,Unified指的是这是一个统一的框架,提供end-to-end的预测,而Real-Time则时体现Yolo算法速度快。

  在介绍YOLO算法的原理之前,有必要介绍一下滑动窗口原理。

滑动窗口

  滑动窗口的思想是将目标检测问题转换为图像分类问题,即使用不同大小和比例的的窗口在整张图片上以一定的步长滑动,在每个窗口对应区域内做分类,逐步完成对整张图片的目标检测。
  很容易看出来,这个方法的问题在于无法事先知道待检测目标的的大小和位置,因此需要设置不同大小和比例的滑动窗口去进行滑动,并且需要选取合适的步长。但是此过程会产生很多的子区域,每个子区域都需要利用分类器去做预测,这就需要很大的计算量,检测速度会受到很大的影响。通常,我们又是很关注检测速度的,因此为了保证检测速度,在使用滑动窗口时,模型一般不能太复杂。
  在R-CNN中采用了selective search方法寻找最可能包含目标的子区域进行检测,即启发式过滤掉很多可能不含有目标的子区域来提高效率。在使用CNN分类器时,滑动窗口是依然是非常耗时的。为了解决这个问题,提出了全卷积的方法。

全卷积

  什么是全卷积(FCN)呢?方法很简单,结合卷积运算的特点,可以利用一种全卷积的方法实现更高效的滑动窗口。全卷积,即使用卷积层代替全连接层。
例如下面这个例子,来源于吴恩达老师的网课:

neural

假设测试图大小是16×16,并令滑动窗口大小是14×14, 滑动步长为2,所以这个测试图可以被窗口划分成4个部分,即输出的维度为[2,2,4],可以看作4个类别的预测概率值。

neural

可以很清楚的看出,经过这一次卷积运算就完成了滑动窗口所有子区域的分类预测,其实这就是overfeat算法的思想。这个思想来源于卷积运算的图片空间位置不变的特性,尽管卷积过程中图片大大减小了,但是特征的相对位置依然保持不变。R-CNN也借鉴了这个思想,由此产生了Fast R-CNN算法。
看起来以上算法已经很好的解决了滑动窗口计算量大的问题,但是这只是对于一个固定大小,固定步长的窗口,并不能很好的在规模不同的图片在进行不同大小目标的检测。由此,产生了YOLO算法。
  [YOLO论文连接]:https://arxiv.org/abs/1506.02640

YOLO算法原理

  YOLO算法直接将原始图片分割成互不重合的小方块,然后通过卷积最后生产这样大小的特征图,基于上面的分析,可以认为特征图的每个元素也是对应原始图片的一个小方块,然后用每个元素来可以预测那些中心点在该小方格内的目标,这就是YOLO算法的朴素思想。

YOLO设计理念

  总的来说,YOLO算法采用一个单独的CNN模型实现end-to-end的目标检测,如下图所示:

neural

  首先将输入图片resize到448x448,然后送入CNN网络,最后处理网络预测结果得到检测的目标。这个过程相比R-CNN算法,其是一个统一的框架,其速度更快,而且YOLO的训练过程也是end-to-end的。

  具体来说,YOLO的CNN网络首先将输入的图片分割成 S×S的网格,然后每个单元格负责去检测那些中心点落在该格子内的目标。如下图所示:

neural

  如上图,可以看到狗这个目标的中心落在左下角一个单元格内,因此该单元格负责预测这个狗。每个单元格会预测B个边界框(bounding box)并计算边界框的置信度(confidence score)。这里置信度包含两个方面,一是边界框含有目标的可能性大小,二是边界框的准确度。前者记为Pr(Object),当该边界框不包含目标时,Pr(object)=0。当该边界框包含目标时,Pr(object)=1。

  边界框的准确度可以用预测框(predicated box)与实际框(ground truth)的交并比(IOU,intersection over union)来表示,记为$\text{IOU}^{truth}_{pred}$。因此置信度可以定义为$Pr(Object)*\text{IOU}^{truth}_{pred}$。

  注意论文里面定义的置信度并不是边界框是否含有目标的概率,而是预测边界框的准确度与Pr(object)的乘积。

  每一个网格单元预测C个类别的概率值,记为:$Pr(Class_i|Object)$。它表示在每个单元格里属于每一个类别的概率。不管有多少个边界框,都仅在每一个单元格上预测一组概率值(这在YOLO后面的版本做了改动)。
  现在可以利用条件类别概率与每个单元格置信度的乘积计算出每个每个边界框特定类别的置信度:

  边界框类别置信度表示的是该边界框中目标属于各个类别的可能性大小以及边界框匹配目标的好坏。
  原论文中利用YOLO计算PASCAL VOC数据集,利用了S=7,B=2。PASCAL VOC数据集一共有20种类别,因此YOLO最终需要预测大小为7×7×30的张量(tensor)。

网络设计

  YOLO利用卷积网络来提取特征值,再利用全连接层预测输出概率值和坐标。其网络结构受GoogleNet模型的启发,拥有24各卷积层,之后紧跟两个全连接层。

neural

  在YOLO模型中,对于卷积层,主要使用1x1卷积来做channle reduction,然后紧跟3x3卷积。对于卷积层和全连接层,采用Leaky ReLU激活函数: max(x, 0.1x) 。但是最后一层却采用线性激活函数。
  在原论文中,作者还训练了加速版YOLO,用了9个卷积层代替原始的24个卷积层,同时在这些卷积层中采用了更少的卷积核。

模型的训练

  正式训练之前,利用了前20个卷积层紧跟一个平均池化层(average-pooling layer)和一个全连接层构成的分类模型在ImageNet数据集上进行了预训练。之后加上4个随机初始化的卷积层和两个随机初始化的全连接层,构成了上图的网络架构。由于检测任务一般需要更高清的图片,所以将网络的输入从224x224增加到了448x448。
模型的最后一层预测了类概率和边界框坐标。利用图片的高度和宽度对边界框的坐标进行了归一化处理,使它们的范围介于0-1之间。
对边界框的坐标进行了参数化处理,其范围也是(0,1)。

  Yolo算法将目标检测看成回归问题,所以采用的是均方差损失函数。但是对不同的部分采用了不同的权重值。首先区分定位误差和分类误差。对于定位误差,即边界框坐标预测误差,采用较大的权重$\lambda _{coord}=5$。然后其区分不包含目标的边界框与含有目标的边界框的置信度,对于前者,采用较小的权重值 $\lambda _{noobj}=0.5$。其它权重值均设为1。然后采用均方误差,其同等对待大小不同的边界框,但是实际上较小的边界框的坐标误差应该要比较大的边界框要更敏感。为了保证这一点,将网络的边界框的宽与高预测改为对其平方根的预测,即预测值变为 $(x,y,\sqrt{w}, \sqrt{h})$。

  另外,YOLO在每个单元格预测多个边界框。但是在训练时,只需要一个边界框预测器负责每一个目标。如果该单元格内确实存在目标,那么只选择与ground truth的IOU最大的那个边界框来负责预测该目标,而其它边界框认为不存在目标。这样设置的一个结果将会使一个单元格对应的边界框更加专业化,其可以分别适用不同大小,不同高宽比的目标,从而提升模型性能。

但是如果一个单元格内存在多个目标怎么办呢?按照原文的设计,这时候Yolo算法就只能选择其中一个来训练,这也是Yolo算法的缺点之一。

最终YOLO的损失函数计算如下:

neural

  其中第一项是边界框中心坐标的误差项, $1^{obj}_{ij}$ 指的是第 i 个单元格存在目标,且该单元格中的第 j 个边界框负责预测该目标。第二项是边界框的高与宽的误差项。第三项是包含目标的边界框的置信度误差项。第四项是不包含目标的边界框的置信度误差项。而最后一项是包含目标的单元格的分类误差项, $1^{obj}_{i}$ 指的是第 i 个单元格存在目标。这里特别说一下置信度的target值 C_i ,如果是不存在目标,此时由于 Pr(object)=0,那么 C_i=0 。如果存在目标, Pr(object)=1 ,此时需要确定 $\text{IOU}^{truth}_{pred}$,当然你希望最好的话,可以将IOU取1,这样 C_i=1 ,但是在YOLO实现中,使用了一个控制参数rescore(默认为1),当其为1时,IOU不是设置为1,而就是计算truth和pred之间的真实IOU。

网络的预测

  YOLO的预测用到了非极大值抑制算法(non maximum suppression, NMS),这里对算法的原理做一个简单的介绍,链接:https://tcnull.github.io/nms/

  了解了NMS算法再来分析YOLO的预测过程,以batch = 1为例,即只预测一张输入图片。
  由前面的分析,很容易知道网络的最终输出的张量大小是7×7×30,将其分割成三个部分:类别概率部分为 [7, 7, 20],置信度部分为 [7,7,2] ,而边界框部分为 [7,7,2,4]。将前两部分相乘(矩阵[7, 7, 20]乘以[7,7,2] 可以各补一个维度来完成 [7,7,1,20]×[7,7,2,1])可以得到类别置信度值为[7, 7,2,20],即总共预测了772=98个边界框。对于这98个边界框,首先将置信度小于阈值的值置为0,然后分别对置信度值使用NMS,并且这里NMS的处理过程和传统过程不一样。这里不对NMS的结果进行剔除,而是直接将其置信度置为0。最后确定每个边界框的类别,当其置信度不为0时才输出检测结果。