当前位置: 首页 > article >正文

MMDetection学习系列(4)——Cascade R-CNN深度探索与实战指南

目录

引言

背景

模型介绍

Faster R-CNN

Iterative BBox

Integral Loss

Cascade R-CNN

Cascaded BBox Regression

Cascaded Detection

实验结果

Coovally AI模型训练与应用平台 

总结


引言

Cascade R-CNN作为目前主流常用的高性能目标检测算法中最广为人知的算法之一。它基于经典的Faster R-CNN架构,通过引入级联式的多阶段检测器来逐层提升检测精度,从而显著提高了模型在困难样本上的表现。

  • 参考论文:https://arxiv.org/pdf/1906.09756


背景

在Faster R-CNN算法中,RPN输出指定数量的RoI候选框,然后输入到R-CNN层进行分类和回归,一般R-CNN部分是设置IoU=0.5来进行正负样本划分。

图片

直观上训练时设置IoU越大,检测的bbox越少,但是普遍质量更好,也就是说 IoU如果设置的比较小,那么在训练过程中可能会带来很多噪声,不利于训练,但是如果IoU太高,会导致正样本太少出现过拟合,结合如下曲线可以进一步验证。

图片

针对不同IoU阈值的regressor和detector进行了实验。从图c可以看出,不同IoU阈值的detector对不同水平的bndbox的优化程度不同,bndbox IoU与detecor的训练阈值越接近,box regress提升越高。而在图c中,detector(u=0.5)在低IoU水平下比detector(u=0.6)表现优异,而在高IoU水平下则反之,而当u=0.7时,由于正样本的不足以及推理时输入的样本IoU较低,detector(u=0.7)的整体表现都降低了。只有输入proposal自身的 IoU分布和detector训练用的阈值IoU较为接近的时候,detector性能才最好,或者说阈值IoU设置应该和R-CNN训练的输入样本IoU分布接近的时候,性能最好,如果两个阈值相距比较远就是mismatch问题。但图 (c)又说明不能一味的提高IoU来达到输出高质量bbox的目的(对应匹配正样本数目不够,会出现过拟合)。


模型介绍

因此,提出了Cascade R-CNN来解决上面的问题。Cascade R-CNN是一个顺序的多阶段extension,利用前一个阶段的输出进行下一阶段的训练,阶段越往后使用更高的IoU阈值,产生更高质量的bndbox。Cascade R-CNN简单而有效,能直接添加到其它R-CNN型detector中,带来巨大的性能提升(2-4%)

既然在Faster R-CNN中不能一味的提高IoU来达到输出高质量bbox的目的,那一个很自然的想法是级联结构,在每个层级采用不同的 IoU 阈值来提升。

图片

  • Faster R-CNN

目前经典的two-stage架构如上图(a)。第一阶段是一个提框的子网H0,用于生成初步的bndbox。第二阶段为特定区域处理的检测子网H1,给定bndbox最终的分类分数C和bndbox坐标B。

  • Iterative BBox

有的研究者认为单次的box regress是不足以产生准确的位置信息的,因此需要进行多次迭代来精调bndbox,这就是iterative bounding box regression:

图片

单次回归(regression)对于边界框(BBox)的精度提升是不够的,因此通常采用多次迭代回归来逐步改进BBox。然而,在多次迭代过程中,不能使用同一个检测头(detection head)。这是因为,每次迭代后的BBox分布都会发生显著变化。即使在初始阶段回归器对BBox的分布最优,经过几次迭代后,它可能不再适用于新的分布,从而导致性能下降。

图片

此外,训练时,IoU阈值设为0.5的回归器对具有更高IoU的假设(hypothesis)产生了次优的效果。图(c)展示了,当IoU阈值为0.5时,迭代回归对IoU大于0.5的假设造成了损害,相比于基准模型(baseline),效果更差。

因此,为了应对这种问题,迭代BBox回归通常需要进行提议积累(proposal accumulation)、框投票(box voting)等手工工程,且这种方法的增益(gain)并不稳定。研究表明,当迭代次数超过两次时,性能改进趋于平稳,甚至可能没有任何好处。

图片

  • Integral Loss

IoU阈值(u)决定了正样本(positive)和负样本(negative)的划分。如果一个假设(hypothesis)与真实框(GT)的IoU高于u,则视为正样本;否则视为负样本。当u值较高时,正样本的数量较少,但背景区域(background)较少;而当u值较低时,可以获得更多样化的正样本,但这会导致检测器难以抑制接近的假阳性(close false positives)。因此,很难找到一个适用于所有IoU水平的分类器。

图片

在推理阶段,RPN等提议生成器生成的假设大多质量较低,因此检测器需要具备更强的辨别能力,尤其是对低质量假设的辨识能力。

图片

