![](https://zwlw-static.oss-cn-shanghai.aliyuncs.com/static/images/covers-random/283.png)
![](https://zwlw-static.oss-cn-shanghai.aliyuncs.com/static/images/covers-random/283.png)
简介
本文介绍目标检测模型YOLO的工作原理。这篇文章发出之后已经有了非常多的改进方法,YOLO也出了后续的版本:YOLOv2, YOLOv3等等,后面我们有时间再介绍。理解了YOLO的最初版本之后,应该会更加容易理解其后续版本。
YOLO(You Only Look Once)是一个目标检测网络。目标检测任务的主要工作就是确定对象在一个图片中的位置并且确认该对象的分类。先前的目标检测方法比如R-CNN及其变体使用了类似数据管道(pipline)的方式。这些方法将任务分解为几个步骤,然后分别解决每一个步骤的问题。这种方法的缺点是运行速度慢,并且由于每个部分都是独立的,这些不同的部分很难一起进行优化。YOLO将所有这些步骤都融合到了一个神经网络模型中,大大加快了运行速度。
我们将目标检测任务重新设计为单个回归问题,可以直接用原始图片像素点作为输入,输出检测对象的边界以及其所属类别的概率。
简单来讲,你可以将一张图片输入到YOLO中,YOLO会输出一个用框框框好目标的图片,并且会输出框框中的对象所属类别的概率。
YOLO
系统概览
Yolo检测系统工作流程如下图所示:
- 图片输入Yolo时首先要进行resize,将图片调整到$448\times 448$大小
- 将调整后的图片输入到Yolo网络中进行处理
- 根据设定的阈值过滤那些可能性非常小的预测(过滤掉那些不包含对象的框框);并且进行非极大值抑制(non-max suppression),以得到对于同一对象的不同预测结果中可能性最大那个
非极大值抑制
如上图所示,Yolo会将图片划分成很多网格,对于中心点落入其中的对象,对应网格负责预测。Yolo对于每个网格会给出$B$个预测,预测包括框框的位置、大小以及框框中对象的类别。现在有一个问题是:一个物体的中心如果落在网格边界附近,那么多个网格可能给出预测。非极大值抑制目的就是从这些不同的预测中选出一个可能性最大的,具体算法大家可自行上网搜索。
下图给出一个非极大值抑制的一个例子,代码来自于github[2]:
可以看到抑制后输出了最准确的预测结果。
网络结构
输出编码方式
我们首先看一下YOLO所用数据的标签(labels)结构。在YOLO中,一张图片被分割成了$S$行,$S$列,那么图片一共就有了$S \times S$个网格。每一个网格负责中心点落入其中的对象的检测工作。
每个网格都对应了$B$个预测结果,每个预测结果由5个元素$(x, y, w, h, confidence)$组成:
- $(x, y)$:表示被检测目标所在框框的中心点位置(相对于所在网格的左上角坐标)
- $(w, h)$:表示目标所在框框的宽和高
$(x, y)$都归一化到了$(0, 1)$之间会(使用相对距离除以网格的宽/高),(w, h)也归一化到$(0, 1)$之间(除以整个图像的宽/高)。
- $confidence$:文中将$confidence$定义为:
其中$Pr(Object)$为网格中存在检测对象的概率,$IOU$表示$Intersection\ Over\ Union$(不知道怎么翻译),含义为$pred$和$truth$的并集区域比上交集区域,如下图所示:
蓝色的$M$和橙色的$N$的IOU为$IOU(M, N) = \frac{A+B+C}{B}$。$confidence$值反映了任意类别对象在网格中的存在性,如果一个网格中不存在任何检测对象,那么$conficence$为$0$。
除了这5个值之外,每个网格还需要预测目标对象所属类别的条件概率:$Pr(class(i)|Object)$。在训练时,如果一个网格中没有对象存在,那么$loss$函数中也不会包含该网格的惩罚项。每个网格会给出$B$个预测结果,但是只会给出一个各分类的预测概率集合。比如检测对象一共有$C$种类别,那么最终就有$S\times S \times C$个输出。这样加上之前介绍的5种预测值,最终的输出一共有$S\times S \times (B \times 5 + C)$个输出值。
为什么每个网格输出 B 个框框?由于训练数据中包含很多类别的数据,所以B个框框可以让不同的类别可以适配到不同的框框中,这样更加准确。训练的时候是计算模型给出的predtion和样本给出的ground truth之间的IOU,哪个框框的$IOU$大就用哪一个。
了解了输出结构之后,其余的就更好理解了。
网络结构
文中提供了两种类型的网络结构,一种为$full$,一种为$fast$。$full$的网络层数多,预测更加准确,$fast$版本损失了一定的准确率,但是可以带来速度上的提升。
$full$版本的网络结构为:
这个网络结构被设计用于Pascal VOC 数据集的训练,因此最终的输出为$7\times 7 \times 30\ (S=7, B=2, C = 20)$。网络结构中$1\times1/3\times3$网络结构是收到了$GoogLeNet$的启发。网络中只有最后一层使用了线形激活函数,其余内部连接都是用了$Leaky Relu$:
Loss 函数
loss函数由好几部分构成,首先是中心点的定位:
其中$\lambda_{coord}$为超参数,是为了调节与其他loss的比例。上述loss函数计算了所有$S\times S$个网格的$B$个预测的定位loss,其中$\Bbb{I}_{ij}^{obj}$等于:
- 1, 如果网格$(i, j)$中存在一个预测对象
- 0, 不存在预测对象
loss函数的下一部分是关于框框的宽和高的:
这里loss函数中加根号为中给出的解释是:同样的误差对于大的框框来说可能影响很小,而对于小的框框来说影响就可能很大。因此,此处通过加根号来部分缓解这个问题(开放之后,大小框框的长度(或宽度)比例缩小了,因此错误对于不同大小框框的差异性也减小了,这样可以让模型不至于太偏袒太大或太小的对象)。
loss函数的第三部分是关于$confidence$的:
其中$\Bbb{I}_{ij}^{noobj}$的值与$\Bbb{I}_{ij}^{obj}$正好相反。这里第二项加了一个参数$\lambda_{noobj}$也是为了调整该部分的权重。
loss函数中的两个$\lambda$在文中的取值为$\lambda_{coord}=5, \lambda_{noobj}=0.5$。加权重是为了模型的稳定性,显然,对于目标检测来讲$(x, y)$和$(w, h)$是最重要的,因此系数大;而对于某个没有包含检测对象的网格而言,它的$confidence$值就不怎么重要,因此只需要给一个较小的系数就可以了。
loss函数的最后一项为分类loss:
这里和标准的$SSE$ loss相比不同的是前面加上了$\Bbb{I}_i^{obj}$,加上此项是因为对于没有对象的网格来说,我们不计算loss。
训练
训练方式如下:
- 首先,使用ImageNet的数据集(1000-class competition)对于前20个卷积层进行预训练(后面接了一个average pool 和全连接层),输入数据大小为$244\times 244$
- 在与训练好的卷积层后面接上随机初始化的4层卷积和2层全连接层作为检测网络。检测网络的输入数据的分辨率提高到了448,以便更加易于检测
- 训练参数:epochs: 135, batch size: 64, momentum: 0.9, decay: 0.0005
- 学习率调整:起始的epochs 将学习率从 0.001 调整到 0.01,75轮之后开始降低学习率
- 对图片使用了数据增强:随机缩放、位移、调整曝光率、调整色彩饱和度等
局限性
- Yolo中每个网格只会给出两个框框预测,显然如果有多个对象的中心点落入同了一个网格中,Yolo无法预测多个
- 对于成群的小物体无法预测(显然)
- 对于纵横比异常的物体无法预测(比如压扁了或者拉长了)
- Yolo对于大小物体的误差惩罚是一样的,上图虽然对框框大小进行了开方来缓解这个问题,但是缺点依旧存在
- Yolo主要错误来源是定位错误
部分实验结果
从上图可以看出,Yolo的性能表现优于其它几个方法,但是距离人类的水平还较大。
上图给出了不同框架的准确度、处理速度的对比。可以看到Yolo的mAP指标在达到63.4的情况下任然可以每秒处理45张图片数据,基本满足一般实时性要求。此外YOLO的fast版本可以在损失部分准确度的情况下,将每秒处理数量提升到155。
后记
这篇文章推荐大家去看下原文,原文写的还是比较详细的,没给出的细节还是需要去看代码才行。不过Yolo后续已经出了几个新的版本,yolo的一些细节可以忽略,推荐直接去看Yolo的新版及其代码。
引用
[1] Redmon, Joseph, et al. "You only look once: Unified, real-time object detection." Proceedings of the IEEE conference on computer vision and pattern recognition. 2016.
[2] https://github.com/SnailTyan/deep-learning-tools.git
更多推荐