R-CNN 物体检测第二弹(Fast R-CNN)
今天,重看了 R-CNN 的后续改进 Fast R-CNN(Arxiv版)-本文中提到的paper,若未特别指明,说的就是此版本。
这里提一把辛酸泪。15年8月份到11月份,当时我参加了实验室和外面合作的一个项目。主要的工作就是在对方提供的航拍图像中,准确快速地检测出车辆等微小目标。大师兄作为该项目的实际负责人,他提出采用Fast R-CNN来进行检测,这也是我第一次听说R-CNN目标检测。在该项目中,我是负责coding的主代码手(就是拼接github上的Fast R-CNN代码),也参与目标bounding box 的annotation工作。因为当时我仅仅是将它作为一个练习 caffe 框架和 python 代码的上手技术,因此并未细看 R-CNN 系列 paper 中的检测流程细节和设计缘由。
时光荏苒,caffe 框架我早就不用了,python代码依旧bug多多,但是这几篇paper的魅力却依旧不减。由于我研一划水厉害,甚至没有正经修过一门机器学习课程。直到后来我看完了台大林轩田的机器学习课程,又看了UCL的RL教程,直到刷了几章deep learning book,又狂写了很多 TF,keras code。我才逐渐意识到,学习真的是一个循序渐进,螺旋上升的过程。那些往日里 paper 中在我看来就是理论堆砌的section,现在看来也是干货满满。比如 Fast R-CNN中2.3节描述 multi-loss的部分,我之前就以为是一个paper噱头,但今天看来,后续的实验说明,这个multi-loss 实现了两个任务的联合学习,并且使得两个任务互相提升。也许,这就是蒟蒻的成长吧。。。扯回来,在我继续学习 CNN-based deep learning以及其在视觉领域的其它应用时,才意识到R-CNN在基于深度学习的检测方法类中的开创性足以比肩AlexNet在基于深度学习的图像分类工作中的意义。而R-CNN连续3篇的逐步改进,更是体现了CNN model的巨大能量和作者的天才思想。
现在,我们就来看这一次改进是怎么加速R-CNN并提升检测性能的。
1. 缘起
1.1 R-CNN的几个不足
尽管 R-CNN 检测算法相对 DPM 等模型在检测性能指标上有了大幅度的提升,但是由于是开创性的工作,它还存在着一些不足,下面一一列出:
- region proposal的生成严重依赖 Selective Search 算法(简写为SS算法)。对 PASCAL VOC中的任意一张图片来说,SS算法得到所有 proposal (按score取前2000个的话)所需时间平均是 1.51 s(参见Faster R-CNN paper的Table 4的数据),这个消耗难以满足检测的实时性要求。
- 假设SS算法对每张图片会产生2000个proposal,对每一个proposal,R-CNN的=都需要首先将proposal对应的bbox从图中抠取出来,然后resize到标准大小,进行一次前传来得到深度特征。这就带来3个问题:
- 因为这里用到的CNN model都是需要用来做图像分类的,所以其深度都很高,即使有GPU加速,这每一次前传也相对耗时。更何况需要对每个proposal都来一次前传,这可是一个串行的过程,因此叠加起来的耗时十分巨大。
- 这里得到的2000个proposal都是在一张图片中的,所以存在大量的overlap,也就是说,得到的2000个深度特征也是存在大量overlap(即信息冗余)。然而冗余数据天生就应该被消灭的…
- 正是由于这大量的冗余数据,在做mini-batch训练时,我每读取一张图片得到的深度特征,都是内存不可承受之重。小PC断然是无法一次性存下如此多的深度特征的(本实验室server一年内存仅为32G…),只能选择将特征cache到硬盘中。
- 虽然R-CNN中的补充实验已经说明 基于hard-negative mining的SVM得到的 mAP,比softmax要高。但是将SVM和detection network的训练隔开,那么用于分类的SVM和提取特征的CNN model并不能完全对应。更好的方式当然是要考虑将提取特征和分类放在一起进行联合训练。
1.2 Fast R-CNN的主要解决手段:
针对 R-CNN检测算法的存在的上述问题,Fast R-CNN主要从以下几方面着手进行改进:
- 对 region proposal 生成算法保留,暂时不考虑改进
- 既然提取一张图片中的2000个proposal的深度特征的过程存在信息冗余,那么对于一张图片,将全图送入CNN model,只进行一次前传操作,然后得到中间某个conv layer的feature map作为整张图片的feature。接下来,每个proposal对应的特征就从这个feature map按照比例进行截取,然后通过pool操作统一转化为固定维度的特征。然后依次将每个proposal的深度特征再送入全连接层进行分类。此外,因为在同一张图上同时获得2000个proposal的深度特诊,因此对训练过程和采样策略(paper 2.3节的”sampled hierarchically”)进行了改进。
- 为了提升CNN model中的softmax的分类效果,采用多任务学习(multi-task learning)的方式来对分类网络和bbox regression进行学习。通过联合学习,提高了softmax分类的准确率和bbox regression的精度
2. 主要检测流程
Fast R-CNN的检测流程主要包含以下几步:
2.1 region proposal generation
直接采用 Selective Search 算法来提取每一张图中的所有可能的 proposal,大概2000张(取object-ness score前2000高的)
2.2 detection network
这里转译一下paper的第2节开头的简介。
一个Fast R-CNN Network 以单张全图和一系列object proposal(上面的2000个)为输入。网络首先采用多层的卷积和pooling层来处理全图以得到 conv feature map;其次,对每个proposal,通过ROI pooling layer来从 feature map 中提取固定长度的vector作为该proposal的特征表示;接下来,将每个proposal的特征送入序贯链接的全连接层,全连接层的末尾有两个输出:一个是用于判断proposal类别的softmax output,一个是用于做bbox regression的输出。
注意,假设目标类别有 K 类,那么softmax 的输出有 K+1 个unit(包括 background 类别),而bbox regression的输出有 4*K 个unit(对每个类都做一下bbox regression)
2.2.1 CNN feature extraction for each proposal
这里详述如何对每张图,只经过一次前传来获得所有proposal的深度特征。
全卷积网络(fully-convolutional network)
只包含了 卷积层 和 pooling 层。这种网络的好处是,对不同size的输入,都可以得到对应不同size的输出。全图经过了卷积层和pooling层后,得到conv feature map。
ROI Pooling Layer
ROI 是指 region of interest,每个 proposal 在conv feature map 中都有对应位置和长宽的 ROI,假设该ROI的位置和长宽参数为: (r,c,h,w),r 和 c 代表了ROI的左上角在整个conv feature map中所占的的row和column数,而 h 和 w 则代表了 ROI 在conv feature map 所占的行数和列数。
理论上来讲,通过proposal在全图中的位置信息,就能得到其在 conv feature map 中的 ROI 信息,接下来就能直接截取出ROI对应区块的深度 feature,那为什么要做 ROI pooling呢?这主要是因为detection network后面是对输入大小有严格规定的 全连接层,而大小不一的proposal产生的深度特征也是大小不一,自然不满足后面的输入要求,因此本文根据 SPP-Net 的启发,提出了 ROI Pooling Layer。
具体地,对 (r,c,h,w)的ROI,需要获得统一的 HxW 的conv feature特征。那么,
ROI max pooling 将 (h, w) 的 ROI window转化为 (H, W)的grid,grid中每个sub-window的size是 (h/H, w/W),那么对每个sub-window中的数值进行 max pooling。这样得到的结果就是 (H, W)的feature map。同样地,对conv feature map的每个channel 都执行这样的max pooling操作。
由此,每个 proposal 得到了 统一大小的深度特征,经过 flatten 操作即可送入 后续的全连接层。
2.2.2 Softmax classification and bbox regression
全连接层的作用是对得到的conv feature进行逐级抽象,以达到能够进行分类的抽象程度。在全连接层的末端加入了两个输入:softmax 输出和 bbox regression 输出。假设目标种类为 K 类
softmax 输出
根据前述,softmax 的输出有 K+1 个unit(包括 background 类别)。softmax 实际上就是在全连接层末端基础上再加一层全连接,再并上 softmax 概率输出。
这里的分类 loss 是:paper中说是log-loss,实际上就是交叉熵损失(cross-entropy loss)
bbox regression 输出
根据前述,bbox regression的输出有 4*K 个unit(对每个类都做一下bbox regression)。每个proposal都对应了一个目标的x,y,w,h 位置信息,bbox regression实际上就是在全连接层末端基础上再加上一层用作坐标回归的线性层(实际上也是全连接),来对proposal的位置信息进行修正,得到新的 x,y,w,h。详细的在 R-CNN 的7.3节中有详细的描述。这里的变化由 R-CNN 中的proposal 的x,y,w,h输入变为这里的全连接层末端向量输入。
R-CNN中的 loss 就是岭回归中的损失,这里的回归loss是 paper 中2.3节定义的 loc loss,下面给出loc loss中用到的 smooth-L1损失,这样设计的原因是:当差异比较小时,梯度也比较小,即只需要进行微小的调整即可;当差异比较大时,不会产生过大的梯度,而是产生范数为1的梯度,不会发生梯度爆炸。
$smooth_{L_1}=0.5x^2, if |x|<1$
$smooth_{L_1}=|x| – 0.5, if |x| >= 1$
这里将 softmax 分类 和 bbox regression 中的损失联合起来进行优化,以同时实现分类和位置回归。
检测时,对每个proposal,先通过softmax判断其类别,然后再根据其类别去提取由bbox regression 得到的属于该类别的位置信息。据此更新proposal的位置信息后,执行NMS(Non-maximum suppression)来去除冗余 bbox
2.2.3 Truncated SVD for faster detection
简言之,就是将原有的不包含非线性激活函数的全连接层转换为低秩矩阵相乘,因为大矩阵相乘在相应的计算库支持,因此可以获得更快的检测速度。
3. 主要训练过程:
因为detection network现在将proposal的特征提取工作放在一次前传中完成,并且存在两项输出,自然训练过程也存在一些变化。
3.1 Mini-batch sampling:
3.1.1 R-CNN 中的 mini-batch
假设构造mini-batch size为R,那么随机选择 R/4 的 类别样本,R*3/4的背景样本。这些样本可能来自很多张图片,但在这里,为了获得样本的深度特征,需要做的前传次数是 R 次。
3.1.2 Fast R-CNN 中的 mini-batch:
因为现在一次前传可以获得一张图片内所有 proposal 的深度特征,因此希望利用这个特性来加速训练过程。通过
Hierarchical sampling
Sampling N images,then samping R/N ROIs from each image
例如,对R=128,N=2,那么原有方式做128次前传,现在只做2次前传。实现了64倍的加速。
注意,这里的背景样本定义和 R-CNN中略有不同,详细参看paper的第2.3节
3.2 Multi-loss
现在只考虑 单个 proposal,softmax的输出向量是p,真实类别是 u,通过bbox regression的预测到的位置信息为$v=(v_x,v_y,v_w,v_h)$,而与proposal IOU最大的ground-truth bbox位置信息(即回归目标)为$tu=(tu_x,tu_y,tu_w,t^u_h)$
$p_u$ 代表向量p的第u个unit,代表softmax预测的proposal属于第u类的概率,$t^u$代表bbox regression预测的proposal如果是第u类时,对应的位置信息。
3.2.1 classification loss
前述的 softmax 分类损失:$L_{cls}(p, u) = -log(p_u)$
3.2.2 localization loss
前述的bbox regression损失:$L_{loc}(t^u, v)=\sum_{i\in{x,y,w,h}}smooth_{L_1}(t_i^u-v_i)$
通过下式来结合上述loss:$L(p,u,t^u,v)=L_{cls}(p, u) + \lambda[u\geq1]L_{loc}(t^u, v)$
3.2.3 multi-loss 联合优化的优势
通过paper 5.1节和 Table 6. 的实验结果显示,和R-CNN中的检测结果对比显示,采用本文的 multi-loss 联合优化,mAP比 R-CNN中的 分类(CNN model提特征+SVM分类)与bbox regression分开的mAP要搞几个百分点。此外,假设检测时不采用bbox regression,而训练时采用multi-loss训练CNN model 与 只采用 softmax-loss训练 CNN model,mAP也要高1个百分点。这说明,联合训练有益于proposal的分类,且这个提高主要来自分类精度的提升。
为什么这里联合训练后,mAP反而比R-CNN中的SVM分类得到的mAP还高呢?还记得上文提到的为什么采用SVM而非Softmax吗?在R-CNN中,之所以不采用softmax,是因为对网络进行训练时,训练的类别样本都是对grounding-truth bbox的微小移动获得的,因此损害了类别样本的质量。试想,在这里采用联合优化的话,若某训练的类别样本和gt bbox的IOU很大(99%),则bbox regression带来的loss会很小,则网络会专注于去优化分类效果;如果某训练的类别样本和 gt bbox的IOU 不大(51%),则bbox regression带来的loss 会比之前大,则网络用于优化分类效果的精力会被分散到优化定位效果上。此外,网络会学到:当proposal和真正的bbox有偏移时,网络会努力去纠正这个偏移,并努力去采用proposal中的和目标类别相关的部分的特征来进行分类。
补充一点认识。R-CNN 中的bbox regression是针对每一类目标训练一次,但每类目标中可能存在多种size和aspect-ratio的gt bbox,因此训练出来的预测能力可能不太好。但是在这里,bbox regression是以每个proposal的深度特征为输入来进行训练,相当于在训练时就引入了物体的特征信息。因此训练出的预测能力对于具体的每个proposal,应该更适配的。
3.3 ROI Pooling Layer的梯度反传
参照一般的pooling layer的梯度反向传播即可
4. 实验分析
4.1 fine-tune which layer?
paper的4.5节给出实验结果:如果采用imagenet上的pretrained weights,只训练全连接层,则mAP下降厉害。但是也不用训练全部的 conv layers。VGG16训练 conv3_1 层及其后的层即可,mAP下降不明显。
4.2 是否需要更多训练数据?
paper的5.3节给出实验结果:相比于DPM在1k张图训练集上,性能就达到饱和无法提升。Fast R-CNN 可以通过提升训练集大小,来提升检测性能,这也是CNN model的优势。但这里的训练集从VOC10到VOC12,同一份测试集上的mAP提高为2.7%左右。
4.3 proposal 更多就更好吗?
paper的5.5节给出实验结果图:当SS算法给出的proposal数量逐渐增多,且得到的proposal同时用于训练和测试,整体的mAP略有下降,这主要是由于object-ness score较低的proposal在训练阶段“污染”了训练集。由此,实验进一步测试,当采用密集采样(类似sliding window的dense sampling)(同时用于训练和测试)时,性能进一步下降。这还是由于dense box对训练集带来的污染。
我个人认为可能还有另一个原因,训练集中的object数量固定,随着proposal个数的增加,类别样本增加的数量有限,而背景样本增加的数量很多,这种类别不平衡问题给训练带来的影响也很大。之前做过的项目中,由于需要检测汽车类别仅有3类,因此最开始的训练检测效果很差,初步分析是类别不平衡的问题。调整类别比例(汽车之间的比例与汽车和背景之间的比例)后,效果并未提升。后来推测是由于背景主要是草原,但也包含了少量人,则背景样本中的差异也很大。于是我们后来又单独抠取了人样本,并作为检测目标的一类。经此操作,不仅汽车被错判为背景的情况大幅减少,就连对人的检测效果也十分显著(人和汽车以及人和草原背景间的差异较大)。
此外,在测试时,过多的 proposal可能会干扰NMS过程,从而影响mAP。