一种折衷方案是将IoU阈值设置为0.5,这虽然能提供较多的正样本,但也带来了较低质量的检测结果,通常被认为是接近的假阳性(如图(a)所示)。一种简单的解决思路是使用多个分类器,每个分类器在训练时使用不同的IoU阈值,并在推理时对这些分类器进行集成。在训练过程中,通过使用积分损失(integral loss),来优化多个质量层级。

图片

然而,这种方法存在问题:它未能解决公式(14)中不同损失对正样本数量操作的差异。此外,随着IoU阈值增大,正样本数量迅速减少,这导致高质量分类器出现过拟合问题。而且,高质量分类器在推理时需要处理大量低质量提议,但它们并未针对这些低质量提议进行优化。因此,该方法在大多数质量层级上无法提高准确率,且相较于迭代边界框(Iterative BBox)方法,其增益有限。

图片

因此,Integral loss在很多IoU水平难以表现出高的准确率。相对于原始的two-stage架构,Integral loss的架构收益相对较小

Cascade R-CNN

  • Cascaded BBox Regression

由于很难训练一个能应付所有IoU水平的regressor,可以把回归任务分解成一个级联的regression问题。

图片

T是级联阶段数,每个regressor对于当前的级联输入都是最优的,随着阶段的深入,bndbox在不断的提升。cascade regression与iterative BBox有以下区别:

  • iteravtive BBox是后处理的方法,而cascaded regression是能够改变bndbox分布的重采样过程。

  • cascaded regression在训练和推理时是一致的,不存在区别。

  • cascaded regression的多个regressor对于对应阶段的输入分布是最优的,而iterative BBox仅对初始分布是最优的。

图片

Bndbox在回归时,为了对scale和location有不变性,将对坐标的学习转移到对坐标差值的学习。由于坐标插值通常较小,因此将其进行归一化,以权衡定位与分类的loss。Cascade R-CNN在每一个stage结束后,都会马上进行计算这些均值/方差

  • Cascaded Detection

产生Cascade R-CNN的启发点主要有两个:

  • 初始的bndbox分布大多落在低质量的区域,这对于高质量classifiers来说是无效的学习。

  • 所有的曲线都高于对角线,即regressor都倾向于能够提升bndbox的IoU。

因此,以集合作为开始,通过级联regress来产生高IoU的集合。这种方法能在提升样本整体IoU水平的同时,使得样本的总数大致维持在一个水平,这会带来两个好处:

  • 不会存在某个阈值的regressor过拟合

  • 高阶段的detector对于高IoU阈值是最优的

随着阶段的深入,一些离群点会被过滤,这保证了特定阈值的detector的训练

图片

在每一个阶段t,都独立一个对阈值最优的classifier 和regressor,是上一阶段的输出,是权重因子,是指示函数,表示背景的不加入计算。与integral loss不同,公式8保证了顺序地训练detectors来逐步提高bndbox质量。在推理时,bndbox的质量是顺序提高的,高质量的detectors只需要面对高质量的bndbox。

Cascade R-CNN训练流程相比Faster R-CNN, Cascade R-CNN训练流程只是多了一个循环而已。

def forward_train(self,
                  x,
                  img_metas,
                  proposal_list,
                  gt_bboxes,
                  gt_labels,
                  gt_bboxes_ignore=None,
                  gt_masks=None):
    losses = dict()
    # 对每个 R-CNN 阶段单独操作( 相比 Faster R-CNN 多了这一层循环)
    for i in range(self.num_stages):
        self.current_stage = i
        # 注意每个 stage 的训练参数不一样,典型的例如 Iou 阈值
        rcnn_train_cfg = self.train_cfg[i]
        lw = self.stage_loss_weights[i]
        sampling_results = []
        # n 个 stage, 就会有 n 个 bbox_assigner 和 bbox_sampler
        if self.with_bbox
            bbox_assigner = self.bbox_assigner[i]
            bbox_sampler = self.bbox_sampler[i]
            num_imgs = len(img_metas)
            # 对每张图片单独分配正负样本和采样
            for j in range(num_imgs):
                assign_result = bbox_assigner.assign(
                    proposal_list[j], gt_bboxes[j], gt_bboxes_ignore[j],
                    gt_labels[j])
                sampling_result = bbox_sampler.sample(
                    assign_result,
                    proposal_list[j],
                    gt_bboxes[j],
                    gt_labels[j],
                    feats=[lvl_feat[j][None] for lvl_feat in x])
                sampling_results.append(sampling_result)
        # 按顺序,对每个 stage 进行 train
        # 相比 Faster R-CNN,不仅仅要输出当前 stage 的 loss,还需要额外输出
        # 预测后分类和 bbox 值,方便用于后续 stage refine
        bbox_results = self._bbox_forward_train(i, x, sampling_results,
                                                gt_bboxes, gt_labels,
                                                rcnn_train_cfg)
        # 记录当前 stage 输出的 loss
        for name, value in bbox_results['loss_bbox'].items():
            losses[f's{i}.{name}'] = (
                value * lw if 'loss' in name else value)

        # 如果不是最后一个 stage,则表示需要进行迭代训练
        if i < self.num_stages - 1:
            # pos_is_gts 表示哪些正样本是 gt bbox ( 因为在 R-CNN 阶段会注入 gt bbox 当做额外的
            # RoI 以加速收敛和防止训练不稳定),在 refine 阶段要把这部分正样本剔除
            pos_is_gts = [res.pos_is_gt for res in sampling_results]
            # roi_labels 是在当前 stage 中定义的每个 proposal 的 label, 背景类别是 num_classes
            roi_labels = bbox_results['bbox_targets'][0]
            with torch.no_grad():
                # 对于 label 为背景的 proposal 可能预测后依然是背景,也可能不是背景
                # 为了能够保证一致性,需要将标注为背景的 roi_labels 替换为网络真正预测类别值
                roi_labels = torch.where(
                    roi_labels == self.bbox_head[i].num_classes,
                    bbox_results['cls_score'][:, :-1].argmax(1),
                    roi_labels)
                # 利用 rois bbox_pred 可以得到新的 proposals,用于下个 stage 训练
                proposal_list = self.bbox_head[i].refine_bboxes(
                    bbox_results['rois'], roi_labels,
                    bbox_results['bbox_pred'], pos_is_gts, img_metas)
    return losses

