目标检测系列(2)—又一个 one stage 的目标检测模型—SSD(上)

1,222 阅读8分钟

前言

自从 3 年前的一次心血来潮,坚持到今天,一路走来经历了很多,也学到很多。特别是当遇到一个自己完全不了解,且有一定深度领域应该如何下手。以后有机会和大家分享一下自学机器学习的经历,希望让大家可以避免一些学习上弯路。深度学习,也学了,也用了,多少也算是对深度学习有了一些了解、特别是深度学习在计算机视觉领域的应用有了一定了解。不过感觉自己虽然学习了,但对许多知识点理解不够深入,还是停留在表面。最近自己时间比较多,所以一是想深入研究一下,二是想把这些零散知识点连接起来。整理出一套资料

  • 深度学习框架剖析
  • 目标检测
  • 语义分割

这两年的工作主要还是集中在目标识别和语义分割这 2 个计算机视觉的任务上。所以分享中主要这两条主线进行展开介绍深度学习在计算机视觉上应用。

对于目标检测任务会有些一些共性问题,我们随后会看一看不同网络针对这些问题是如何给出自己的答案的

  • 正负样本不均衡问题
  • 不同尺度目标识别
  • 如何有效定义一个损失函数

one stage detection

什么是 one-stage 目标检测

之前分享过一篇关于 YOLOv1 的文章,目标检测系列—深度解读 YOLOv1 (1) 其实 YOLO 系列模型从 v1 到 v5 都属性 one stage 目标检测模型,今天要介绍的 SSD 也属于 one stage 目标检测的模型。好那么,什么是 one stage 呢? 所谓 one-stage 也就是模型只对输入图像进行一次观察(检测),便可以给出了预测结果(检测出事先定义好的类别以及其位置),其实这里 one stage 是相对于之前 two stage 模型而说的。two stage 是对图像观察两次,第一次观察图像后,给出了许多其中可能包含目标的候选框(区域),接下来在第二次观察,是在这些候选区域上进行目标检测,并且对候选框进行调整以准确地表示出目标位置和大小。

011.png

one-stage 目标检测一般流程

在开始介绍 SSD 之前,就需要先清楚什么是 one-stage 目标检测的一般流程。one stage 目标检测是先把图像以网格形式划分为若干区域。每个小区域通常称为网格(grid cell),每个区域负责检测目标,在 YOLOv1 中,每个网格负责检测那些中心点落在该网格区域内的目标。在 SSD 以及 YOLOv2 以后版本,他们都引入锚框(anchor box)的概念,每个网格会生成一系列锚框(anchor box),然后基于这些锚框来生成预测框来负责检测目标,模型要学习的是预测框相对于锚框的偏移量。

001.png

SSD(Single Stage Detection)

首先我们在一阶段目标检测网络中没有使用候选框生成,而是使用。在 SSD 中就是将图片划分成网格,然后每一个网格创建一些锚框,这些锚框会给出一个其所属类别的预测,类别数中除了数据集提供类别外还包括了背景这个类别,例如 VOC 是 20 个类别,那么每个锚框负责是从 21 类别(将背景算为一个类别)

结合上图我们来看一看 SSD ,经过一系列卷积操作后,得到了 m×n×pm \times n \times p 特征图,其中 p 是通道数,例如 8x8 和 4x4 特征图,然后在这些特征图上应用 3x3 的卷积。对于每一个位置,拿到 k 个边界框,这些边界框具有不同大小和宽高比,这样做的目的让边界可以适应各种不同宽高比的目标。然后每一个边界框会具有类别(这里类别包括背景)的得分以及边界框相对于初始给定边界框的偏移量,也就是会有 (c+4)kmn 个边界框。

SSD 结构图

008.png

在网络结构上,SSD 和 YOLOv1 虽然都是 one-stage detector 的确有着明显的差异。YOLOv1 主干网络是一个自定义的网路结构,而且最后两层是全连接,随后 reshape 成想要的输出形状。而 SSD 是在 VGG16 基础上进行了改造,并且最后都是卷积层,并没有用到全连接层。

009.png

如上图,在 VGG16 的第 5 模块将其 Pooling 层替替换为 3x3 卷积层,然后再经过一个 Atrous/Dilated Conv 层后进行一系列卷积操作得到不同尺度的特征图。

为了有更准确的检测,输出不同尺寸的特征图还要经过一个 3×3 的卷积再进行物体检测,如上图。

016.png

这里以 Conv4_3 为例,其尺寸是 38×38×512,对其应用 3×3 的卷积输出预测。每个网格有 4 个边界框,每个边界框将要预测(类+4)个类别。因此在 Conv4_3 中,输出是 38×38×4×(c+4)。假设数据集为 VOC,有 20 个类别,再加上 1 个背景类,那么输出就是 38×38×4×(21+4)=144,400,边界框数量就是 38×38×4=5776。以此类推

  • Conv7: 19×19×6 = 2166 边界框 (这里对于网格位置 6 边界框)
  • Conv8_2: 10×10×6 = 600 边界框 (这里对于网格位置 6 边界框)
  • Conv9_2: 5×5×6 = 150 边界框 (这里对于网格位置 6 边界框)
  • Conv10_2: 3×3×4 = 36 边界框 (这里对于网格位置 4 边界框)
  • Conv11_2: 1×1×4 = 4 边界框 (这里对于网格位置 4 边界框)

