特斯拉 AI DAY 扩展分享—单阶段 YOLO 系列(1)

784 阅读8分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

特斯拉中也用到类似 YOLO one-stage 目标检测,说以也想借这个机会来回顾一下。那么什么是 one-stage 目标检测呢?也就是生成候选框和目标预测与边界框回归都是由一个网络完成的。

ironman_evolution.jpg

今天来说一说和写一写 YOLOv1,YOLOv1 在目标检测中应该算独树一帜,有点类似今天 Web 前端 vue 地位。而且一路走来不断地给我们带来惊喜。YOLO 是 You Only Look Once 缩写,顾名思义是一个 one-stage 目标检测框架,是一个端到端的目标检测框架。YOLOV1 将目标检测问题成功转换为回归(regression)的问题。网上有很多关于 YOLO 的文章和视频,希望我的文章能够给你带来不一样内容,帮助你更好理解 YOLO 当前比较流行多目标检测的框架。

输入和输出

通常我们知道神经网络模型,所谓神经网络模型就是一个函数,当将数据输入给函数,函数就会给一个输出。在 YOLOv1 是输入一张图片,输出是一个结构化数据,其中包含图片中出现那些目标以及目标的位置信息。随后文章中会将所有我们要检测不同类别的目标统称为前景

输入的数据是 448 x 448 x 3,由于网络的最后需要接入两个全连接层,全连接层需要固定尺寸的输入,故需要将输入resize。

最后一个 FC 层得到一个 1470 x 1 的输出,将这个输出 Reshap 一下,得到 7 x 7 x 30 的一个Tensor,即最终每个单元格都有一个 30 维的输出,代表预测结果

yolov1_001.jpeg

  • 输出向量表示预测结果 [c,x,y,w,h][c,x,y,w,h]
  • x,y,w,hx,y,w,h 表示位置信息,分别是边界框的中心点和边界框的宽和高
  • Pr(Object)Pr(Object) 表示是前景的概率是多少,还需要乘以一个 IoU,为什么还要乘以一个 IoU 呢?也就是除了希望正确判断是前景,还希望作为前景其预测的边界框与真实的目标边界框越接近。
  • Pr(Classi,Object)Pr(Class_i,Object) 类别,检测为前景,所谓前景也就是说这个网格中存在目标类别,这个用于推出检测目标所属的类别。通过公式来看这是一个条件概率,所以概率可以表示Pr(ClassiObject)×Pr(Object)×IoUpredtruth=Pr(Classi)×IoUpredtruthPr(Class_i|Object)\times Pr(Object) \times IoU_{pred}^{truth} = Pr(Class_i) \times IoU_{pred}^{truth}
  • 每一个网格都负责进行目标检测
  • S×S×(B×(1+4)+C)=7×7×30=1470S \times S \times (B \times (1+4) + C) = 7 \times 7 \times 30 = 1470

025.png

这神经网络输出数值如何映射到图片来用于推理以及和真实值进行对比,在 YOLOv1 网络输出宽和高是一个0 到 1 之间小数,需要乘以图片的真实的宽和高

wpred=0.25wimg=0.25×448=112\begin{aligned} w_{pred} = 0.25\\ w_{img} = 0.25 \times 448 = 112 \end{aligned}

026.png

同理边界框的中心点也采用比例来表示不过还需要结合网格的位置进行计算

网络结构

首先在ImageNet上对网络中的前20层进行预训练,之后再在这20层后连上4层卷积和2层全连接层进行训练。所以,前20层是用预训练网络初始化,最后的这 6 层是随机初始化的并在训练过程中更新权重。此外,因为detection需要更多图片细节的信息,所以在训练时,统一将输入图片的size从 224×224224 \times 224 调整为 448×448448 \times 448

YOLOv1 主要是 24 层的卷积的结构,是由卷积层和全联接层所组成的网络结构。其中没有使用 Maxpooling 作为下采样,而是使用了卷积核大小为 1x1 步长为 2 的卷积作为下采样的方式。中间用的激活函数都是 LeakyReLU,在 YOLOv1 时代还没有 BatchNormalization ,经过卷积提取特征后会得到一个特征向量后,经过一个卷积最终输出 7 x 7 x 3 矩阵

