0. 目标检测网络分类
- One-stage,如SSD、YOLO
- Two-stage,如Faster R-CNN
0.2 One-stage(以SSD、YOLO为例)
检测过程:
- 基于anchors直接进行分类以及调整边界框
0.3. Two-stage(以Faster R-CNN为例)
检测过程:
- 通过专门模块生成候选框(Region Proposal Network,RPN)去寻找前景和调整边界框(基于anchors)
- 基于之前生成的候选框进行进一步分类以及调整边界框(基于proposals)
前景:需要检测的目标均为前景,不需要检测的均为背景
0.4 两种网络对比
网络类型 | 代表网络 | 工作原理 | 优点 |
One-stage | SSD、YOLO | 基于anchors直接进行分类以及调整边界框 | 检测速度快 |
Two-stage | Faster R-CNN | 1. 通过专门模块生成候选框(Region Proposal Network,RPN)去寻找前景和调整边界框(基于anchors);2. 基于之前生成的候选框进行进一步分类以及调整边界框(基于proposals) | 检测准确率高 |
具体使用哪种类型的网络需看实际任务需求。
PS:Faster R-CNN是一个经典的网络,虽然是Two-stage网络,但对One-stage网络的学习有帮助。
1. R-CNN(Region with CNN feature)理论部分
1.1 引言
题目名称:Rich feature hierarchies for accurate object detection and semantic segmentation
论文地址:https://arxiv.org/pdf/1311.2524.pdf
提出时间:2014年
R-CNN可以说是利用深度学习进行目标检测的开山之作,作者Ross Girshick多次在PASCAL VOC的目标检测竞赛中夺冠,曾在2010年带领团队获得终身成就奖。
1.2 R-CNN算法流程
- 一张图片使用Selective Search方法生成 ~
- 对每个候选区域使用CNN提取特征
- 特征送入每一类的SVM分类器中,判别是否属于该类
- 使用回归其精细修正候选框位置
1.2.1 [第一步] 候选框区域的生成
原理:利用SS(Selective Search)算法和图像分割的方法得到一些原始区域,然后使用一些合并策略将这些区域合并,得到一个层次化的区域结构,而这些结构就包含着可能需要的物体。
比如下面这张图片,我们可以得到不同的候选框。
1.2.2 [第二步] 对每个候选区域使用CNN提取特征
将2000个候选框缩放到227×227像素,接着将候选框区域输入事先训练好的AlexNet网络,获取4096维的特征,即得到2000×4096维矩阵。
CNN将负责分类的FC去掉了,所以可以得到右边4096维的特征向量。
1.2.3 [第三步] 将特征向量送入每一类的SVM分类器,判断是否属于该类别
将第二步获得的特征向量与20(分类个数)个SVM组成权值矩阵 相乘,得到每个候选框是某个目标类别的得分矩阵。分别对得分矩阵中每一列(即每一类)进行非极大值抑制(Non Maximum Suppression,NMS),剔除重叠的候选框,得到该列(该类别)中得分最高的一些候选框。
1.2.3.1 得到候选框与类别得分的矩阵
SVM是一个二分类的分类器,所以多类别需要训练相同个数的分类器。
这里分类数为20是因为使用的数据集是PASCAL VOC
- 2000:2000个候选框
- 20:PASCAL VOC的类别数
最右边的矩阵每一行代表一个候选框,列(20列)为该候选框对每一个类别的分数(共有20个)
1.2.3.2 NMS剔除重叠的候选框
- 先针对每一个类别,找到得分(概率)最高的候选框 A
- 计算其他候选框B与A的IoU
- 如果IoU大于设定的阈值,则删除B
- 执行2 -> 删除某一类别所有IoU大于阈值的候选框
- 执行1 -> 遍历完所有的类别
IoU:两个目标框的交并比。
最后得到的是,一个类别只有一个最完美的候选框
其实边界框、候选框、建议框都是一个东西,所以这里统一称为候选框
1.2.4 [第四步] 使用回归器修正候选框位置
对NMS处理后剩余的候选框进一步筛选和剔除后,分别用20个回归器对上述20个类别中剩余的候选框进行回归操作,最终得到每个类别修正后得分最高的Bounding Box。
如图,黄色框P表示候选框Region Proposal,绿色G表示GT,红色框 表示Region Proposal进行回归后的预测窗口,这是一个可以用最小二乘法解决的线性回归问题。
Note: 在回归过程中, 依然使用CNN的输出特征向量进行预测。
1.3 R-CNN算法存在的问题
- 测试速度慢
测试一张图片约53s(CPU)
- 用Selective Search算法提取候选框用时越2s
- 一张图像内候选框之间存在大量重叠,导致提取特征操作冗余。
- 训练速度慢
训练过程极其繁琐 - 训练所需空间大
训练SVM和BBox回归需要从每个图片中的每个目标候选框提取特征并写入磁盘。对于非常深的网络,如VGG-16, 从VOC 2007训练集上的5k图片上提取的特征需要数百GB的存储空间。
1.4 解释R-CNN为什么是two-stage
- Region proposal (通过SS算法)
- 四个部分:
- Feature extraction(CNN)
- Classification(SVM)
- BBox regression(Regression)
2. Fast R-CNN理论部分
2.1 引言
题目名称:Fast R-CNN
论文地址:https://arxiv.org/pdf/1504.08083.pdf
代码链接:https://github.com/rbgirshick/fast-rcnn
提出时间:2015年
Fast R-CNN是R-CNN的升级版,同样使用VGG-16作为网络的backbone。与R-CNN相比,Faster R-CNN训练时间快9倍,推理时间快213倍,准确率从62%提升至66%(PASCAL VOC数据集)。
2.2 Fast R-CNN算法流程
- 一张图片使用Selective Search方法生成 ~
- 将图片输入CNN得到对应的特征图,将SS算法生成的候选框投影到特征图上获得对应的特征矩阵
- 将每个矩阵通过ROI Pooling层缩放为 7×7 大小的特征图,接着将特征图展平(flatten)并通过一系列FC得到预测结果
ROI(Region of Interest,感兴趣区域)
2.3 Fast R-CNN 与 R-CNN的不同之处
- 第一步是一样的
- 第二步,R-CNN是将每一个候选框都输入CNN中得到每一个候选框的特征向量;而Fast R-CNN是将输入图片送入CNN,得到一个特征图A,再将不同的候选框映射到特征图A中,得到针对这个候选框的特征矩阵。
- 第三步也不同,R-CNN专门训练了SVM分类器用于对每一个候选框进行分类,又专门训练了回归器对候选框进行调整;而Fast R-CNN将二者结合在了一个网络中(并联而非串连),不需要单独训练分类器和回归器。
2.4 [第二步] Fast R-CNN如何生成候选框特征矩阵
在R-CNN中,通过SS算法得到2000个候选框,则需要进行2000次正向传播得到2000个特征 —— 很冗余 ——很多重叠部分计算计算一次就可以。
在Fast R-CNN中,直接将整张图片送入CNN得到这张图片的特征图,再根据候选框与原图的关系映射到特征图上,就不需要重复运算了。——大幅度提升Fast R-CNN的运算速度
2.5 关于正负样本的解释
在Fast R-CNN网络训练过程中,并不会使用SS算法提供的所有候选框(SS算法生成大约2000个候选框),只需使用一小部分的数据即可。对于采样数据,它分为“正样本”和“负样本”。
- 正样本:候选框中确实存在所需检测目标(前景)的样本
- 负样本:候选框中没有所需检测目标(背景)的样本
为什么要将样本分为正样本和负样本呢?
假如我们要训练一个猫狗分类器,如果猫的样本数量远大于狗的样本数量(数据不平衡),网络在预测时会更偏向于“猫”,很明显这样是不对的。如果数据中全是“猫”的样本, 没有“狗”的样本,那么网络预测几乎一定会出现问题。
同理,在训练Fast R-CNN时,如果数据中全部都是正样本,那么网络就会很大概率认为候选区域是所需要检测的目标(可能这个框明明框住的是背景,但网络仍会认为这个被框住的背景是有用的,是一个前景),这时网络肯定会出问题。所以数据要分为正样本和负样本。
在原论文中,对于每一张图片,从2000个候选框中采集64个候选框。这64个候选框,一部分框的是正样本,一部分框的是负样本。那么正样本是如何定义的呢?
只要候选框与真实框(GT)的IoU大于0.5,则认定为正样本,反之认定为负样本。
2.6 [第二步] 将用于训练样本的候选框通过ROI Pooling层映射到特征图上
原理:
左边图其实是一个经过特征提取的特征图,本身可视化出来也是很抽象的,这里只是为了方便理解,使用了RGB图像。
具体实现为:将特征图划分为 7×7 个小块,对其每一小块执行MaxPooling
这样处理对输入特征图的尺寸没有要求了,无论怎样都可以缩放到7×7 -> 在R-CNN中,输入图像被限定为227×227,而在Fast R-CNN中,输入图像尺寸不再被限制。
这里忽略了Channel维度,和最大池化一样,有几个通道就做几次,最后concat就可以了。
2.7 Fast R-CNN网络架构
2.7.1 分类器
2.7.2 边界框回归器
- :用来调整候选框中心坐标的回归参数
- :用来调整候选框宽度和高度的回归参数
2.8 Fast R-CNN的损失函数
2.8.1 分类损失
其中为分类损失,是Softmax交叉熵损失。
- sotfmax交叉熵损失 -> 多分类 -> PyTorch代码为
nn.CrossEntropyLoss
- sigmoid交叉熵损失 -> 二分类 -> PyTorch代码为
nn.BCELoss
BCELoss: Binary Cross Entropy Loss
其中代表分类器预测当前候选区域为类别的概率。
Note:对于softmax的交叉熵损失来说,如果采用one-hot编码(标签),那么结果只计算真实类别概率的损失。
即:。和Fast R-CNN的分类损失是一样的。
2.8.2 回归损失
其中为定位损失。如果我们将看成是一个函数,那么该回归损失可以写为:
即回归损失由四部分组成,分别针对 的损失。
是一个平衡系数,用于平衡分类损失和回归损失(此消彼长,很好理解)。
艾佛森括号:“在数学中,以Kenneth E. Iverson命名的“艾佛森括号”,是一种用方括号记号,如果方括号内的条件满足则为1,不满足则为0。”
即对于 ,当时里面的数为1,当里面的数为0。
那么如何理解这个艾佛森括号呢?
- 当候选框里面的目标确实是正样本,才会进行回归
- 否则(负样本的情况下),不进行候选框回归。
2.8.3 回归损失函数:L1 loss, L2 loss以及Smooth L1 Loss的对比
详细的损失函数解释可以看:
2.8.3.1 均方误差MSE(Mean Square Error, MSE)—— 损失
均方误差是模型预测值 与真实样本值 之间差值平方的均值,其公式如下:
其中,和分别表示第个样本的真实值及其对应的预测值,为样本的个数。
忽略下标 ,设,以为横轴,MSE的值为纵轴,得到函数的图形如下:
MSE的函数曲线光滑、连续,处处可导,便于使用梯度下降算法,是一种常用的损失函数。而且,随着误差的减小,梯度也在减小,这有利于收敛,即使使用固定的学习速率,也能较快的收敛到最小值。
当和也就是真实值和预测值的差值大于时,会放大误差;而当差值小于时,则会缩小误差,这是平方运算决定的。
- MSE对于较大的误差(>1)给予较大的惩罚,较小的误差(<1)给予较小的惩罚。也就是说,对离群点比较敏感,受其影响较大。
- 如果样本中存在离群点,MSE会给离群点更高的权重,这就会牺牲其他正常点数据的预测效果,最终降低整体的模型性能。 如下图:
可见,使用 MSE 损失函数,受离群点的影响较大,虽然样本中只有 5 个离群点,但是拟合的直线还是比较偏向于离群点。
2.8.3.2 均绝对误差(Mean Absolute Error, MAE) —— 损失
均绝对误差是指模型预测值和真实值之间距离的均值,其公式如下:
忽略下标 ,设,以为横轴,MAE的值为纵轴,得到函数图形如下:
MAE曲线连续,但在处不可导。而且 MAE 大部分情况下梯度都是相等的,这意味着即使对于小的损失值,其梯度也是大的。这不利于函数的收敛和模型的学习。但是,无论对于什么样的输入值,都有着稳定的梯度,不会导致梯度爆炸问题,具有较为稳健性的解。
相比于MSE,MAE有个优点就是,对于离群点不那么敏感。因为MAE计算的是误差的绝对值,对于任意大小的差值,其惩罚都是固定的。
针对上面带有离群点的数据,MAE的效果要好于MSE。
2.8.3.3 MSE和MAE的选择
- 从梯度的求解以及收敛上,MSE是由于MAE的。
- MSE处处可导,而且梯度值也是动态变化的,能够快速的收敛;而MAE在0点处不可导,且其梯度保持不变。
- 对于很小的损失值其梯度也很大,在深度学习中,就需要使用变化的学习率,在损失值很小时降低学习率。
- 对离群(异常)值得处理上,MAE要明显好于MSE。
如果离群点(异常值)需要被检测出来,则可以选择MSE作为损失函数;如果离群点只是当做受损的数据处理,则可以选择MAE作为损失函数。
总之,MAE作为损失函数更稳定,并且对离群值不敏感,但是其导数不连续,求解效率低。另外,在深度学习中,收敛较慢。MSE导数求解速度高,但是其对离群值敏感,不过可以将离群值的导数设为0(导数值大于某个阈值)来避免这种情况。
在某些情况下,上述两种损失函数都不能满足需求。例如,若数据中90%的样本对应的目标值为150,剩下10%在0到30之间。那么使用MAE作为损失函数的模型可能会忽视10%的异常点,而对所有样本的预测值都为150。这是因为模型会按中位数来预测。而使用MSE的模型则会给出很多介于0到30的预测值,因为模型会向异常点偏移。
这种情况下,MSE和MAE都是不可取的,简单的办法是对目标变量进行变换,或者使用别的损失函数,例如:Huber,Log-Cosh以及分位数损失等。
2.8.3.4 Smooth L1 Loss
在Faster R-CNN以及SSD中对边框的回归使用的损失函数都是Smooth L1 作为损失函数,
其中,
Smooth L1 能从两个方面限制梯度:
- 当预测框与 ground truth 差别过大时,梯度值不至于过大;
- 当预测框与 ground truth 差别很小时,梯度值足够小。
2.8.3.5 Smooth L1 Loss 对比L1 Loss 和 L2 Loss
其中为预测框与groud truth之间的差异:
上面损失函数对的导数为:
上面导数可以看出:
- 根据MSE的导函数来说,当增大时,L2的损失也增大。 这就导致在训练初期,预测值与 groud truth 差异过于大时,损失函数对预测值的梯度十分大,训练不稳定。
- 根据MAE的导函数来说,L1对的导数为常数,在训练的后期,预测值与ground truth差异很小时,L1的导数的绝对值仍然为,而 learning rate 如果不变,损失函数将在稳定值附波动,难以继续收敛以达到更高精度。
- 根据Smooth L1的导函数来说,在较小时,对的梯度也会变小。 而当较大时,对的梯度的上限为1,也不会太大以至于破坏网络参数。SmoothL1完美的避开了L1和L2作为损失函数的缺陷。
三者放在一起的函数曲线对比:
从上面可以看出,该函数实际上就是一个分段函数,在之间实际上就是L2损失,这样解决了L1的不光滑问题,在]区间外,实际上就是L1损失,这样就解决了离群点梯度爆炸的问题
2.8.3.6 三种回归损失函数总结
对于大多数CNN网络,我们一般是使用L2-loss而不是L1-loss,因为L2-loss的收敛速度要比L1-loss要快得多。
对于边框预测回归问题,通常也可以选择L2损失,但L2范数的缺点是当存在离群点(outliers)的时候,这些点会占loss的主要组成部分。比如说真实值为1,预测10次,有一次预测值为1000,其余次的预测值为1左右,显然loss值主要由1000决定。所以FastRCNN采用稍微缓和一点绝对损失函数(smooth L1损失),它是随着误差线性增长,而不是平方增长。
Smooth L1 和 L1 Loss 函数的区别在于,L1 Loss 在0点处导数不唯一,可能影响收敛。Smooth L1的解决办法是在 0 点附近使用平方函数使得它更加平滑。
Smooth L1的优点:
- 相比于L1损失函数,可以收敛得更快。
- 比于L2损失函数,对离群点、异常值不敏感,梯度变化相对更小,训练时不容易跑飞。
2.9 解释Fast R-CNN为什么是two-stage
- Region proposal (通过SS算法)
- 四个部分(均通过CNN实现):
- Feature extraction
- Classification
- BBox regression
2.10 Fast R-CNN速度问题
虽然Fast R-CNN比R-CNN快乐213倍,但仍然不快。通过对特征提取的改进,虽然变快了,但是SS算法获取候选框是没有改进的,仍然需要2s的时间(后面CNN实现部分只需要几毫秒),所以SS算法获取候选框成为了Fast R-CNN的速度瓶颈。
3. Faster R-CNN
3.1 引言
论文题目:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
论文链接:https://arxiv.org/abs/1506.01497
提出时间:2015年
Faster R-CNN是Fast R-CNN的升级版,同样使用VGG-16作为网络的backbone。推理速度在GPU上达到5fps(包括候选框的生成),准确率也有进一步的提升。在2015年的ILSVRC以及COCO竞赛中获得多个项目的第一名。
这么快是因为Faster R-CNN使用RPN(Region Proposal Network)解决了候选框生成慢的问题。
3.2 Faster R-CNN算法流程
- 将图像输入网络得到相应的特征图
- 使用RPN结构生成候选框并投影到特征图上获得相应的特征矩阵
- 将每个特征矩阵通过ROI Pooling层缩放到7×7大小的特征图,接着将特征图展平通过一系列FC层得到预测结果。
本质上是:RPN + Fast R-CNN
3.3 RPN网络结构
首先对输入图片进入特征提取得到的特征图上使用一个滑动窗口,每滑动到一个位置,生成一个一维向量。再对这个一维向量送入两个FC,输出两个值:①目标概率 scores和②边界框回归参数 coordinates。其中是针对个anchor box而言,即针对每一个anchor生成两个概率,一个是背景(负样本)的概率,一个是前景(正样本)的概率 —— 个anchor就会生成 个scores。同样的,针对每一个anchor也会生成4个候选框回归参数,所以是
个anchor的形状是固定的(长宽比例是固定的)
3.3.1 RPN生成6个值的例子
需要注意的是:
- 每一个anchor是会生成两个概率:一个是背景(负样本)的概率,一个是前景(正样本)的概率,这并不是某一个分类的概率,而是该目标是前后背景(正负样本)的概率!
- 每个anchor生成的4个回归参数也是为了将其移动到最佳的位置。
- 给出个anchor的目的是为了检测不同大小和长宽比的物体
3.3.2
即在每个滑动窗口都会生成 9 个anchor,此时会有:
- 2×9=18个正负样本分数
- 4×9=36个候选框回归参数
思考一个问题:ZF和VGG的感受野分别为171和228,那为什么可以识别256×256和512×512像素的目标呢?
作者认为通过一个小的感受野去预测一个比它感受野大的目标候选框是有可能的 —— 看到物体的一部分也是有可能猜出目标完整的位置区域(这是作者给出的看法)。在实际使用中,用小感受野去预测大的候选框也是有效的。
3.3.3 计算Faster R-CNN以ZFNet为backbone,特征图3×3滑动窗口在原图中感受野的大小
这里的滑动窗口实现使用3×3卷积实现的(stride-1, padding=1),卷积过后得到与输入shape相同的特征图,之后再并联两个1×1卷积获得 scores 和
3.4 损失
3.4.1 RPN损失
其中,为平衡参数,默认为10,所以和是差不多大的。所以这个式子还可以进一步化简(在代码部分,使用代替)。
3.4.1.1 分类损失
是以e为底的。
在PyTorch官方实现的代码中,分类损失使用的二分类交叉熵损失。
3.4.1.2 边界框回归损失
3.4.2 Fast R-CNN损失
3.4.2.1 分类损失
3.4.2.2 边界框回归损失
3.5 Faster R-CNN训练
现在普遍的方法:直接采用RPN Loss + Fast R-CNN Loss的联合训练方法
原论文中采用分别训练RPN以及Fast R-CNN的方法(分布训练的方法):
- 利用ImageNet预训练分类模型初始化前置卷积网络层参数(初始化backbone网络参数),并开始单独训练RPN网络参数(迁移学习的方法训练RPN网络);
- 固定RPN网络独有的卷积层以及FC层参数,再利用ImageNet预训练分类模型初始化前置卷积网络参数,并利用RPN网络生成的目标建议框是训练Fast R-CNN网络参数(再次初始化backbone并固定住RPN,之后训练Fast R-CNN);
- 固定利用Fast R-CNN训练好的前置卷积网络层参数,微调RPN网络独有的卷积层以及FC层参数(固定backbone,再次训练RPN);
- 同样保持固定前置卷积网络层参数,去微调Fast R-CNN网络的全连接层参数(固定住前面的,单独训练FC层)。
- 最后RPN网络与Fast R-CNN网络共享前置卷积网络层参数,构成一个统一的网络。
3.6 解释Faster R-CNN为什么是one-stage(end2end)
以下四个部分全部由CNN完成,所以是单阶段端到端网络而非双阶段网络
- Region proposal
- Feature extraction
- Classification
- Bounding box regression
R-CNN和Fast R-CNN之所以是双阶段网络,是因为使用了SS算法生成候选框,而Faster R-CNN使用RPN网络代替了这个部分,所以是单阶段网络
4. R-CNN、Fast R-CNN、Faster R-CNN流程对比
框架越来越间接,检测效果也越来越好。