现在我们把所有不同特征层的边界框加起来,共得到了 5776+2166+600+150+36+4=8732 个边界框。前面说的 YOLOv1 ,将图像划分为 7×7 的网格,每个网格有 2 个边界框,一共得到 7×7×2=98 个边界框,这与拥有 8732个边界框的 SSD 相比,YOLOv1 边界框要少的多。

损失函数

损失函数由两部分组成,分别 LconfL_{conf}LlocL_{loc},其中 N 是匹配上的默认的边界框。

L(x,c,l,g)=1N(Lconf(x,c)+αLloc(x,l,g))L(x,c,l,g) = \frac{1}{N}\left( L_{conf}(x,c) + \alpha L_{loc}(x,l,g) \right)
  • 这里 N 是匹配上边界框的数量,也就是正例样本数量
  • α\alpha 是一个权重值,这里 α\alpha 取值为 1

分类损失函数

关于分类损失函数这里使用 softmax 损失函数

Lconf(x,c)=iPosNxijPlog(Ci^P)iNegN(Ci^0)L_{conf}(x,c) = -\sum_{i \in Pos}^N x_{ij}^P \log(\hat{C_i}^P) - \sum_{i \in Neg}^N (\hat{C_i}^0)
  • 这里第一部分 iPosNxijPlog(Ci^P)-\sum_{i \in Pos}^N x_{ij}^P \log(\hat{C_i}^P) 正样本类别损失
  • 第二部分 iNegN(Ci^0)\sum_{i \in Neg}^N (\hat{C_i}^0) 是负样本的类别损失
  • Ci^P\hat{C_i}^P 表示第 ii 个默认框预测为pp 类别的概率,因为第 ii 个默认框对应 GT 边界框所框住的目标类别为 pp
  • xijpx_{ij}^p 当第 i 个默认框与第jj个 GT 边界框框进行匹配,这里 PP 表示 GT 的第 P 类别也就是第 ii 个默认框对应到 jj GT 边界框的 PP 类别概率
Ci^p=exp(CiP)Pexp(CiP)\hat{C_i}^p = \frac{\exp(C_i^P)}{\sum_{P} \exp(C_i^P)}
Lloc(x,l,g)=L1smooth(12ijxijligj2)L_{loc}(x,l,g) = L_1^{smooth}(\frac{1}{2} \sum_{ij} x_{ij}||l_i - g_j||^2)

这里 xijx_{ij} 表示表示边界框和真实框的 IoU 大于 0.5 才会列入计算。

019.png

再是实际预测时候,不是直接预测边界框,而是预测边界框相对于锚框的偏移量,在训练时候也是要学到让预测边界框相对于锚框的偏移量接近真实框(GT)相对于锚框的偏移量。

在上图中,位于右上角图中,用绿色框表示真实框,在图像中,通常以左上角点作为原点,然后 x 和 y 表示目标中心点,w 和 h 表示目标宽和高。接下来在左下角图中,橘黄色框表示一个锚框,通过 IoU 计算这个锚框和真实框比较接近,如果用 y,xy^{\prime},x^{\prime} 表示锚框中心点,h,wh^{\prime},w^{\prime} 表示锚框高和宽,要学习的是锚框相对于真实框偏移量也就是Δx,Δy\Delta x ,\Delta y

x=x+Δxy=y+Δyx = x^{\prime} + \Delta x\\ y = y^{\prime} + \Delta y

其实继续来看右下角图,并不是直接预测 Δx,Δy\Delta x ,\Delta y ,而是 Δx/w,Δy/h\Delta x/w^{\prime} ,\Delta y/h^{\prime}Δx,Δy\Delta x ,\Delta y 进行了归一化的处理,同对于宽高是预测 log(w/w)\log(w/w^{\prime})log(h/h)\log(h/h^{\prime}) 其实这样做的好处就是将这些值归一化到 0 到 1 之间,便于学习和预测。

smooth L1 损失函数

这里从名字上来看

在 Fast RCNN 和 SSD 关于边界框位置回归都用到了 Smooth L1 这个损失函数,这个损失函数具有 L1 和 L2 优点,也就是首先 Smooth L1 要比 L1 收敛快,但是相对于 L2 函数对离群点又不那么敏感,梯度变化相对更小。

但L2范数的缺点是当存在离群点的时候,这些点会占loss的主要组成部分。比如说真实值为1,预测10次,有一次预测值为1000,其余次的预测值为1左右,显然loss 值主要由 1000 这个离群点占得比重比较大。所以 FastRCNN 采用稍微缓和一点绝对损失函数(smooth L1损失),是随着误差线性增长,而不是平方增长,通过上图可以看出 L1 、L2 和 Smooth L1 三者之间的关系。

017.png

0.5x2  ifx<1x0.5  otherwise0.5x^2 \; if|x| < 1\\ |x| - 0.5 \; otherwise
Lloc=ijmx,y,h,w1ijmatchL1smooth(dmitmi)2L_{loc} = \sum_{ij} \sum_{m \in x,y,h,w} \mathbb{1}_{ij}^{match} L_1^{smooth} (d_m^i - t_m^i)^2

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