我正在参加「掘金·启航计划」
本文是我和好友 @Zee 读论文后整理而来,部分表述可能存在不清晰之处、甚至可能出现错误。欢迎交流指正。
部分图片源于互联网,如有侵权,请联系我删除
R-CNN
R-CNN(Regions with CNN features) 是深度学习领域的经典框架之一,首次将卷积神经网络(CNN)引入了目标检测领域,并取得了优秀的效果。为了实现这个目的,本文解决了两个主要问题:使用深度网络定位目标,以及使用少量有标注的数据集训练出高容量的模型。
本文使用的数据集为 PASCAL VOC ,具体内容可以参考 目标检测数据集PASCAL VOC详解
本文涉及文章:Rich feature hierarchies for accurate object detection and semantic segmentation
结构
此目标检测系包含三个模块
- 生成各自独立的区域候选框
- 较大的卷积网络,用以从各区域中提取定长的特征向量
- 一些用以分类的线性 SVM(支持向量机)
最后实际上还有一个部分,使用回归算法精修候选区域。基本流程如下图:
确定候选区域
文章的这一部分用的是 Selective Search ,一种传统的目标检测算法。文章里仅是一笔带过,故在此不做赘述。具体算法原理可以参考:理解Selective Search – 知乎 (zhihu.com)。
此处使用它生成两千个候选区域。
特征提取
此部分通过五个卷积层、两个全连接层,将传入的 227*227 的 RGB 图片提取为 4096 维的特征向量。卷积网络的结构如下:
对于任意区域大小的图片,这里最终采用的是直接拉伸的方法转为 227*227。不过在拉伸前会对区域框做一个扩大处理,使得拉伸后的图片周围有原图的 p 像素上下文(此处 p = 16 )
文章的支撑材料里探讨了几种不同的 warp 方法。
SVM+NMS
对于每一个类别,作者使用相应的已训练好的 SVM 对已提取出的特征向量进行打分。当所有候选区域都打完分后,对每个类别使用 NMS(非极大值抑制)算法,扔掉那些 IoU 高出
给定阈值的区域。下面具体介绍这个部分:
IoU
Intersection-over-union,正如其名称所言,计算的是两个矩形框的交集区域面积除以并集区域面积
该值的取值范围为 [0, 1],0 代表完全不相交,1 代表二者完全等同
NMS
NMS 用于去除重复框,效果如下
它的算法原理并不复杂,主要是下面这几个步骤:
- 给定n个候选框,根据其分数从大到小排序
- 循环遍历每一个框,计算它与其他框的 IoU ,如果大于特定的阈值,就丢弃对应的框(因为那俩很可能框的是同一个东西)
- 重复,直至所有框处理完成(被保留或丢弃)
对应 Python 代码如下:
import numpy as np
def nms(dets, thresh):
""" :dets 给定的候选框
:thresh 阈值
return 保留的框们
"""
# 获取dets的各种信息
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
scores = dets[:, 4]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
order = scores.argsort()[::-1]
keep = []
while order.size > 0:
i = order[0]
keep.append(i)
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
# 计算 IoU
ovr = inter / (areas[i] + areas[order[1:]] - inter)
# 保留 IoU 低于 thresh 的那些框
inds = np.where(ovr <= thresh)[0]
order = order[inds + 1]
return keep
训练
预训练
CNN 在 ILSVRC 2012 训练集上做了预训练,该数据集具有图像级别的标注(也就是没有候选框)
微调
为了使 CNN 适应于目标检测的新任务,作者使用缩放后的候选区域微调网络。这一过程中,网络的最后一层(分类输出层)从 1000 维更改为了 21 维 (20 种不同的目标 + 背景),其余层结构不变。作者将所有与人工标注的框的IoU大于 0.5 的区域认为是正类(也就是对应分类)、小于 0.3 的是背景(这俩数值是{0, 0.1, …, 0.5}以网格搜索的方式整出来的)。
梯度下降的初始学习率为 0.001 (预训练时的10%),每一轮采样 32 个正样本区域和 96 个背景区域组成 size 为 128 的 batch。鉴于相较于背景来说,正类较为稀少,因此采样时会偏向于正类。
Bounding Box Regression
作者使用由 D. Hoiem, Y. Chodpathumwan, and Q. Dai. Diagnosing error in object detectors. In ECCV. 2012.
提出的目标检测分析工具来探究此方法的错误模式,理解微调是怎么起作用的。一顿操作后,提出了 Bounding Box Regression
用于降低定位误差。通过使用从 Selective Search
选出的区域的 pool5pool_5 特征(CNN 的第五个卷积层后的最大值池化层) ,作者训练了个线性回归模型以预测一个新的候选区域。结果显示,这帮助修复了大量的错误定位,提升 mAP
3到4个百分点。
结果和问题
当时,这一模型在 PASCAL VOC 2012 数据集上得到了 30% 的提升(相较于之前的最好结果),效果可以说是斐然、
但是,R-CNN 也有很多问题:
- 慢。尽管在原论文里,作者一直在强调“我们这个方法很快”;但展示的数据放在今天看却慢的吓人:用(当时的)GPU 检测一张图片需要 13s,而 CPU 甚至达到了 50s+。这样的耗时不难理解:每张图要先用 Selective Search 提取 2000 个候选区域,每个候选区域都需要用 CNN 提取特征,并用 SVM 进行分类,这也是后面改进的重点。
- 大。由于后面的过程需要前面过程产生的特征,保存这些特征需要占用大量的存储空间。
- 图片变形。由于送入 CNN 时图片被强制缩放到 227*227,因此不免变形
正因为有这样的问题,R-CNN 后续有很多改进。下面继续介绍
Fast R-CNN
正如名称所言,Fast R-CNN 是对 R-CNN 的改进,结果不仅能使用较深的卷积神经网络(VGG16),训练上速度也快了后者仅 9 倍,测试上更是快了 200+ 倍,检测单图仅需 0.3s (不包括产生候选区域的时间);它在 VOC 2012 上的 mAP 也达到了 66% ( R-CNN 是 62% )。
不过,在正式介绍它之前,我们先看另一项 R-CNN 的改进:SPPnet
SPPnet
SPPnet,提出于Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
,通过共享部分计算加速了 R-CNN。简单来说,SPPnet 对整张图进行卷积、计算特征(而不是像 R-CNN 一个候选区域来一次),然后使用对应部分的特征对每个物体进行分类。通过最大池化,将候选框内的特征图转化为固定大小的输出(例如6×6)来提取对应候选框的特征。多输出尺寸被池化后连接成空间金字塔池。SPPnet 在测试时将 R-CNN 加速10到100倍。由于更快的候选框特征提取,训练时间也减少了 3 倍。
简而言之,SPP 能够实现 任意尺寸输入、固定尺寸输出(给全连接层)。SPPnet 基于此实现了对不同输入尺寸的适应性。
但 SPPnet 也有缺点,类似 R-CNN ,它也是多阶段流水线,包含提取特征、微调、训练 SVM 以及最后的 Box Regression,这些特征也得写入到磁盘。所以接下来回到主题,看看 Fast R-CNN 的改进
优点
总的来说,相对 R-CNN 和 SPPnet,它有这几个优点:
- 更高的 mAP
- 单阶段训练,使用了多任务损失(multi-task loss)
- 训练时会更新所有网络层
- 无需将特征存储于磁盘
结构
Fast R-CNN 仍然使用 Selective Search 产生候选区域,并将图片和这些候选区域作为输入。不同于对每个候选都做卷积,Fast R-CNN 对整张图片卷,并产生一个卷积特征图,然后对每个候选 RoI(Region of Interest,感兴趣区域)用 RoI 池化层产生定长的特征向量,丢入全连接层。最后会产生两个同级输出:第一个是分类结果,第二个是精修过的区域位置。
这里能看出比较有趣的另一点是,Fast R-CNN 将 R-CNN 最后的 Box Regression 也巧妙结合到了整个网络中。不过下面我们先看看另一个提到的东西: RoI 池化层
RoI 池化层
此层使用最大值池化,将任意感兴趣的有效区域转成小的、定长的特征图(长度 H*W,比如 7*7,H、W均为超参数)。本文里,RoI 使用一个四元组定义 (r,c,h,w)(r,c,h,w),分别对应左、上、高、宽
。
具体的操作时,RoI 池化层将 h*w 的 RoI 窗口划分为 H*W 的网格,然后将每个小格对应位置的值最大值池化、放入对应的网格内。对特征图的每个通道来说,这样的操作都是独立的。
其实这一层就是简化版的 SPP ,就是把金字塔池化缩到了一层。把不同尺寸的输入丢进去,最后都能得到固定维度的特征,能够丢给全连接层。
一个 h*w = 5*5 的输入经过 H*W = 2*2 后,结果示意如下
训练
初始化
本文尝试三个从 ImageNet 训练出来的模型,分别是 R-CNN 用的 CaffeNet(AlexNet 改进版)、VGG_CNN_M_1024 和 VGG16,从小到大分别称为S
、M
、L
。为了适应本文效果,模型做了如下三个变换:
- 最后的最大值池化层改为了 RoI 池化层,对每个模型固定了这一层输出的大小 H*W (比如 L模型就是 7*7)
- 最后的全连接层和 softmax 换成了上面描述的并行层
- 模型的输入被改成了两个部分:图片本身和相应的 RoI 区域
微调
对R-CNN 和 SPPnet 来说,当训练时,它们的某一批候选区域是随机挑的,比如 128 个候选区域可能来自 128 张不同的图片,但 Fast R-CNN 则是从 N 张图片里每张取 R/N 的候选区域出来,比如 N=2,R=128 两张图各取 64 个。更重要的是,由于同一张图的 RoI 可以共享计算,因此相较于之前的两个网络,它能大幅加快计算速度。
多任务损失
由于输出是两个并行的层,Fast R-CNN 的损失函数也就是二者之和。具体定义为
L(p,u,tu,v)=Lcls(p,u)+λ[u≥1]Lloc(tu,v)L(p, u, t^u , v) = L_{cls}(p, u) + λ[u ≥ 1]L_{loc}(t^u , v)
前半部分 Lcls(p,u)=−logpuL_{cls}(p, u) = – log p_u 即为预测类别(p)和真实类别(u)的对数损失;后半部分则为区域的损失。其中,λlambda为二者的平衡系数(在本文里均使用 1 ),[u ≥ 1]
则表示仅当 u
为真实类别时才计算,u = 0 (背景类)时不计算。最后的部分定义如下:
同 R-CNN 使用的 L2L_2 损失(x2x^2)不同,此处的损失更平滑。当 x 较大时,前者的梯度(2x2x)较大,容易导致梯度爆炸;而此处的式子会保持梯度恒小于等于 1。
Mini-batch 采样
如上面已经展示的那样,Fast R-CNN 用 2*64 个 RoI 组成 mini-batch,类似于 R-CNN ,里面包含 25% 的目标样本(IoU >= 0.5)和 75% 的背景样本(0.1 <= IoU < 0.5)。在训练时,每个图片有 0.5 的概率水平翻转。
其他训练时的一些细节,如超参数的选择等此处略去,感兴趣的可以参考原文。
检测
检测的基本过程已经在结构里概述过,此处不再赘述。说一句,在得到结果的分类框和各自的分数后,Fast R-CNN 也对使用了 NMS,对每个类别的重复框做了处理。
在做检测时,作者发现,有比较多的时间花在了全连接层上。而我们知道,全连接层其实就是在计算矩阵 WxWx。为了加速这一过程,作者用到了 SVD(奇异值分解)。
SVD
简单来说,对给定的任意形状矩阵 MM,都可以分解成下列形式
假定原始矩阵大小为 n*m,则分解出的三个矩阵大小分别如下
矩阵 ΣSigma 仅在对角线上有值,称为奇异值
,按重要程度从左上到右下排序。因此,我们可以仅保留前 kk 个奇异值,同时舍去U和VTU和V^T多余的行和列,就能起到压缩的效果。被保留的区域如下图所示:
压缩后的三个矩阵相乘,大小仍为 m*n,且信息基本保持不变(在k值适当时)。
最终到实现时,相当于把一个全连接层改为两个,第一个不含偏置,第二个才加上偏置。
一些结果
下表来自原文,分别展示了三者在训练和测试上的速度
可以看到,对于 L 模型,Fast R-CNN 在训练上比 R-CNN 快到了 8.8 倍,测试上则达到了 213 倍(加上 SVD 的情况);同时,它的 mAP 也高于 R-CNN。
除此之外,作者还做了不少的对比实验,检验了对微调层的选择、多任务训练是否有帮助、scale 的策略、训练数据增加是否有帮助、softmax 和 SVM 对比、更多的候选框是否有效等,感兴趣的同学可以阅读原文,此处不再赘述。
缺点
尽管 Fast R-CNN 有不少优点,但仍然存在一些缺陷。其中,由于它挑选候选框仍然使用 Selective Search 算法,这成了耗时的主要来源。后文的 Faster R-CNN 就针对此做了改进。
Faster R-CNN
此部分由我的好友 @Zee 撰写的 PPT 整理而来,由衷感谢他的支持。
对应文章:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
结构
Faster R-CNN 相较于 Fast R-CNN 的最大改进就是,它提出了 RPN 结构来代替 Selective Search 生成候选框,并且与目标检测的卷积层进行共享来缩短训练时间和测试时间,同时提高目标检测的精度。二者结构的对比如下所示:
观察上图,我们能发现,Faster R-CNN 使用 RPN 结构从特征图中产生候选区域,而其余部分均与 Fast R-CNN 类似。文章里作者使用了两种卷积网络:ZF
和 VGG16
,下图是使用 ZF
网络的详细结构图
所以接下来,咱们就来看看 RPN 是个什么东西?
RPN
对于特征图 𝐻×𝑊×𝑑,我们使用一个 n*n(文章中n=3
) 的滑动窗口, 对每个中心点生成个 𝑘 个 (原文为 3×3 共九个, 三种比例分别为 1:1, 1:2, 2:1
,三个尺寸分别为 128 , 256, 512
) anchors。产生的 anchors 示意如图:
之后对所有的 anchors 做 bounding box regression 回归,这样如果对应的 anchor 有对应目标,就能找到尺寸最匹配的框。
经过 3×3 卷积层后,每个滑动窗口被映射为一个维度为 d 的低纬特征向量 (对于 ZF 是 256, VGG16 则为 512 ) , 它被送入到两个并行的 1×1 的卷积层,分别生成 𝐻×𝑊×2𝑘 和 𝐻×𝑊×4𝑘 的输出。前者 H*W 代表 anchors 的组数,每组包含 k 个 anchor,相邻的两个数字分别代表预测为目标物体和背景的概率;后者其余类似,4 个数字代表最终框的宽高以及位置偏移的相关量。
最后,将两个输出和 reshape 信息一起结合,生成对应于原始图片尺寸的 proposal, 与 feature map 一起送入 RoI pooling 层。后续结构与 Fast RCNN 一致。
损失函数
类似于 Fast R-CNN ,Faster 的损失函数也由两部分组成:
- 分类损失是 log 损失, i 是每一个 minibatch 中每个 anchor 的索引
- 如果 anchor 为 positive,pi∗p_i^* 为 1, 否则为 0; pip_i 表示 anchor 为 positive 的概率
- 回归损失函数是 smooth L1L_1
- tit_i 是表示(𝑡𝑥, 𝑡𝑦, 𝑡𝑤, 𝑡ℎ)四个参数的预测向量,ti∗t_i^* 是表示 ground truth 对应的向量
- 最后使用 N𝑐𝑙𝑠N_{𝑐𝑙𝑠} 和 𝑁𝑟𝑒𝑔𝑁_{𝑟𝑒𝑔} 来进行标准化,原文中设置 N𝑐𝑙𝑠=256N_{𝑐𝑙𝑠}=256、 Nreg=2400N_{reg}=2400、 λ=10lambda =10; 代码中 N𝑐𝑙𝑠=256N_{𝑐𝑙𝑠}=256、 Nreg=128N_{reg}=128、 λ=1lambda =1。因为只有正 anchor 才会被计算回归损失, 而 mini-batch 一般是 128 个正样本和 128 个负样本
训练
在训练时,作者采用了四步训练法来实现 RPN 和 Faster R-CNN 的卷积层参数共享。具体步骤如下:
实验
文章做了大量的实验,以验证各因素对算法效果的影响。
缺点
当然,Faster R-CNN 也存在一些缺点,我们的归纳如下所示
- 卷积提取网络:无论是 VGGNet 还是 ResNet,其特征图仅仅是单层的,分辨率通常也较小,这些都不利于小物体及多尺度的物体检测,因此多层融合的特征图、增大特征图的分辨率等都是可以优化的方向。
- NMS:在 RPN 产生 Proposal 时,为了避免重叠的框,使用了 NMS,并以分类得分为筛选标准。但 NMS 本身的过滤对于遮挡物体不是特别友好,本身属于两个物体的 Proposal 有可能因为 NMS 而过滤为 1 个,造成漏检,因此改进优化 NMS 是可以带来检测性能提升的。
- RoI Pooling:Faster R-CNN 的原始 RoI Pooling 两次取整带来了精度的损失,因此后续 Mask RCNN 针对此 Pooling 进行了改进,提升了定位的精度。
- 全连接:原始 Faster R-CNN 最后使用全连接网络,这部分全连接网络占据了网络的大部分参数,并且 RoI Pooling 后每一个 RoI 都要经过一遍全连接网络,没有共享计算。
- 正负样本:在 RPN 及 RCNN 部分,都是通过超参数来限制正、负样本的数量,以保证正、负样本的均衡。而对于不同任务与数据,这种正、负样本均衡方法是否都是最有效的值得思考,且现实生活中得到均衡的正负样本有时难以实现。
- 两阶网络:Faster R-CNN 的 RPN 与 R-CNN 两个阶段分工明确,带来了精度的提升,但速度相对较慢,实际实现上还没有达到实时。因此,网络阶数也是一个值得思考的问题。
感谢阅读,如有帮助,欢迎不吝点赞。
本文仅发于掘金和个人平台,作者 FunnySaltyFish。