实验结果

作者在通用目标检测、实例分割数据集COCO上进行了实验,换上骨干网ResNeXt-152的Cascade R-CNN又刷出了新高度!AP达到50.9。如下图:

图片

使用不同的检测器和骨干网,级联后都能获得大幅度的精度提升,如下图:

图片

同时可见,级联后推断速度有少许变慢,但在可接受的范围内。

下图是将Cascade Mask R-CNN与基线版本比较的结果,在实例分割任务中,也取得了明显的精度提升。

图片

作者还在一些特殊目标类、不同数据集上做了实验。

图片

均表明该算法能一致性的提高精度。


Coovally AI模型训练与应用平台 

Coovally AI模型训练与应用平台,它整合了整合30+国内外开源社区1000+模型算法。  

图片
平台已部署Cascade R-CNN系列模型算法

在Coovally平台上,无需配置环境、修改配置文件等繁琐操作,一键另存为我的模型,上传数据集,即可使用Cascade R-CNN等热门模型进行训练与结果预测,全程高速零代码!而且模型还可分享与下载,满足你的实验研究与产业应用。

图片


总结

Cascade R-CNN通过引入多阶段级联结构,成功突破了传统目标检测方法在复杂样本处理上的局限性。它在小物体、遮挡物体和复杂背景下的表现尤为突出,成为了一种具有重要意义的目标检测算法。随着技术的不断发展,Cascade R-CNN也为后来的模型算法提供了非常好的创新思路。


如果您有兴趣了解更多关于模型算法的使用方法等,欢迎关注我们,我们将继续为大家带来更多干货内容!

别忘了点赞、留言、收藏哦!


http://www.kler.cn/a/508096.html

相关文章:

  • DETRs with Collaborative Hybrid Assignments Training论文阅读与代码
  • 移动端H5缓存问题
  • 频域增强通道注意力机制EFCAM模型详解及代码复现
  • docker一张图理解
  • C++通透讲解设计模式:依赖倒转(1)
  • 如何使用PHP构建IoC容器,实现依赖注入!
  • 进程的家园:探索 Linux 地址空间的奥秘
  • 多线程进阶-线程安全的集合类
  • 游戏如何检测Xposed框架
  • C#实例化类,当类名和方法一样或者不一样时运行流程
  • 【达梦数据库(Oracle模式)】如何将视图中的数据导出
  • Python 爬虫学习指南与资料分享
  • rsync结合inotify实现文件实时同步
  • Lua项目下SSRF利用Redis文件覆盖lua回显RCE
  • 人工智能之深度学习_[3] -PyTorch自动微分模块和构建线性回归模型
  • 1.1初探大模型:起源与发展
  • 如何将数据库字符集改为中文,让今后所有的数据库都支持中文
  • 二十三种设计模式-代理模式
  • IF=24.5! 综述:机器人纹理识别触觉感知和机器学习进展
  • 请求响应-
  • 【算法】差分
  • python爬取Boss直聘,分析北京招聘市场
  • Android-V lmkd 中的那些属性值
  • WORD转PDF脚本文件
  • 如何攻击一个服务器(仅用于教育及娱乐实验目的)
  • 从零用java实现 小红书 springboot vue uniapp (10)系统消息模块 接收推送消息优化