1、RCNN系列
1.1 从RCNN到Fast RCNN、Faster RCNN
(1)RCNN(2014)
Object Detection任务主要包含两个内容:识别物体,确定位置。在识别物体这一块,传统的做法是利用特征点来表征物体的类,例如:SIFT,SURF等;在CNN方法出现之后,普遍采用“卷积+池化+全连接”的方式来完成。而对于确定物体的位置,最流行的就是莫过于Region Proposal Regression,在图像中产生一系列的候选框,然后利用回归/分类的方式找到最合适的那个box。基于目标检测中的“识别+定位”任务,RCNN提出了下图所示的方法。
总体而言,RCNN的流程分为三步:
- 提取候选区域:这里相当于找到可能存在目标物体的位置,但是只是候选位置,后面会通过一些手段去掉那些不正确的;
- 利用CNN计算特征:它的输入就是前一步中找到的候选区域图像,输出的是区域图像的特征向量;
- 区域分类与回归:根据区域图像特征向量来判断该候选区域属于哪一类,也有可能是属于背景。
详细来说,在第一步会产生大约2000个左右的 Region Proposal,所使用的方法是 Selective Search(SS,选择性搜索)。在第二步中对 proposal 进行 crop/warp 操作将其处理到固定大小 227*227,以此作为 CNN 的输入;CNN 模型包括5个卷积、2个全连接,由此得到每一个 proposal 的特征,其大小为 4096 维。第三步中分类采取 SVM 方法,将 proposal feature 送入每一类的 SVM 判断它是否属于该类别,它会对该区域所属类别进行打分,利用 NMS 找到那些最有可能的 proposal;起初 proposal 的位置跟 Groundtruth 会有区别,在每一次迭代学习过程中使用 Bounding Box Regression 的方法对其进行修正:构建一个线性回归器,将 region feature 作为输入,计算得到 proposal 在当前位置上的缩放和偏移尺寸,然后进行更新。
Selective Search 是产生Region Proposal的一种方法,和它相同地位的还有:穷举搜索、sliding window等。
SS方法先是通过图像分割的方法得到一个区域集R,该集合中的每一个元素都是原图像在像素级别上的一个segmentation,看起来就跟油画一样是不能够作为Regina Proposal的(有部位上的重叠、包含、遮挡等)。
SS给R的每一个元素套上一个Box,然后计算相邻区域的相似度(基于颜色、纹理、尺寸、形状)得到一个相似度集S,根据S挑选出相似度最高的两个区域 r i 、 r j r_i、r_j ri、rj;二者合并得到 r t r_t rt 后,将 r t r_t rt 加入集合R,然后把S中与 r i 、 r j r_i、r_j ri、rj 相关联的部分全部去掉,重新计算 r t r_t rt 与相邻区域的相似度、并加入S;反复迭代,直到S为空。
RCNN的问题在于:
- Region Proposal 的选取太耗时;
- 候选区域之间的重叠部分特征相同,但是依然会被作为不同的 proposal 送入CNN进行计算,导致特征提取存在冗余;
- CNN中的全连接层要求输入特征尺寸相同,因此送入CNN的区域需要通过 crop/warp 操作来固定大小,而这种操作又会让图像变形,降低识别的准确性
- SS、SVM、边框回归三个部分相互独立,每一步都需要单独训练,耗时且无法实现end-2-end。
之后的SPP-Net(Spatial Pyramid Pooling,作者:何凯明)针对RCNN的第二、三点问题进行改进,它把提取到的 Region Proposal 的位置信息放在CNN卷积之后,让CNN先针对整体图像计算特征,然后将位置信息通过比例映射到整张图的 feature map上提取出候选区域的特征图,这样就不用针对每一个候选区域计算特征图了;其次,取消对 proposal 的 crop/warp 操作,这样 proposal 的大小就各不相同,所以要在全连接之前加入 SPP 层,保证全连接层接收到的特征尺寸不变。
(1)一般我们要求输入CNN的图像尺寸保持一致,实际上这种硬性需求与卷积层无关,而是全连接层的需求。因为卷积层只要指定卷积核大小、步长后,图像多大都无所谓,但是全连接层它要把特征拼接成一个特定维度的向量,如果输入特征尺寸不同那么所需要的参数量也不相同。
(2)SPP全称是Spatial Pyramid Pooling(空间金字塔池化),它加在全连接层之前。具体来说,对于任意一个维度的特征,它将对其做三种分割:4*4、2*2、1*1,依次可以得到16、4、1个网格,然后在这21(在RCNN中,有20个目标类别,外加一个背景类)个网格中分别进行最大池化得到一个一维的值,将这21个值拼接成一个21维向量最为最终输入全连接层的特征。
(2)Fast RCNN(2015)
Fast RCNN借鉴了SPP的思想,在 RCNN 的基础上做出以下改进:
- 不再对每个 proposal 做单独的特征提取,而是在整张图像上提取特征,然后按照对应的位置、大小映射到不同的候选区域,避免 Region Proposal 特征的重复计算。
- ROI池化:ROI 在这里指的是网格,它借鉴了 SPP 的思想,取消对 proposal 的 crop/warp,直接将区域特征图划分成 H ∗ W H*W H∗W 个网格(例如 3 ∗ 7 = 21 3*7=21 3∗7=21),然后对每一个网格使用最大池化,这样池化后的特征尺寸就只取决网格划分的方式,而对输入图像尺寸保持不变性。同时它可以进行反向传播,为end-2-end打下基础。
- 用 softmax 替代 SVM 做 proposal 的分类,在损失函数中加入 softmax loss,将分类、回归放在一起完成。
- 全连接层的计算针对于所有 proposal feature,这是整个 CNN 网络中主要的计算量,为了降低计算复杂度,将全连接层中的权重矩阵进行 SVD(奇异值分解)。
Fast RCNN的整体框架如下图所示,相比较于RCNN而言它弥补了RCNN的很多缺陷,但是仍然采用 selective search 的方法来提取 Region Proposal,这也成为它在速度方面的最大限制。
(3)Faster RCNN(2015)
相比于 Fast RCNN,Faster RCNN 的改变主要在以下两点:
- RPN:Region Proposal Network,区域生成网络,以此替代之前一直使用的 selective search 方法,使得候选框的选取速度、精度大大提升。Faster RCNN 可以看做是 RPN+Fast RCNN 的系统,它将训练好的 RPN 模型嵌入到Faster RCNN 中,实现了 RPN 与 Faster RCNN 的权值共享。
- Anchor:这个是 RPN 产生 proposal 时所使用的一种策略,CNN 卷积层之后会输出一个 feature map,它的大小随输入图像大小而变化,Faster RCNN 在 feature map 的每个特征点上产生9个固定大小的锚框 anchor,锚框的初始尺寸通过聚类算法从数据集中统计得到,然后让 RPN 对这些锚框进行边框回归,由此得到大量 proposal。
下图给出了 Faster RCNN 的整体框架,其主要改进点落在 RPN,而 RPN 中最富新意的就是锚框Anchor。
Faster RCNN 网络接受任意尺寸的图像作为输入,通过卷积操作计算得到该图像的feature map,随后将 feature map 输送给 RoI 的同时共享给 RPN。RPN 会先在 feature map 的每一个像素点上产生 9 个固定尺寸大小的锚框 anchor,如上图右上角所示;对于每一个锚框,RPN 会进行两个操作:(1) 利用 softmax 判断锚框所选区域是前景还是背景;(2) 对锚框所选区域内的特征进行边框回归。softmax 给出二分类概率值,边框回归对锚框进行位置偏移得到预测框
x
y
w
h
xywh
xywh。接着对预测框进行筛选:先利用前景分类概率 foreground score 进行排序,根据 top-k 输出一定数量的预测框;然后将预测框对应的 anchor 在特征图中的位置映射回原始图像,剔除掉那些严重越界的预测框;最后用非极大值抑制 NMS 再次筛选,输出最终的Region Proposal。得到 proposal 以后,后续操作就跟 Fast RCNN 一样了。
RPN 在 Faster RCNN 中独立完成训练,它的训练方法、训练数据、训练过程都是独立的,训练好了之后直接把它嵌入在Faster RCNN中。
1.2 Mask RCNN(2017)理论基础——论文
Mask RCNN 是何凯明基于 Faster RCNN 模型提出来的一种 Instance Segmentation(实例分割)方法。
Object Detection:目标检测,输出图像中个体的bounding box。
Semantic Segmentation:语义分割,输出像素级别的类归属。
Instance Segmentation:实例分割,输出像素级别的类归属以及类的实体ID,就是给出每一个实例的轮廓。
上图左边给出了 Mask RCNN 的模型结构,大体上沿袭了 Faster RCNN 的框架思路,不同之处在于:
(1)RoI Align 代替 ROI Pooling
之前 Fast/Faster RCNN 在全连接层之前都采用 RoI Pooling,这可以使得模型能够接受任意尺寸大小的图像作为输入。但是,该方法有两个量化问题:(1) RPN 方法得到的锚框 anchor 需要进行边框回归,回归结果是一个浮点数,在映射到 feature map 上时需要做舍入;(2) 网格的划分直接采用
w
/
W
、
h
/
H
w/W、h/H
w/W、h/H,也需要进行舍入。
这两次量化会直接影响 proposal 的准确性。RoI Align的做法是:回归和网格划分还是照做,但是不再进行舍入,而是在网格(位置大小均是浮点数)内找四个位置固定的虚拟坐标点,这四个点的特征值由网格内的真实特征点根据双线性插值计算得到,然后对这四个虚拟特征点做 max pooling 操作。当然了,不一定非要是4个虚拟特征点,实际上只用网格中心点的双线性插值也可以达到相类似的效果。
(2)加入 mask 分支
Faster RCNN 在全连接之后通过两个分支分别输出 proposal 的类别和预测位置,Mask RCNN 在此基础上增加一个 mask 分支,该分支利用 FCN 对 proposal 特征图中的每一个像素进行分类。原始的 FCN 中用的是 softmax 和交叉熵,Mask RCNN 为了避免同类间的竞争,采用了 sigmoid,并对每个 proposal 区域输出
k
∗
m
∗
m
k*m*m
k∗m∗m 维度的mask,
k
k
k 是类别数量,
m
m
m 就是 proposal 经过 RoI Align 得到的特征图的尺寸,将特征图的点映射回原始图像,就能得到原始图每个像素点的类别。因为该分支输出了针对每一类的 mask,这样就不涉及像素之间的类别竞争。要注意的是,
L
m
a
s
k
L_{mask}
Lmask 在计算时只针对 proposal 所属的第
k
k
k 类,其他类 mask 不参与损失函数计算。
关于FCN:
(1)FCN是Semantic Segmentation的里程碑之作,它对图像进行像素级的分类,解决了语义级别的图像分割。
(2)FCN不包含全连接层,只有卷积层,在最后一个卷积层的后面接一个反卷积层,将feature map还原到原始图像尺寸大小,对每一个像素进行预测,最后逐像素求softmax损失,这就相当于每一个像素就是一个样本。
Mask RCNN 的特征提取网络使用的是 ResNet101,同时文章也给出 FPN 的同等对比方案,因为 FPN 能融合不同尺度上的特征,所以它能提炼更加丰富的上下文信息。
关于FPN:
一般的特征预测可以有三种形式:(1)采用网络最后一层的特征预测,典型的有SPP、Fast/er RCNN;(2)图像金字塔,每一种图像尺寸进行一次特征预测;(3)多尺度融合,每一层特征进行一次预测,不同层之间没有联系,典型的有SSD。
FPN(Feature Pyramid Network),特征金字塔网络,顶层特征通过上采样和底层特征进行融合,层与层之间有相互联系。
1.3 Mask RCNN的实现与效果
Mask RCNN的Tensorflow版本开源下载地址。
代码写的很清晰、很整洁,不管能不能理解原理,先让它跑起来再说,看一下结果。
此项目依赖于COCO,其配置方式为:
- 下载COCO项目:git clone https://github.com/pdollar/coco
- 编译Python API:cd coco/PythonAPI >>> make -j8
- 复制coco/PythonAPI/pycocotools文件夹到samples/coco中(和coco.py同级目录)
Mask RCNN的官方源码在Detectron,Detectron是Facebook的开源物体检测平台,它基于Caffe2、用Python写成。除了Mask RCNN的实现之外,Detectron还包含了ICCV 2017最佳学生论文RetinaNet,Ross Girshick 此前的研究Faster R-CNN和RPN、Fast R-CNN、以及R-FCN的实现。
1.4 Mask RCNN的后续进展
Mask RCNN的出世时间是2017年,到目前为止它依然是相当强悍的目标检测方法之一,当然也不乏超越它的作品。
- 2017年,旷视提出Light-head RCNN,它在性能上超越了Mask RCNN,在模型使用更小的网络时其效率更是超过Yolo和SSD。它这里的“head”指的是Fast RCNN进行RoI Pooling之后的分类/回归网络部分,文章旨在对这一部分进行优化,针对该部分提出了性能更好的RCNN-subnet,优化了计算、降低了复杂度。
- Reasoning-RCNN:Faster RCNN是一种常用的物体检测模型,然而,当检测类的数量小于100时,物体检测是最成功的。Reasoning-RCNN 针对具有数千个类别的大规模物体检测问题,提出了一种基于长尾数据分布、重遮挡和类模糊的目标检测方法。该模型在3个主要数据集上进行训练和评估——Visual Gnome(3000个类别)、ADE(445个类别)和COCO(80个类别)。该模型能够在Visual Gnome上获得16%的提升,在ADE上获得37%的提升,在COCO上获得15%的提升。
2、Yolo系列
RCNN 系列属于目标检测中 2-stage 方法的代表作品,之所以称为 2-stage 是因为它们需要先通过一类算法找到图像中的候选区域 Region Proposal,然后再利用另外一类算法对这些区域进行分类、回归,完成目标检测问题中的识别与定位。该方法的 pipeline 需要多个独立的部分,每一部分需要单独数据集、单独训练,过程较为繁琐且无法实现端到端的训练。
针对 2-stage 的问题,YOLO 提出 1-stage 的目标检测方法:Fast RCNN 主要的改进不是将 proposal 进行网格划分嘛,YOLO 将这种思想直接应用到原始图像上,那就不需要做生成 proposal 的工作了呀!所以,YOLO 将 proposal生成、分类、回归放到一个模型中统一完成,在速度上有相当的优势,虽然精度有所降低,但是随着版本的进化也相应的有所改善。
2.1 从Yolo v1到Yolo v2
(1)Yolo(2015)
Yolo使用最直观的求解思路,对于输入的完整图像,经过一个网络直接给出每一个目标物体的位置bbox、所属类别,它的思路设计可以概括为以下几步:
- 将图像分割成一个 S ∗ S S*S S∗S 的网格:;
- 每一个网格给出 B B B 个 bbox,每个 bbox 包含五个输出值:中心点坐标+尺寸 ( x , y , w , h ) (x,y,w,h) (x,y,w,h) ,置信度 c o n f i d e n c e confidence confidence;
- 每一个网格还给出它属于每一类的概率 P r ( C l a s s i ∣ O b j e c t ) Pr(Class_i|Object) Pr(Classi∣Object);
- 对 2、3 的输出结果进行 NMS 处理,依此给出整张图的目标物体的位置、类别。
下图是Yolo的流程图:
为什么可以直接在原始图像上划分网格?Faster RCNN 在特征图的每个特征点上生成 anchor,如果把这些特征点映射回原始图像其实也就是一个个的网格,YOLO 相当于直接把特征点映射回去了,希望通过原始图像上的网格直接产生对目标物体的预测。
在开始训练之前,要为图像的每个网格打上标签,生成标签的做法是:根据真实的目标框所在位置,判断它落在哪个网格内,包含目标框中心点的网格会被赋予有效的 label(真实类别,真实边框)。 对于需要网络预测的 bbox,它的表达形式为
(
x
,
y
,
w
,
h
)
(x,y,w,h)
(x,y,w,h),前两个参数给出 bbox 的中心相对于该网格左上角的所在位置,后两个参数给出了 bbox 相对于全图的大小尺寸,它们的值都被归一化到 0~1。网络最终的输出形式是
(
7
,
7
,
30
)
(7,7,30)
(7,7,30),因为原始图像被划分成
S
∗
S
=
7
∗
7
S*S=7*7
S∗S=7∗7 个网格,每一个网格有
B
=
2
B=2
B=2 个 bbox 预测,每个预测框有5个位置参数 、
C
=
20
C=20
C=20 个类别参数,所以最终特征正尺寸是 7*7,通道数量是 5*2+20=30。根据此输出值,计算 bbox 的所属类概率
c
o
n
f
i
d
e
n
c
e
∗
P
r
(
C
l
a
s
s
i
∣
O
b
j
e
c
t
)
confidence * Pr(Class_i|Object)
confidence∗Pr(Classi∣Object) 也就是 bbox 的置信度乘以它所在网格类概率。虽然每个网格都能计算这样一个值,但是只有在前面的 label 标签中包含目标框中心点的网格才有资格作为预测值,参与到后续loss计算。具体来看看损失函数:
λ
coord
∑
i
=
0
S
2
∑
j
=
0
B
I
i
j
obj
[
(
x
i
−
x
^
i
)
2
+
(
y
i
−
y
^
i
)
2
]
+
λ
coord
∑
i
=
0
S
2
∑
j
=
0
B
I
i
j
obj
[
(
w
i
−
w
^
i
)
2
+
(
h
i
−
h
^
i
)
2
]
+
∑
i
=
0
S
2
∑
j
=
0
B
I
i
j
o
b
j
(
C
i
−
C
^
i
)
2
+
λ
n
o
o
b
j
∑
i
=
0
S
2
∑
j
=
0
B
I
i
j
n
o
o
b
j
(
C
i
−
C
^
i
)
2
+
∑
i
=
0
S
2
I
i
o
b
j
∑
c
∈
classes
(
p
i
(
c
)
−
p
^
i
(
c
)
)
2
\begin{array}{l} {\lambda_{\text { coord }} \displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\text { obj }}\left[\left(x_{i}-\hat{x}_{i}\right)^{2}+\left(y_{i}-\hat{y}_{i}\right)^{2}\right]} \\ +\lambda_{\text { coord }} \displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\text {obj}} \left[\left(\sqrt{w_i}-\sqrt{\hat{w}_{i}}\right)^{2}+ \left(\sqrt{h_i}-\sqrt{\hat{h}_{i}}\right)^{2} \right]\\ +\displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\mathrm{obj}}\left(C_{i}-\hat{C}_{i}\right)^{2} \\ +\lambda_{\mathrm{noob} j} \displaystyle \sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\mathrm{noobj}}\left(C_{i}-\hat{C}_{i}\right)^{2} \\ +\displaystyle\sum_{i=0}^{S^{2}} \mathbb{I}_{i}^{\mathrm{obj}} \sum_{c\in\text {classes}}\left({p_{i}(c)-\hat{p}_{i}(c)}\right)^{2} \end{array}
λ coord i=0∑S2j=0∑BIij obj [(xi−x^i)2+(yi−y^i)2]+λ coord i=0∑S2j=0∑BIijobj[(wi−w^i)2+(hi−h^i)2]+i=0∑S2j=0∑BIijobj(Ci−C^i)2+λnoobji=0∑S2j=0∑BIijnoobj(Ci−C^i)2+i=0∑S2Iiobjc∈classes∑(pi(c)−p^i(c))2第一部分计算的是包含物体中心的网格的 bbox 中心位置损失,这里只会计算与 GroundTruth 交并比最大的那个 bbox,虽然给的
j
j
j 值是0~B,但是后面的计算只与
i
i
i 有关,说明只有一个bbox参与计算。具体是哪一个 bbox,由
I
i
j
obj
\mathbb{I}_{i j}^{\text {obj}}
Iijobj 计算得到,它给出了根据
I
O
U
IOU
IOU 选择 bbox 的数学表示。
第二部分计算的是尺寸损失,大物体与小物体同时偏离一个尺寸带来的误差是不同的,这里为了减小这种尺度大小带来的影响,将
w
/
h
w/h
w/h 进行开方然后计算损失。
第三部分计算的是置信度损失,与前两部分相比这一部分没有系数
λ
coord
\lambda_{\text {coord}}
λcoord,原因是 bbox 位置信息与置信度信息维度不同、重要性不同,如果将它们同等对待处理显然不合理,为了突出 bbox 损失故在其前面加入系数
λ
coord
=
5
{\lambda_{\text{coord}}}=5
λcoord=5。
第四部分计算的是不包含物体中心的网格置信度损失,
I
i
j
noobj
\mathbb{I}_{i j}^{\text {noobj}}
Iijnoobj 负责教会模型判断哪些网格不包含物体中心,系数
λ
noobj
=
0.5
{\lambda_{\text{noobj}}}=0.5
λnoobj=0.5 弱化这类网格的影响。
第五部分计算的是分类损失,它与bbox是无关的,所以判别参数是
I
i
obj
\mathbb{I}_{i}^{\text {obj}}
Iiobj,且与置信度同等重要。
(1)包含物体中心的网格:需要计算分类loss,两个predictor都要计算置信度loss(系数不同),预测的bbox与ground truth IOU比较大的那个predictor需要计算位置、尺寸loss。
(2)不包含物体中心的网格:只需要计算置信度loss。
上图是Yolo的网络结构,对于卷积层的参数先用 ImageNet 做分类预训练,预训练输入图像尺寸为 224*224,之后进行检测训练时将输入图像尺寸改为 448*448(为什么要这样做?)。
RCNN 系列的边框回归是在 proposal/anchor 上进行的,而 YOLO 没有做边框回归,它直接输出 bbox 的中心位置、尺寸大小,中心点针对网格左上角,尺寸大小是相对于全图而言,如果要类比的话可以认为这里的网格就相当于 RCNN 系列中 的 anchor,不准确哈!YOLO 的不足在于:一个网格最终只有一个目标物体的输出,这导致它对那些尺寸较小或者比较拥挤的目标的检测不是很准确。
(2)Yolo v2(2017)
Yolo-v2对Yolo进行了多方面的改进。
- BatchNormal的使用:BN 首次出现是在2015年的Inception v2,但是在2016年的 Yolo 中并未使用,Yolo-v2 加入此部分,使得mAP获得了2%的提升,同时去掉了 dropout 也不会产生过拟合;
- 高分辨率分类器:Yolo 在预训练分类器时使用 224*224 图像,在检测时使用448*448图像,这使得网络需要重新适应新的输入图像尺寸,Yolo-v2 则直接采用448*448 分辨率图像(还是ImageNet数据库)来做预训练,将mAP提高4%;
- 卷积联合Anchor:Yolo-v2 借鉴Faster-RCNN 的 Anchor 方法,在 Yolo 中是通过两个全连接层得到 7*7*30 的输出,这里直接将全连接层去掉,然后调整卷积网络的池化层,将输入图像改为 416*416,确保卷积网络的最终输出是一个13*13 的 feature map,然后在每一个特征点上产生 Anchors;Yolo 一个网格只会预测一个物体,而 Yolo-v2 每一个 Anchor 都可能检测到一个物体。这样的操作会稍微降低mAP(69.5%→69.2%),但是 Recall 从81%上升到88%,说明可检测到的内容大大提升了(漏检率降低)。
- 维度聚类:这里指的是调整对 Anchor 尺寸的选择,Faster-RCNN 中Anchor 是人为指定的(具体为什么是这个尺寸全来自于经验),Yolo-v2 采用K-means 聚类的方法对训练集进行分析,为的就是找到最优的
k
k
k 值以及最适合的Anchors。最终确定下来
k
=
5
k=5
k=5 是比较合适的,这样 bbox 的数量由 Yolo 的 7*7*2=98 上升到 13*13*5=845。
对于两个数据集,5个先验框的width和height如下: COCO: (0.57273, 0.677385), (1.87446, 2.06253), (3.33843, 5.47434), (7.88282, 3.52778), (9.77052, 9.16828) VOC: (1.3221, 1.73145), (3.19275, 4.00944), (5.05587, 8.09892), (9.47112, 4.84053), (11.2364, 10.0071)
- 直接位置预测:Yolo 中模型直接给出 bbox 的中心坐标位置、尺寸,这在一定程度上会导致模型的不稳定(具体原因可以对比一下RCNN的边框回归,为什么RCNN边框回归的时候不是直接输出坐标值而要进行转换?)。Yolo-v2 效仿 RPN 网络中对 bbox 回归的形式,从网络输出到最终真实bbox的映射定义为 b x = σ ( t x ) + c x b y = σ ( t y ) + c y b w = p w e t w b h = p h e t h Pr ( Object ) ∗ I O U ( b , Object ) = σ ( t o ) \begin{aligned}b_{x}&=\sigma\left(t_{x}\right)+c_{x} \\ b_{y}&=\sigma\left(t_{y}\right)+c_{y}\\b_{w}&=p_{w}e^{t_{w}} \\b_{h}&=p_{h} e^{t_{h}} \\ \operatorname{Pr}(\text { Object }) * I O U(b, \text { Object }) &=\sigma\left(t_{o}\right) \end{aligned} bxbybwbhPr( Object )∗IOU(b, Object )=σ(tx)+cx=σ(ty)+cy=pwetw=pheth=σ(to)这里, t x 、 t y t_x、t_y tx、ty 是相对于 c x 、 c y c_x、c_y cx、cy 的offset, c x 、 c y c_x、c_y cx、cy 是anchor所在网格相对于图像左上角的位置; t w 、 t h t_w、t_h tw、th 是相对于 p w 、 p h p_w、p_h pw、ph 的offset, p w 、 p h p_w、p_h pw、ph 是先验 anchor 的尺寸(这就体现了先验 anchor 的作用); σ \sigma σ 指的就是激活函数,模型通过学习得到 t x 、 t y 、 t w 、 t h 、 t o t_x、t_y、t_w、t_h、t_o tx、ty、tw、th、to。也就是说,在人工标记 label 的时候需要按照 13*13 网格的方式把 GroundTruth 转化成这种形式。激活函数将位置和置信度参数限定在0~1之间,也就是只在网格附近做预测。维度聚类和直接位置预测使得 Yolo-v2 的mAP值上升了5%。
- 细粒度特征:Faster-RCNN 和 SSD 中将不同层次上的特征图进行融合,使得模型可以适应对小物体的检测;Yolo-v2 照此添加一个“透层”,类似于 ResNet 的操作,将 26*26*516 的上层特征变为 13*13*2048(特征大小变为1/4,通道数变为4倍),然后与最后的卷积输出 13*13*1024 特征连接,得到 13*13*3072 特征图。如此一来,大尺度特征图连接到小尺度,在进行池化操作的时候,一些细节特征、小目标物体就不会被轻易丢掉,这对于小目标物体的检测是有积极效果的,最终该操作可以使mAP提升1%。
- 多尺度训练:Yolo-v2 可以适应不同分辨率的输入图像,其做法是:在训练的时候每迭代一定次数(10个epoch),就换不同的输入尺寸(320~608,以32为等差)。网络进行了5次 max pooling,当输入图片大小为320*320时,最终特征图大小就是10*10;当输入图片大小为608*608时,最终特征图大小就是19*19。
Yolo 使用 GoogLeNet 作为basebone,Yolo-v2 则提出自己的网络结构Darknet-19:
为什么第一层卷积的输出是224*224?实际上,这并不是最终的检测模型的输入尺寸,整个Yolo-v2的训练分三个阶段:
- 预训练阶段:在 ImageNet 分类数据集上从头训练 Darknet-19,图像大小是224*224,总共160个 epoch。
- fine-tuning 阶段:在第一阶段的基础上将输入图像调整为448*448,训练10个epoch,这里除了 epoch 和学习率进行调整以外其他参数均不变。
- 检测训练阶段:将 Darknet-19 分类模型修改为检测模型(去掉最后一个1000通道的1*1卷积层以及 Avgpool、Softmax层,添加3个 1024 通道的 3*3 卷积层,每个卷积后面接上一个1*1卷积),检测数据集用的是VOC和COCO。
前两个阶段其实都是分类预训练,为的是让 Darknet-19 拥有较好的分辨能力;第三阶段才是目标检测,使用的数据集也改成了COCO、VOC-2007。
Yolo-v2 中每个网格有5个 bbox,每个 bbox 有4个坐标值、1个置信度值、20个类别概率值,因此一个网格需要5*(4+1+20)=125个 filters。Yolo中一个网格有2个bbox,这两个bbox共享一个类别概率,Yolo-v2中则是每一个bbox都有一个属于自己的类别概率。
Yolo-v2的细节很多,论文中只给了最为突出的部分,要了解所有的细节还是需要对源码进行剖析。Yolo-v2的损失函数可以参考这里。
这里所说的网格其实是最后特征图上的一个点,但是映射回原图可以看做是一个网格
(Yolo9000的部分有待补充!)
2.2 Yolo v3(2018)
Yolo-v3 论文比 Yolo-v2 还要随意,具体优化内容主要有:
- bbox的预测:基本上还是沿用 Yolo-v2 那一套(对 anchor 的offset),但是 Yolo-v3 使用逻辑回归对每一个框打分,该分数用于选取与 GroundTruth 最为契合的 bbox(之前使用 IOU 最大的bbox),被舍弃掉的 bbox 将只会参与置信度损失的计算。
- 分类预测:Yolo-v2 对于分类使用的是softmax,得到一个20维的向量;Yolo-v3 改变这一做法,它使用多个逻辑分类器,每一个分类器用来判断 bbox 是否属于一个类,然后用二元交叉熵计算损失。这样做的好处是,可以应对 Open Images Dataset 这样的一个物体同时属于多个类的情况。
- 多尺度预测:Yolo-v3 效仿 FPN 的多级特征金字塔,通过上采样和 concat 大尺度特征,可以生成除 13*13 以外的 26*26、52*52 特征图,特征图的每一个特征点拥有3个 anchor,每一个 anchor 拥有4个 offset 数据、1个置信度、80个类别信息。这些 anchor 同样通过 K-means 来获得,只是
k
=
9
k=9
k=9,然后均分给多尺度的每一层。文章给出 416*416 尺度下图像的 anchor 尺寸:
(10×13)、(16×30)、(33×23)、(30×61)、(62×45)、(59×119)、(116 × 90)、(156 × 198)、(373 × 326)
- 特征提取:Yolo-v2 中使用了一个“透层”将 26*26 的特征图连接到 13*13 的特征图上,这有点类似于ResNet的残差思想;Yolo-v3 直接加入残差块,去掉池化的同时增加卷积的步长,保证输入图像经过5次下采样,由此诞生了Darknet-53。
2.3 Yolo v3的实现与效果
作为工程项目来说,Yolo-v3的检测效果应该是相当不错的,这里我们不去讨论mAP、COCO数据集上的表现等刷分用的参数,就仅仅看它在实际应用中的performance,速度、精度都很令人满意。重要的是,Yolo-v3开源代码的使用极其简单,即便是看源码、根据自己的需求修改源码都很方便(主要是代码写得很清晰)。参考Tensorflow版本的项目,得到下图结果。
2.4 Yolo v3的后续进展
Tiny Yolo
Yolo Nano
Gaussian YOLOv3
YOLO-v4
3、SSD
3.1 SSD的理论基础——论文
SSD(Single Shot MultiBox Detector)发表于2015年,Faster RCNN 和 Yolo 之后的作品,它也属于目标检测的 1-stage 范畴,同时借鉴了OverFeat、SPP、Fast RCNN、Yolo、Faster RCNN 的一些思想。SSD 由一个 base network 和6个卷积特征层构成,base network 是自VGG-16改造来的,6个卷积特征层分别输出不同尺寸的特征。
SSD 的网络结构图还是很清晰的,它和 YOLO 的区别就在于:YOLO 只利用到最后一层特征层的信息,而 SSD 则利用了不同尺度上的特征信息,其精度可想而知比 YOLO 要好。在卷积神经网络中,低层卷积更关心特征在哪里,它更多的是提取一些具体的细节信息,其分类准确性并不高;而高层卷积则更关心特征是什么,它提取的是与整体相关的抽象信息,可能丢失了类似物体在哪里的位置信息。SSD 将二者结合,在不同尺度的特征图上设置初始框,对于那些和真实目标交并比较大的初始框,网络对它做分类预测和位置偏移,并从中产生预测值。
SSD 的三个创新点:
- 用于检测的多尺度特征图:相比于 Yolo 而言,SSD 添加了多个卷积特征层用于最终的目标检测(不再是最后一层预测结果),它使得 SSD 可以适应不同尺寸目标物体的检测。(当时 Yolo 的缺陷就是对小目标物体检测不准)
- 用于检测的卷积预测器:SSD的每一个卷积特征层,可以通过一系列的过滤器(1*1、3*3)输出大量预测结果(维度为(Classes+4)的向量),在不同尺度特征图上输出的预测 bbox 数量不同,具体如下表所示,最终得到的检测数量是8732。
- Default Box和长宽比:default box 是SSD中一个很重要的内容,它指代的就是上面生成的8732个预测框,这就类似于 RCNN 系列中的 anchor,它也是在特征图的每一个特征点上产生一系列边框,只不过 default box 在不同尺度上的尺寸大小是不一样的,同真实框之间的转换关系与 Faster RCNN、Yolo-v2 中类似,也就是 offset。还有一个概念就是 prior box,这个是从 default box 中筛选出来的,选取标准是与真实框的 IOU 超过一定阈值,它的数量远小于 default box 数量,最后 prior box 作为正样本,其它 default box 作为负样本。
3.2 SSD的实现与效果
TODO
3.3 SSD的后续进展
TODO
4、RetinaNet
5、Anchor-Free目标检测
anchor的前世今生(上)
anchor的前世今生(下)
知乎1:物体检测的轮回: anchor-based 与 anchor-free
知乎2:目标检测:Anchor-Free时代
anchor based与anchor free对比
anchor free相关论文解析
Anchor-free之SAPD