损失函数

其实对于 YOLO ,可能不仅是 YOLO 还包括像 FastRCNN 这样多目标检测框架,要想真正理解好这些框架,就需要对损失函数理解透彻。所以今天我们详细地对 YOLOv1 损失函数进行解释。对于目标检测的损失值和以往我们做的回归和分类问题那样,只考虑比较单一或者说简单损失就可以了,这里需要从多个方面来衡量损失,其中包括定位损失、目标检测损失和分类损失 3 个部分

027.png

定位损失(Location Loss)

yolov1_003.jpeg

i=0S2j=0BIijobj[(xix^i)2+(yiy^i)2+(wiw^i)2++(hih^i)2]\sum_{i=0}^{S^2} \sum_{j=0}^B \mathbb{I}_{ij}^{obj} \left[ (x_i - \hat{x}_i)^2 + (y_i - \hat{y}_i)^2 + (w_i - \hat{w}_i)^2 + + (h_i - \hat{h}_i)^2 \right]
  • 可以用平方差来做损失函数,分别计算预测边界框和这是框间中心位置的偏差以及宽和高的偏差
  • Iijobj\mathbb{I}_{ij}^{obj} 表示第 i 网格中第 j 个边界框,如果负责做预测则为 1 否则为 0 ,我们只考虑那些有前景网格目标检测的损失值

028.png

I51obj=((0.70.7)2+(0.50.5)2+(0.50.5)2+(0.750.7)2)\mathbb{I}_{51}^{obj} =\left( (0.7 - 0.7)^2 + (0.5 - 0.5)^2 + (0.5 - 0.5)^2+ (0.75 - 0.7)^2 \right)
I51obj=((0.60.6)2+(0.50.5)2+(0.20.2)2+(0.30.25)2)\mathbb{I}_{51}^{obj} =\left( (0.6 - 0.6)^2 + (0.5 - 0.5)^2 + (0.2 - 0.2)^2+ (0.3 - 0.25)^2 \right)

根据上看公式我们计算了两个比例差异较大目标的损失值,对于两个目标只是高度方面预测和真实结果存在差异,这样做好处是便于衡量。又是因为这些数值在计算损失值都采用比率方式来表达,这是因为 0 到 1之间数值便于神经网络学习。这是,正是采取了这样表达方式才带了一些问题,对于较小比例物体的误差无法正确地给反应。所以为了消除这个问题,采取对于长和宽采取开根号来解决问题

i=0S2j=0BIijobj[(xix^i)2+(wiw^i)2+(hih^i)2]\sum_{i=0}^{S^2} \sum_{j=0}^B \mathbb{I}_{ij}^{obj} \left[ (x_i - \hat{x}_i)^2 + ( \sqrt{w_i} - \sqrt{\hat{w}_i} )^2 + (\sqrt{h_i} - \sqrt{\hat{h}}_i)^2 \right]
I51obj=((0.60.6)2+(0.50.5)2+(0.20.2)2+(0.30.25)2)+I51obj=((0.60.6)2+(0.50.5)2+(0.20.2)2+(0.30.25)2)=I51obj×(0.03)2+I71obj×(0.048)2\mathbb{I}_{51}^{obj} =\left( (0.6 - 0.6)^2 + (0.5 - 0.5)^2 + (0.2 - 0.2)^2+ (0.3 - 0.25)^2 \right) + \mathbb{I}_{51}^{obj} =\left( (0.6 - 0.6)^2 + (0.5 - 0.5)^2 + (0.2 - 0.2)^2+ (0.3 - 0.25)^2 \right) = \mathbb{I}_{51}^{obj} \times (0.03)^2 + \mathbb{I}_{71}^{obj} \times (0.048)^2

目标损失

i=0s2j=0B(CiC^i)2\sum_{i=0}^{s^2}\sum_{j=0}^B (C_i - \hat{C}_i)^2
i123456789
CiCiC_iCi000110100
C^iCi\hat{C}_iC^i0.10.10.10.10.60.10.60.10.1
CiC^iCiCiC_i - \hat{C}_iCi −C^i0.10.10.10.10.40.10.40.10.1

