深入解读 MMDetection 中的 Cascade RPN:级联区域提议网络与自适应卷积实战指南
【免费下载链接】mmdetectionOpenMMLab Detection Toolbox and Benchmark项目地址: https://gitcode.com/gh_mirrors/mm/mmdetection
Cascade RPN(Cascade Region Proposal Network)是 MMDetection 中内置的一种高质量区域提议算法,它通过"单锚点 + 多阶段级联细化"的思路替代传统 RPN 的密集多锚点设计,并用自适应卷积实现特征与提议框的对齐。本文以 configs/cascade_rpn/README.md 为核心骨架,结合 mmdet/models/dense_heads/cascade_rpn_head.py 的源码实现与 configs/cascade_rpn 下的三套官方配置,系统讲解其算法原理、两阶段级联结构、自适应卷积的两种模式、关键配置项语义,以及如何用它替换 Faster R-CNN / Fast R-CNN 的 RPN 并完成训练与推理。读完本文,你将能够理解 Cascade RPN 的完整工作流,并在自己的检测实验中直接复用官方配置或按需调整超参数。
一、从传统 RPN 的痛点看 Cascade RPN 的设计动机
传统 RPN(Region Proposal Network)在特征图的每个位置上铺设多种预定义尺度和宽高比的锚点(如 Faster R-CNN 默认 3 种尺度 × 3 种宽高比),并通过分类分支判断前景背景、回归分支微调锚点位置。论文Cascade RPN: Delving into High-Quality Region Proposal Network with Adaptive Convolution(Vu et al., NeurIPS 2019)指出这种启发式设计的两个核心局限:
- 锚点数量多但质量低:为覆盖目标的尺度多样性,需要大量预定义锚点,但锚点与真实目标之间的对齐程度依赖人工设定的超参数;
- 特征与锚点不对齐:RPN 在固定位置的网格点上采样特征,而回归后的锚点(提议框)位置往往已偏离原始网格,导致后续阶段使用的特征与实际框位置存在偏差。
Cascade RPN 通过两条关键设计系统性解决上述问题:
- 单锚点 + 多阶段细化:每个位置只使用一个锚点(尺度 8、宽高比 1.0),通过多个级联阶段逐步精修提议框;各阶段对正样本的定义由宽松到严格(第一阶段使用无锚点的区域分配策略,后续阶段逐步切换到基于 IoU 的锚点策略);
- 自适应卷积(Adaptive Convolution):卷积的采样位置以当前锚点为引导,而非固定在规则网格上,从而在各阶段维持特征与提议框的对齐。
论文报告在 COCO 上,简单的两阶段 Cascade RPN 相比传统 RPN 将 AR 提升13.4 个点,超越了当时的已有区域提议方法;将其应用于 Fast R-CNN 与 Faster R-CNN,检测 mAP 分别提升3.1 与 3.5 个点。MMDetection 在此基础上提供了可直接复现的官方实现。
二、算法核心:两阶段级联结构与自适应卷积
2.1 整体工作流:渐进式精修的级联流水线
在 MMDetection 中,级联提议网络由两个层级组成,定义在 mmdet/models/dense_heads/cascade_rpn_head.py:
CascadeRPNHead:级联的"总调度器",持有若干StageCascadeRPNHead子阶段(self.stages = ModuleList()),负责串联各阶段的输入输出、逐阶段计算损失,并在阶段之间调用refine_bboxes用上一阶段的回归结果生成新的锚点;StageCascadeRPNHead:继承自RPNHead的单个级联阶段,负责该阶段的特征提取、分类/回归预测与损失计算。
CascadeRPNHead.loss与loss_and_predict中的核心循环(见 cascade_rpn_head.py)清晰展示了级联流程:
for i in range(self.num_stages): stage = self.stages[i] # 依据自适应卷积类型生成偏移量(offset 模式)或置空(dilation 模式) if stage.adapt_cfg['type'] == 'offset': offset_list = stage.anchor_offset(anchor_list, stage.anchor_strides, featmap_sizes) else: offset_list = None x, cls_score, bbox_pred = stage(x, offset_list) # 计算本阶段损失,loss 字典中以 s{i}.xxx 命名,便于区分各阶段 stage_loss = stage.loss_by_feat(*rpn_loss_inputs) # 除最后一个阶段外,用回归结果精修锚点,作为下一阶段的输入 if i < self.num_stages - 1: anchor_list = stage.refine_bboxes(anchor_list, bbox_pred, batch_img_metas)从源码结构可以看到两个关键机制:
- 锚点精修(refine_bboxes):阶段 i 的回归头输出 bbox_pred 后,
refine_bboxes(cascade_rpn_head.py)使用DeltaXYWHBBoxCoder将上一阶段的锚点与回归量解码为新的绝对坐标框,作为下一阶段的锚点继续细化; - 特征桥接(bridged_feature):
forward_single(cascade_rpn_head.py)中,若某阶段设置了bridged_feature=True,则该阶段卷积输出的特征会更新输入特征(bridged_x = x),实现跨阶段的特征信息流动。
2.2 自适应卷积:让采样位置跟随锚点
AdaptiveConv类(cascade_rpn_head.py)是特征对齐的关键,支持两种adapt_type:
| 模式 | 底层实现 | 适用场景 | 源码要点 |
|---|---|---|---|
dilation | 普通nn.Conv2d+ 固定膨胀率 | 锚点尺度均匀(第一阶段) | padding=dilation, dilation=dilation,无需 offset 输入 |
offset | DeformConv2d(可变形卷积) | 锚点任意形状(第二阶段) | 按锚点宽高与中心计算 3×3 核的 18 维偏移量 |
在offset模式下,anchor_offset(cascade_rpn_head.py)为每个锚点计算可变形卷积的采样偏移,偏移量由两部分叠加:
- 形状偏移(shape offset):由锚点的宽
w、高h相对步长stride的比值决定,使 3×3 卷积核的采样点沿锚点形状拉伸; - 中心偏移(center offset):由锚点中心相对特征图规则网格中心的偏差决定,使采样点对准锚点中心。
两者相加得到最终的 18 维偏移(3×3 核 × 2 坐标),再通过offset.permute(0, 2, 1).reshape(N, -1, H, W)重塑后送入DeformConv2d。这一机制让每一级的卷积感受野"贴"在当前提议框上,从实现层面印证了论文中"自适应卷积以锚点为引导学习采样特征"的表述。值得注意的是,源码中的_shape_offset注释明确说明当前仅支持kernel_size=3, dilation=1的偏移模式,调整adapt_cfg时需注意这一限制。
2.3 两阶段训练策略:从"无锚点"到"严格 IoU"
与两阶段结构对应,CascadeRPNHead在训练时使用两个train_cfg.rpn子配置(RegionAssigner→MaxIoUAssigner),正样本定义由宽松到严格:
| 阶段 | 分配器 | 正样本标准 | 采样器 | 分类分支 | 自适应卷积 | 特征桥接 |
|---|---|---|---|---|---|---|
| Stage 0 | RegionAssigner(center_ratio=0.2, ignore_ratio=0.5) | 基于区域中心比的无锚点分配 | 无(sampling=False,使用PseudoSampler) | 无(with_cls=False) | dilation(dilation=3) | bridged_feature=True |
| Stage 1 | MaxIoUAssigner(pos_iou_thr=0.7, neg_iou_thr=0.7, min_pos_iou=0.3) | 与 GT 的 IoU ≥ 0.7 | RandomSampler(256 个样本,正样本比例 0.5) | 有(with_cls=True) | offset | bridged_feature=False |
对应源码中StageCascadeRPNHead.__init__的逻辑(cascade_rpn_head.py):当train_cfg中未提供sampler时,自动退化为PseudoSampler,这正是第一阶段sampling=False的实现基础。
这种"渐进收紧"的正样本定义与 Cascade R-CNN 的思想一脉相承:早期阶段用宽松标准快速召回大量候选,后续阶段用严格标准筛出高质量提议,从而在保持召回率的同时提升提议质量。
三、官方配置逐行解析
configs/cascade_rpn目录下提供了三套可直接运行的官方配置:
- cascade-rpn_r50-caffe_fpn_1x_coco.py:纯 Cascade RPN 提议网络(RPN-only),用于评估区域提议质量(AR);
- cascade-rpn_fast-rcnn_r50-caffe_fpn_1x_coco.py:Cascade RPN + Fast R-CNN,基于预生成的提议文件训练检测头;
- cascade-rpn_faster-rcnn_r50-caffe_fpn_1x_coco.py:Cascade RPN + Faster R-CNN,端到端联合训练。
3.1 Cascade RPN 头配置(以 RPN-only 配置为例)
_base_ = '../rpn/rpn_r50-caffe_fpn_1x_coco.py' model = dict( rpn_head=dict( _delete_=True, # 覆盖基类配置中的标准 RPNHead type='CascadeRPNHead', # 级联提议头 num_stages=2, # 级联阶段数 stages=[ dict( type='StageCascadeRPNHead', in_channels=256, feat_channels=256, anchor_generator=dict( type='AnchorGenerator', scales=[8], # 每位置仅一个尺度 ratios=[1.0], # 每位置仅一个宽高比(正方形锚点) strides=[4, 8, 16, 32, 64]), # FPN 五层特征图步长 adapt_cfg=dict(type='dilation', dilation=3), bridged_feature=True, # 输出特征桥接至下一阶段 sampling=False, # 不采样,使用 PseudoSampler with_cls=False, # 第一阶段不做分类 reg_decoded_bbox=True, # 直接对解码后的框回归(配合 IoU 损失) bbox_coder=dict( type='DeltaXYWHBBoxCoder', target_means=(.0, .0, .0, .0), target_stds=(0.1, 0.1, 0.5, 0.5)), loss_bbox=dict(type='IoULoss', linear=True, loss_weight=10.0)), dict( type='StageCascadeRPNHead', in_channels=256, feat_channels=256, adapt_cfg=dict(type='offset'), # 可变形卷积自适应采样 bridged_feature=False, sampling=True, with_cls=True, # 第二阶段启用分类 reg_decoded_bbox=True, bbox_coder=dict( type='DeltaXYWHBBoxCoder', target_means=(.0, .0, .0, .0), target_stds=(0.05, 0.05, 0.1, 0.1)), # 更小的回归 std,回归更保守 loss_cls=dict( type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), loss_bbox=dict(type='IoULoss', linear=True, loss_weight=10.0)) ]), train_cfg=dict(rpn=[ dict( assigner=dict( type='RegionAssigner', center_ratio=0.2, ignore_ratio=0.5), allowed_border=-1, pos_weight=-1, debug=False), dict( assigner=dict( type='MaxIoUAssigner', pos_iou_thr=0.7, neg_iou_thr=0.7, min_pos_iou=0.3, ignore_iof_thr=-1, iou_calculator=dict(type='BboxOverlaps2D')), sampler=dict( type='RandomSampler', num=256, pos_fraction=0.5, neg_pos_ub=-1, add_gt_as_proposals=False), allowed_border=-1, pos_weight=-1, debug=False) ]), test_cfg=dict( rpn=dict( nms_pre=2000, max_per_img=2000, nms=dict(type='nms', iou_threshold=0.8), min_bbox_size=0))) optim_wrapper = dict(clip_grad=dict(max_norm=35, norm_type=2))配置要点说明:
_delete_=True:基类 configs/rpn/rpn_r50-caffe_fpn_1x_coco.py 已定义标准RPNHead,必须删除后才能替换为CascadeRPNHead;- 单锚点:
scales=[8]+ratios=[1.0]意味着每层特征图每位置仅 1 个锚点,相比传统 RPN 的 9 个锚点大幅减少; - 两个 bbox_coder 的 std 差异:第一阶段的
target_stds=(0.1, 0.1, 0.5, 0.5)允许较大回归幅度,第二阶段(0.05, 0.05, 0.1, 0.1)使回归更收敛于小范围——对应渐进精修的直觉; reg_decoded_bbox=True:回归目标直接使用解码后的绝对坐标框(pos_bbox_targets = sampling_result.pos_gt_bboxes),从而可以使用IoULoss直接在框级别监督回归;- 梯度和
IoULoss(linear=True):两阶段均使用线性 IoU 损失且权重为 10.0,配合optim_wrapper.clip_grad(max_norm=35, norm_type=2)的梯度裁剪,保证训练稳定; - 测试阶段 NMS 阈值 0.8:较标准 RPN 默认的 0.7 更宽松,因为级联提议本身质量更高,允许保留更多重叠提议(
nms_pre=2000, max_per_img=2000)。
该配置继承的 caffe 风格基类还包含data_preprocessor的 caffe 归一化参数(mean=[103.530, 116.280, 123.675],bgr_to_rgb=False)以及冻结 BatchNorm 的norm_eval=True、style='caffe'骨干设置,训练时需注意数据预处理需与预训练权重匹配。
3.2 与 Faster R-CNN 联合训练(端到端配置)
cascade-rpn_faster-rcnn_r50-caffe_fpn_1x_coco.py 以 configs/faster_rcnn/faster-rcnn_r50-caffe_fpn_1x_coco.py 为基类,在级联头之上调整了 R-CNN 部分:
rpn_weight = 0.7 # 级联 RPN 损失权重缩放因子 model = dict( rpn_head=dict( _delete_=True, type='CascadeRPNHead', num_stages=2, stages=[...]), # 与 3.1 相同的两阶段定义,但损失权重乘 rpn_weight roi_head=dict( bbox_head=dict( bbox_coder=dict(target_stds=[0.04, 0.04, 0.08, 0.08]), loss_cls=dict( type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.5), loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), train_cfg=dict( rpn=[...], # RegionAssigner → MaxIoUAssigner 两阶段分配 rpn_proposal=dict(max_per_img=300, nms=dict(iou_threshold=0.8)), rcnn=dict( assigner=dict( pos_iou_thr=0.65, neg_iou_thr=0.65, min_pos_iou=0.65), sampler=dict(type='RandomSampler', num=256))), test_cfg=dict( rpn=dict(max_per_img=300, nms=dict(iou_threshold=0.8)), rcnn=dict(score_thr=1e-3)))与纯 RPN 配置的差异集中在:
rpn_weight = 0.7:RPN 的各损失权重乘以 0.7(如loss_weight=10.0 * rpn_weight、loss_cls=1.0 * rpn_weight),避免端到端联合训练中 RPN 损失喧宾夺主,同时 R-CNN 的分类损失权重提升到 1.5;rpn_proposal提议数量收紧:从 2000 降至 300,并设置 NMS 阈值 0.8,保证送入 R-CNN 的提议数量适中;- R-CNN 分配器更严格:
pos_iou_thr=0.65, neg_iou_thr=0.65, min_pos_iou=0.65均高于标准 Faster R-CNN 的 0.5——因为 Cascade RPN 提供的提议质量更高,检测头可以放心使用更高的正样本门槛。
3.3 与 Fast R-CNN 组合(基于预生成提议文件)
cascade-rpn_fast-rcnn_r50-caffe_fpn_1x_coco.py 以 configs/fast_rcnn/fast-rcnn_r50-caffe_fpn_1x_coco.py 为基类,检测头配置与 3.2 相同,其特殊之处在于通过proposal_file指定预生成的提议:
_base_.train_dataloader.dataset.proposal_file = 'proposals/crpn_r50_caffe_fpn_1x_train2017.pkl' _base_.val_dataloader.dataset.proposal_file = 'proposals/crpn_r50_caffe_fpn_1x_val2017.pkl' test_dataloader = _base_.val_dataloader这意味着使用 Fast R-CNN 时,需要先用 Cascade RPN 配置在训练/验证集上离线生成提议并保存为 pkl 文件(训练约 12 epoch),再单独训练检测头。MMEngine 同时支持注释中展示的两种写法:直接在train_dataloader = dict(dataset=dict(proposal_file=...))中覆盖,或通过_base_引用逐层修改。这种"提议生成与检测训练解耦"的方式更贴近论文中的实验设定,也便于对比不同提议方法的公平性。
四、实验结果与模型权重
根据 metafile.yml 与 README,官方在 COCO 上的结果汇总如下。
4.1 区域提议质量(AR 1000)
| Method | Backbone | Style | AR 1000 | Config | Download |
|---|---|---|---|---|---|
| CRPN | R-50-FPN | caffe | 72.0 | config | model |
4.2 检测性能(COCO box AP)
| Method | Proposal | Backbone | Style | Schedule | box AP | Config | Download |
|---|---|---|---|---|---|---|---|
| Fast R-CNN | Cascade RPN | R-50-FPN | caffe | 1x | 39.9 | config | model |
| Faster R-CNN | Cascade RPN | R-50-FPN | caffe | 1x | 40.4 | config | model |
说明:
- 表中模型均为官方在 COCO 上训练所得(见 metafile.yml,Training Data: COCO,训练资源 8× V100,12 epochs / 1x 调度),可直接下载权重用于推理或微调;
- 纯 RPN 配置的 CRPN 模型 AR 1000 达 72.0;接入 Fast R-CNN / Faster R-CNN 后 box AP 分别达到 39.9 / 40.4,与论文"3.1 / 3.5 点提升"的实验结论相互印证;
- 论文全称为Cascade RPN: Delving into High-Quality Region Proposal Network with Adaptive Convolution(arXiv:1909.06720),引用信息见 README 的 Citation 部分。
五、训练与推理实战
以下命令在 MMDetection 3.x 环境中运行,$CONFIG指向上述任一配置文件(推荐以cascade-rpn_faster-rcnn_r50-caffe_fpn_1x_coco.py起步)。
5.1 单机训练与测试
# 单 GPU 训练 python tools/train.py $CONFIG # 多卡分布式训练(8 卡) bash tools/dist_train.sh $CONFIG 8 # 测试(自动加载与配置文件同目录的 checkpoint) python tools/test.py $CONFIG ${CHECKPOINT_FILE}训练过程中的日志、checkpoint 默认输出到work_dirs/下与配置同名的工作目录。由于 Cascade RPN 两阶段均包含可变形卷积(第二阶段)与梯度裁剪,训练显存占用与耗时高于标准 RPN,请在资源规划时预留空间。
5.2 用预训练权重做推理与可视化
# 使用官方发布的权重进行测试 python tools/test.py configs/cascade_rpn/cascade-rpn_faster-rcnn_r50-caffe_fpn_1x_coco.py \ https://download.openmmlab.com/mmdetection/v2.0/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco/crpn_faster_rcnn_r50_caffe_fpn_1x_coco-c8283cca.pth # 单张图片推理可视化 python demo/image_demo.py demo/demo.jpg \ configs/cascade_rpn/cascade-rpn_faster-rcnn_r50-caffe_fpn_1x_coco.py \ https://download.openmmlab.com/mmdetection/v2.0/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco/crpn_faster_rcnn_r50_caffe_fpn_1x_coco-c8283cca.pth注意:demo/image_demo.py的推理流程遵循模型配置中的test_cfg(此处max_per_img=300、NMS 阈值 0.8),推理得到的检测框即为 Cascade RPN 提议经 R-CNN 头精修后的最终结果。
5.3 Fast R-CNN 流程:先出提议,再训检测头
若需复现 cascade-rpn_fast-rcnn_r50-caffe_fpn_1x_coco.py 的实验流程,可参照以下两阶段方案:
- 用纯 RPN 配置 cascade-rpn_r50-caffe_fpn_1x_coco.py 训练 Cascade RPN,并分别在
train2017、val2017上推理保存提议为 pkl(对应配置中的proposal_file路径); - 以 Fast R-CNN 配置训练检测头,此时数据集加载器会从
proposals/crpn_r50_caffe_fpn_1x_train2017.pkl读取提议而非在线生成。
这种解耦式流程适合需要在固定提议集合上快速迭代检测头(或公平对比不同提议器)的研究场景。
六、扩展与注意事项
6.1 如何调节级联强度
在CascadeRPNHead中可通过num_stages与stages列表自由增减阶段数,但需同时保证train_cfg.rpn列表长度一致(源码断言num_stages == len(stages))。经验性配置原则:
- 首阶段建议保持
sampling=False, with_cls=False, bridged_feature=True的"粗召回"设定,配合RegionAssigner无锚点分配; - 中间/末阶段逐步启用分类与随机采样,将
MaxIoUAssigner的pos_iou_thr从 0.7 起逐级提高,实现渐进式严格化; adapt_cfg的offset模式目前只支持 3×3 核与 dilation=1(源码断言),dilation模式则支持任意膨胀率,修改时注意对应限制。
6.2 兼容性与限制
- 当前实现仅支持二分类前景/背景设定,源码断言
num_classes == 1(cascade_rpn_head.py),即作为提议网络使用,不能直接当多类别检测头; - 预训练权重加载:
CascadeRPNHead使用ModuleList组织阶段,源码注释特别提示"Pretrained weights cannot be loaded when use nn.ModuleList",加载 caffe 风格 ResNet-50 预训练权重时以 configs/rpn/rpn_r50-caffe_fpn_1x_coco.py 的Pretrained初始化方式为准(open-mmlab://detectron2/resnet50_caffe); - 测试阶段 NMS 阈值(0.8)高于标准 RPN(0.7),若替换回标准 RPN 或与其他检测头组合,需重新验证后处理参数;
- 仓库提供的
RegionAssigner等任务模块实现在 mmdet/models/task_modules/assigners,测试用例覆盖了 Cascade RPN 的两阶段配置与损失计算(见 tests/test_models/test_dense_heads/test_cascade_rpn_head.py),可作为理解各阶段行为的参考。
七、总结
Cascade RPN 用"单锚点 + 多阶段级联精修 + 自适应卷积"重新设计了区域提议网络:第一阶段的dilation自适应卷积与RegionAssigner无锚点分配负责粗召回,第二阶段通过offset可变形卷积对准任意形状锚点、以 IoU≥0.7 的严格标准筛选高质量提议,最终以两阶段损失的渐进式监督实现提议质量的显著提升。MMDetection 提供的三套官方配置(RPN-only、Fast R-CNN、Faster R-CNN)覆盖了从提议质量评估到端到端检测的完整实验路径,AR 1000 达到 72.0,接入检测器后 box AP 达到 39.9 / 40.4。本文结合 cascade_rpn_head.py 的源码与 configs/cascade_rpn 下的配置文件,完整呈现了该算法的原理、配置语义与实战用法,你可以在此基础上直接复用官方配置,或针对自己的数据与算力调整级联阶段数、分配阈值与损失权重。
【免费下载链接】mmdetectionOpenMMLab Detection Toolbox and Benchmark项目地址: https://gitcode.com/gh_mirrors/mm/mmdetection
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考