MMDetection 检测器鲁棒性基准测试实战:图像损坏评测的原理、工具与结果分析
【免费下载链接】mmdetectionOpenMMLab Detection Toolbox and Benchmark项目地址: https://gitcode.com/gh_mirrors/mm/mmdetection
本文围绕 MMDetection 内置的「图像损坏基准测试(Image Corruption Benchmark)」工具展开,系统讲解其设计来源、底层实现、完整命令行用法与评测指标含义。读完你将掌握如何用
tools/analysis_tools/test_robustness.py对任意检测/分割模型施加 15~19 类损坏变换、在 0~5 级严重程度下批量评测,并正确解读 P、mPC、rPC 三类指标,评估模型在真实恶劣场景(如自动驾驶冬季天气)下的鲁棒性。
背景:为什么需要鲁棒性基准测试
目标检测与实例分割模型通常在干净数据集上评测,但真实部署环境往往充满噪声、模糊、恶劣天气与数字失真。MMDetection 提供了 Michaelis 等人在论文Benchmarking Robustness in Object Detection: Autonomous Driving when Winter is Coming(arXiv:1907.07484,2019)中定义的图像损坏基准测试工具,用于量化模型在各类常见损坏(corruption)下的性能退化程度。该基准测试仿照 Dan Hendrycks 与 Thomas Dietterich 在 ICLR 2019 发表的 ImageNet-C 基准测试(Benchmarking Neural Network Robustness to Common Corruptions and Perturbations,arXiv:1903.12261)设计,是评估模型泛化能力与部署可靠性的重要手段。
@article{michaelis2019winter, title={Benchmarking Robustness in Object Detection: Autonomous Driving when Winter is Coming}, author={Michaelis, Claudio and Mitzkus, Benjamin and Geirhos, Robert and Rusak, Evgenia and Bringmann, Oliver and Ecker, Alexander S. and Bethge, Matthias and Brendel, Wieland}, journal={arXiv:1907.07484}, year={2019} }上图直观展示了同一张自动驾驶场景图像在各类损坏变换(噪声、模糊、天气、数字失真等)严重程度 3 级下的视觉效果,也是后续评测中被施加到输入图像上的典型干扰形态。
基准测试的整体设计
损坏变换来源:imagecorruptions 库
图像损坏变换函数本身并不由 MMDetection 实现,而是来自独立的imagecorruptions库(与 robust-detection-benchmark 同属 bethgelab 组织)。该库可以单独安装:
pip install imagecorruptions安装后即可在 MMDetection 的评测流程中直接使用。需要注意的是,imagecorruptions属于可选依赖,未安装时评测脚本仍可运行,但在实际施加损坏变换时会抛出RuntimeError('imagecorruptions is not installed')(见 mmdet/datasets/transforms/transforms.py 中Corrupt.transform的守卫逻辑,源码通过try/except ImportError将corrupt置为None后再做判空)。
与 ImageNet-C 的差异
与 ImageNet-C 相比,MMDetection 的适配做了三处关键调整:
- 支持任意尺寸图像:ImageNet-C 面向固定尺寸的分类图像,而检测任务中图像尺寸任意,损坏变换函数需按原图分辨率生效;
- 支持灰度图像:部分检测数据集(如行人检测、遥感场景)包含灰度图,变换函数必须能处理单通道输入;
- 解除 Linux 特定库依赖:原版「运动模糊(motion blur)」与「雪(snow)」损坏依赖部分 Linux 专用库,MMDetection 对其进行了修改,避免使用者额外安装这些系统级依赖。
底层实现:Corrupt数据变换
损坏变换在 MMDetection 中被封装为一个标准的注册式数据变换Corrupt(位于 mmdet/datasets/transforms/transforms.py),其设计如下:
- 通过
@TRANSFORMS.register_module()注册到TRANSFORMS注册表,可直接在配置的pipeline中以字典形式使用; - 构造参数:
corruption(损坏名称,必填)与severity(严重程度,默认 1); - 作用对象:将
results['img'](要求为np.uint8类型)传入imagecorruptions.corrupt()函数,原地返回损坏后的图像; __repr__输出形如Corrupt(corruption=gaussian_blur, severity=1),便于日志排查。
该变换的单元测试位于 tests/test_datasets/test_transforms/test_transforms.py,测试验证了「加载图像 → 施加Corrupt(corruption='gaussian_blur')」后输出图像仍保持np.uint8类型,以及__repr__的字符串格式。
使用 test_robustness.py 进行鲁棒性评测
MMDetection 提供了专用评测脚本 tools/analysis_tools/test_robustness.py。当前仓库版本支持单张 GPU 测试(多 GPU 测试与检测结果可视化在原文档中标注为未实现)。
前提条件
- 已安装 MMDetection 及其运行依赖;
- 已安装
imagecorruptions(pip install imagecorruptions); - 准备好模型配置文件(
${CONFIG_FILE})与预训练权重(${CHECKPOINT_FILE}); - 准备测试数据集(脚本默认沿用配置中的
test_dataloader,并将dataset.test_mode置为True)。
基础用法:全量 benchmark 评测
# single-gpu testing python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}]其中--out指定结果 dump 文件(必须为.pkl或.pickle后缀,脚本会通过向test_evaluator追加DumpResults虚拟指标将逐级结果写入磁盘);评估指标在当前仓库版本中由配置文件里的test_evaluator决定(脚本不再单独解析--eval,这与旧版命令行略有差异,以当前 test_robustness.py 源码为准)。
按损坏类别筛选
--corruptions支持类别名与具体损坏名两种粒度,类别到具体损坏的映射由脚本内部展开(源码见 tools/analysis_tools/test_robustness.py):
# 只测噪声类 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --corruptions noise # 只测模糊类 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --corruptions blur # 只测天气类 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --corruptions weather # 只测数字失真类 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --corruptions digital或直接指定任意自定义组合(多个损坏名以空格分隔),例如:
# 高斯噪声、缩放模糊和雪 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --corruptions gaussian_noise zoom_blur snow完整的损坏类别与成员映射如下(共 4 类 benchmark 损坏 + 1 类 holdout 损坏):
| 类别 | 成员损坏 | 说明 |
|---|---|---|
noise | gaussian_noise、shot_noise、impulse_noise | 噪声类 |
blur | defocus_blur、glass_blur、motion_blur、zoom_blur | 模糊类 |
weather | snow、frost、fog、brightness | 天气类 |
digital | contrast、elastic_transform、pixelate、jpeg_compression | 数字失真类 |
holdout | speckle_noise、gaussian_blur、spatter、saturate | 留出类(不计入 benchmark 汇总) |
其中benchmark(默认值)对应前 4 类共 15 种损坏,all则在 benchmark 基础上追加 holdout 的 4 种,共 19 种;None表示不施加任何损坏(此时脚本自动将severities固定为[0])。
控制损坏严重程度
--severities控制施加在图像上的损坏强度,取值 0~5,数值越大损坏越强,其中0表示原始图像(不施加任何损坏):
# 仅严重程度 1 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --severities 1 # 严重程度 0、2、4 python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] --severities 0 2 4脚本默认值为[0, 1, 2, 3, 4, 5],即一次性评测全部 6 个等级。内部实现上,脚本会为每种损坏×每个严重程度构建独立的test_dataloader:通过copy.deepcopy复制test_dataloader,并在pipeline的第 1 个位置(图像加载之后)插入dict(type='Corrupt', corruption=..., severity=...)变换(源码见 tools/analysis_tools/test_robustness.py)。此外,严重程度 0(无损坏)的结果只评估一次,其他损坏的 0 级结果直接复用第一类损坏的 0 级结果,避免重复计算(源码见 tools/analysis_tools/test_robustness.py)。
完整参数速查表
以下为当前仓库版本中test_robustness.py支持的全部命令行参数(源码见 tools/analysis_tools/test_robustness.py):
| 参数 | 取值/默认 | 说明 |
|---|---|---|
config(位置参数) | 必填 | 测试配置文件路径 |
checkpoint(位置参数) | 必填 | 模型权重文件 |
--out | .pkl/.pickle | 保存预测结果为 pickle 文件,供离线评估 |
--corruptions | 默认benchmark,可选all/benchmark/noise/blur/weather/digital/holdout/None及 19 种具体损坏名 | 指定损坏变换类型 |
--severities | 默认[0,1,2,3,4,5] | 损坏严重程度等级 |
--work-dir | 默认取配置或 config 文件名 | 保存评估指标文件的目录 |
--summaries | 默认False | 为每种损坏和严重程度打印汇总 |
--show | 开关 | 展示检测结果(需--out或--show-dir之一) |
--show-dir | 字符串 | 保存绘制了检测结果的图像目录 |
--wait-time | 默认 2 | 展示间隔(秒) |
--seed | 默认None | 随机种子,用于复现损坏变换的随机性 |
--launcher | none/pytorch/slurm/mpi,默认none | 任务启动器 |
--local_rank | 默认 0 | 本地进程编号 |
--final-prints | P/mPC/rPC,默认mPC | 最终打印的鲁棒性指标 |
--final-prints-aggregate | all/benchmark,默认benchmark | 汇总全部结果或仅汇总 benchmark 损坏 |
--cfg-options | xxx=yyy键值对 | 覆盖配置项,支持列表/嵌套结构(如key="[a,b]") |
其中--out、--show、--show-dir三者至少指定其一,否则脚本会断言失败(源码见 tools/analysis_tools/test_robustness.py)。
评测指标解读:P、mPC、rPC
评测完成后,--out对应的结果文件(形如${out 前缀}_results.pkl)记录了每种损坏在各严重程度下的完整评估结果。汇总统计与打印由 tools/analysis_tools/robustness_eval.py 完成,其核心逻辑如下:
- P(Performance on Clean Data):干净数据上的性能,即严重程度 0 的结果,作为基准参照;
- mPC(Mean Performance under Corruption):所有损坏×非零严重程度的平均性能。当
aggregate='benchmark'时仅统计前 15 种 benchmark 损坏,即mPC = np.mean(results[:15, 1:, :]);当aggregate='all'时统计全部损坏; - rPC(Relative Performance under Corruption):相对性能保持率,
rPC = mPC / P,反映模型在损坏下保留了多大比例的精度,是评估鲁棒性最直观的指标。
针对不同数据集,脚本支持两类统计方式(源码见 tools/analysis_tools/robustness_eval.py):
- COCO 风格(
coco、cityscapes):按task(bbox/segm)输出 mAP、mAP_50、mAP_75、mAP_s、mAP_m、mAP_l 等完整指标; - Pascal VOC(
voc):仅支持 bbox 任务与 AP50 指标,输出形式为各类别 AP 的均值。
在 test_robustness.py 中,脚本会根据cfg.dataset_type是否为VOCDataset自动选择 VOC 或 COCO 风格的汇总逻辑。
模型鲁棒性测试结果(COCO 2017val)
下表为各模型在 COCO 2017 val 上的鲁棒性测试结果(来自 docs/zh_cn/user_guides/robustness_benchmarking.md),其中 "box AP clean" 为干净数据上的 box AP,"box AP corr." 为损坏数据下的 box AP,"box %" 为两者比值(即 rPC),mask 列同理:
| Model | Backbone | Style | Lr schd | box AP clean | box AP corr. | box % | mask AP clean | mask AP corr. | mask % |
|---|---|---|---|---|---|---|---|---|---|
| Faster R-CNN | R-50-FPN | pytorch | 1x | 36.3 | 18.2 | 50.2 | - | - | - |
| Faster R-CNN | R-101-FPN | pytorch | 1x | 38.5 | 20.9 | 54.2 | - | - | - |
| Faster R-CNN | X-101-32x4d-FPN | pytorch | 1x | 40.1 | 22.3 | 55.5 | - | - | - |
| Faster R-CNN | X-101-64x4d-FPN | pytorch | 1x | 41.3 | 23.4 | 56.6 | - | - | - |
| Faster R-CNN | R-50-FPN-DCN | pytorch | 1x | 40.0 | 22.4 | 56.1 | - | - | - |
| Faster R-CNN | X-101-32x4d-FPN-DCN | pytorch | 1x | 43.4 | 26.7 | 61.6 | - | - | - |
| Mask R-CNN | R-50-FPN | pytorch | 1x | 37.3 | 18.7 | 50.1 | 34.2 | 16.8 | 49.1 |
| Mask R-CNN | R-50-FPN-DCN | pytorch | 1x | 41.1 | 23.3 | 56.7 | 37.2 | 20.7 | 55.7 |
| Cascade R-CNN | R-50-FPN | pytorch | 1x | 40.4 | 20.1 | 49.7 | - | - | - |
| Cascade Mask R-CNN | R-50-FPN | pytorch | 1x | 41.2 | 20.7 | 50.2 | 35.7 | 17.6 | 49.3 |
| RetinaNet | R-50-FPN | pytorch | 1x | 35.6 | 17.8 | 50.1 | - | - | - |
| Hybrid Task Cascade | X-101-64x4d-FPN-DCN | pytorch | 1x | 50.6 | 32.7 | 64.7 | 43.8 | 28.1 | 64.0 |
从上表可以观察到两个规律:其一,模型在损坏图像上的 AP 普遍大幅下降,单阶段与两阶段检测器的 rPC 大多在 50%~57% 区间,说明常见损坏对检测性能的破坏相当显著;其二,更强的骨干网络与可变形卷积(DCN)通常带来更高的绝对精度,也在一定程度上提升了 rPC——例如 Faster R-CNN X-101-32x4d-FPN-DCN 的 box % 达到 61.6%,显著高于 R-50-FPN 的 50.2%,表明模型容量与特征自适应能力有助于提高鲁棒性。
注意事项与使用建议
- 结果存在随机性:由于部分损坏变换(如噪声、模糊)内部带有随机过程,测试结果可能略有不同。若需严格复现,可通过
--seed指定随机种子(脚本会在每轮测试前调用runner.set_randomness(args.seed),源码见 tools/analysis_tools/test_robustness.py); - 依赖安装:务必先
pip install imagecorruptions,否则评测会在第一个损坏变换处因RuntimeError中断; - 评估范围:
benchmark模式默认只统计 15 种核心损坏;如需将 holdout 类(speckle_noise、gaussian_blur、spatter、saturate)纳入统计,需使用--corruptions all并配合--final-prints-aggregate all; - 多 GPU 支持现状:当前仓库的鲁棒性评测脚本仅支持单 GPU 测试,多 GPU 与检测结果可视化在原文档中标记为待实现;
- 结果解读视角:对比
box %(rPC)比单纯对比损坏下的绝对 AP 更有意义,因为它剔除了模型基础精度差异,反映的是模型在损坏下的相对保持能力;同时建议在报告中同时给出 P 与 mPC,便于读者还原绝对水平。
综上,MMDetection 的鲁棒性基准测试工具链由三个层次构成:底层的Corrupt数据变换(mmdet/datasets/transforms/transforms.py)负责施加损坏,中间的 test_robustness.py 负责批量调度评测,顶层的 robustness_eval.py 负责汇总输出 P/mPC/rPC。这套工具可无缝复用到你训练好的任意 MMDetection 模型上,是衡量模型在恶劣环境下部署可靠性的标准实践。
【免费下载链接】mmdetectionOpenMMLab Detection Toolbox and Benchmark项目地址: https://gitcode.com/gh_mirrors/mm/mmdetection
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考