2×(0.4)2+7×(0.1)2=0.32+0.072 \times (0.4)^2 + 7 \times (0.1)^2 = 0.32 + 0.07

因为在实际中,YOLOv1 中是 7 x 7 x 2 其中 49 个网格,每一个网格提供 2 个预测框所以一共 98 框,而其中,这样问题也就是在 loss 中没有检测到目标的损失值占的比重比较大。也就是在学习过程中会更加重视背景部分,而忽略前景部分的学习。

2×(0.4)2+96×(0.1)2=0.32+0.962 \times (0.4)^2 + 96 \times (0.1)^2 = 0.32 + 0.96

这里 YOLOv1 设计者直接给出一个系数来平衡前景和背景的学习,这个系数根据实验得来通常为 0.5

i=0S2j=0SIijobj(CiC^i)2+λnoobji=0S2j=0SIijobj(CiC^i)2\sum_{i=0}^{S^2} \sum_{j=0}^S \mathbb{I}_{ij}^{obj} (C_i - \hat{C}_i)^2 + \lambda_{noobj} \sum_{i=0}^{S^2} \sum_{j=0}^S \mathbb{I}_{ij}^{obj}(C_i - \hat{C}_i)^2

分类损失(Classification Loss)

i=0S2Iijobjcclasses(pi(c)p^i(c))2\sum_{i=0}^{S^2} \mathbb{I}_{ij}^{obj} \sum_{c \in classes} (p_i(c) - \hat{p}_i(c))^2

主要针对每一个网格,计算方式的,物体中心在某一个网格时候在会在进行学习。

最终我们将这个三个损失进行求和作为总的损失,在学习过程中就是以这个总的损失值最小作为目标进行学习。在求和时,对定位损失前还需要加上一个系数就是 lambda 这个数设置也是一个经验值为 5 目的就是让学习过程更加重视定位的准确性而已。

现存问题

029.png

  • 两个目标出现在同一个网格,YOLOv1 学习就会出现一些问题,如图车和人中心点都落在同一个网格中,YOLOv1 就无法给出正确预测,其实这样情况还是很多,所以这个缺点对于 YOLOv1 来说是一个必须解决问题,随后介绍 YOLOv2,YOLOv3 时大家会看到 YOLO 的设计者是如何一步一步将这个问题进行解决的
  • 每一个网格最多只能够检测到一个物体,所以即使同一种类别多个物体的中心都落在同一个网格,YOLOv1 检测起来还是比较吃力的。
  • 其实这些问题都是 YOLOv1 设计原因,所以无法通过调参数来解决
  • YOLOv1 需要大量资料来进行学习,特别对于写边界框宽高比 YOLOv1 在学习资料中没有见过的目标,对于这样目标检测效果就会差一下

030.png

  • 从上图来看 Background 错误来看,YOLOv1 在将背景误判为前景的错误率相对于 Fast R-CNN 要低很多。为什么会有这样结果呢,因为在 YOLOv1 用于测试网格只有 98 个,而在 Fast R-CNN 中用于检测网格大约在 2000 个左右,所以就不难理解为什么 Fast R-CNN 容易将前景误判为背景了。
  • 对于前景检测能力 YOLOv1 要略低与 Fast R-CNN,这个和上面道理相同,因为 Fast R-CNN 用于检测目标的候选框远远多于 YOLOv1 所以检测效果一定要好
  • 从定位准确度来看,表示分类正确了,在这些分类正确目标的预测边界框和真实的边界框之间 IoU 位于 0.1 到 0.5 之间的数量,这个数量越多说明定位准确度越差,YOLOv1 在定位准确度上较 Fast R-CNN 还需要努力。

031.png

我们在看 Faster R-CNN 和 YOLOv1 在 PASCAL VOC 2007 数据集上测试结果进行对比 YOLO 每秒处理的能力 45 要远远大于 Faster R-CNN 的每秒 18 帧的处理能力,所以从速度和性能两个方面综合考略,在当时 YOLO 具有绝对优势