Vision Mamba 项目中的 Detectron2 Evaluation 评估模块:从 DatasetEvaluator 到 COCO/LVIS 全量评估体系
Vision Mamba 项目中的 Detectron2 Evaluation 评估模块:从 DatasetEvaluator 到 COCO/LVIS 全量评估体系
本篇文章以仓库 det/docs/modules/evaluation.rst 所索引的 detectron2.evaluation 模块为核心,系统讲解 Vision Mamba(Vim)检测框架中用于模型性能评估的完整技术栈:评估器的抽象基类、评估驱动的统一入口、面向 COCO / LVIS / Panoptic / 语义分割 / Pascal VOC / Cityscapes 的具体评估器实现,以及评估结果如何接入训练流程与命令行。读者读完本文后,将掌握在 detectron2 系框架内为任意检测/分割数据集接入评估器、运行离线评测、解读评估结果,并复现本仓库 det/scripts 下 Vim 检测模型评估脚本的完整能力。
评估模块全景:detectron2.evaluation 包的构成
本仓库的评估代码全部位于 det/detectron2/evaluation/ 目录,该目录的包入口 init.py 统一导出了全部对外 API:
from .cityscapes_evaluation import CityscapesInstanceEvaluator, CityscapesSemSegEvaluator
from .coco_evaluation import COCOEvaluator
from .rotated_coco_evaluation import RotatedCOCOEvaluator
from .evaluator import DatasetEvaluator, DatasetEvaluators, inference_context, inference_on_dataset
from .lvis_evaluation import LVISEvaluator
from .panoptic_evaluation import COCOPanopticEvaluator
from .pascal_voc_evaluation import PascalVOCDetectionEvaluator
from .sem_seg_evaluation import SemSegEvaluator
from .testing import print_csv_format, verify_results
从源码结构看,整个评估体系可分为四个层次:
- 抽象基类与驱动入口:
DatasetEvaluator(评估器基类)、DatasetEvaluators(多评估器聚合)、inference_on_dataset(推理+评估统一驱动)与inference_context(模型推理模式上下文),见 evaluator.py; - 具体任务评估器:
COCOEvaluator、LVISEvaluator、RotatedCOCOEvaluator、COCOPanopticEvaluator、SemSegEvaluator、PascalVOCDetectionEvaluator、CityscapesInstanceEvaluator、CityscapesSemSegEvaluator; - 性能加速与工具函数:
fast_eval_api.py中的COCOeval_opt(C++ 加速的 COCO 评估实现)、testing.py中的print_csv_format与verify_results; - 引擎集成层:
DefaultTrainer通过EvalHook在训练中周期性调用评估,tools/train_net.py与tools/plain_train_net.py提供build_evaluator工厂函数。
评估器抽象基类:DatasetEvaluator 的三个生命周期方法
所有具体评估器都继承自 DatasetEvaluator,其设计思想是"推理与评估解耦":inference_on_dataset 负责把模型跑完整个测试集,而 DatasetEvaluator 负责逐步累积模型输入/输出并在最后汇总出指标。基类定义了三个可重写的方法:
| 方法 | 职责 | 说明 |
|---|---|---|
reset() |
开始一轮评估前的准备工作 | 在每个评估轮次开始前调用,典型实现是清空 self._predictions 列表 |
process(inputs, outputs) |
处理一对输入与输出 | 若输入输出包含 batch,可按 for input_, output in zip(inputs, outputs) 逐条消费 |
evaluate() |
汇总全部结果并返回指标字典 | 返回格式为 {task_name: {metric_name: score}},例如 {"bbox": {"AP50": 80}} |
基类注释中特别指出,evaluate() 返回的字典格式约定是 train_net.py 所期望的:key 为任务名(如 bbox),value 为指标名到分数的映射。具体评估器可以返回任意格式的字典,只要调用方能够处理即可。
DatasetEvaluators:多评估器聚合分发
DatasetEvaluators 是一个包装类,把多个评估器组合成一个,将 reset()、process()、evaluate() 依次分发给内部所有评估器。其 evaluate() 会合并各评估器返回的结果,且断言不同评估器不得产生同名的 key,避免结果冲突。这为"一个数据集同时评估多个任务"提供了组合能力——例如 COCO Panoptic 场景中同时跑 COCOEvaluator 与 COCOPanopticEvaluator。
推理与评估的统一驱动:inference_on_dataset
inference_on_dataset 是整个评估流程的核心入口函数,它同时完成三件事:推理、指标评估、推理速度基准测试。其签名与行为要点如下:
- model:可调用对象,接收 data_loader 产出的一个元素并返回输出;若是
nn.Module,会通过inference_context临时切到eval模式(inference_context 会在退出后恢复原训练状态); - data_loader:有确定长度的可迭代对象,其元素作为模型输入;
- evaluator:传入
DatasetEvaluator、评估器列表或None。传None时内部创建一个空操作评估器,仅做推理速度基准而不评估任何指标; - callbacks:可选的回调字典,支持
on_start、before_inference、after_inference、on_end四个阶段钩子。
流程上的关键实现细节(对应 evaluator.py):
- 进入
torch.no_grad()上下文,避免推理产生梯度开销; - 预热机制:
num_warmup = min(5, total - 1),前若干个 batch 只跑不计时,用于排除 CUDA 初始化、显存分配等干扰,从预热结束处重新起表计时; - 分项计时:分别统计
total_data_time(数据加载)、total_compute_time(模型计算,GPU 下会调用torch.cuda.synchronize()保证计时准确)、total_eval_time(评估器process); - 周期性日志:每 5 秒至少输出一次
Dataloading / Inference / Eval / Total s per iter与ETA; - 结束日志格式为
Total inference time: {mm:ss} ({x.xxxxxx} s / iter per device, on {n} devices),该格式注释标明会被 grep 解析,可用于脚本化结果提取; - 返回值即
evaluator.evaluate()的结果,主进程之外的 rank 返回None时统一替换为空字典{}。
COCOEvaluator:bbox / segm / keypoints 三类任务的通用评估器
COCOEvaluator 是使用最广泛的评估器,其定位是"在 COCO 指标之外,还能支持任意边界框检测、实例分割或关键点检测数据集"。指标范围 0~100(区别于 0~1),当无法计算(如没有预测)时返回 -1 或 NaN。
构造参数详解
其构造函数(L47-L96)接收以下参数:
| 参数 | 含义与要点 |
|---|---|
dataset_name |
被评估数据集的名字。数据集元数据必须包含 json_file(COCO 格式标注路径),或者该数据集处于 detectron2 标准格式、可自动转换为 COCO 格式 |
tasks |
可评估的任务元组,取值 "bbox"、"segm"、"keypoints"。默认从预测结果自动推断(_tasks_from_predictions 会扫描预测中是否含 segmentation 与 keypoints 字段,见 L210-L220) |
distributed |
默认 True,表示收集所有 rank 的结果并在主进程执行评估;False 则只评估当前进程 |
output_dir |
可选,用于转储预测结果,包含两个文件:instances_predictions.pth(torch.load 可加载的原始预测)与 coco_instances_results.json(COCO 结果格式的 json) |
max_dets_per_image |
每张图最大检测数上限,COCO 默认 100;内部会重排为 COCOeval 需要的 <a href="https://link.gitcode.com/i/e42fbe51ea26c4c28dac928b81fe0276" target="_blank">1, 10, max_dets_per_image] 形式([L106-L115),可用于 AP fixed / AP pool 等需要更大上限的指标 |
use_fast_impl |
是否使用快速但非官方的 AP 实现 COCOeval_opt;该实现结果与官方 API 非常接近,但更耗内存,论文发表建议仍用官方 API |
kpt_oks_sigmas |
关键点 OKS 计算所需 sigmas,为空时使用 COCO 默认值;否则长度应与 ROI_KEYPOINT_HEAD.NUM_KEYPOINTS 一致 |
allow_cached_coco |
是否复用前次验证生成的缓存 COCO json,更换验证数据时应置为 False |
评估流程与输出
process()(L157-L175)从每个输入的 image_id 与输出的 instances / proposals 构建预测记录;evaluate()(L177-L208)负责跨进程聚合(comm.gather)、转储预测文件,并分别走 _eval_box_proposals(AR 指标)与 _eval_predictions(AP 指标)两条分支。
生成的指标集(见 _derive_coco_results,L323-L389):
- bbox / segm:
AP、AP50、AP75、APs、APm、APl; - keypoints:
AP、AP50、AP75、APm、APl; - 当类别数大于 1 时,额外输出每个类别的
AP-{category_name}逐类 AP,并用 tabulate 打印成管道表格。
值得注意的是 instances_to_coco_json 中 mask 用 RLE 编码(counts 需 decode 为 UTF-8 字符串以适配 json 序列化),关键点坐标需减 0.5 与 COCO 标注格式对齐——这是评估精度正确性的关键细节。
其他内置评估器一览
包内还提供了面向不同数据协议与任务类型的评估器:
- LVISEvaluator:使用 LVIS 官方评估 API 评估 proposal 与实例检测/分割,要求数据集元数据提供 LVIS 格式
json_file,支持bbox/segm任务,max_dets_per_image默认上限为 300(LVIS 数据集约定); - COCOPanopticEvaluator:基于 PanopticAPI 评估 Panoptic Quality,并将全景分割预测保存到
output_dir;内部会把连续类别 id 映射回数据集的原始 id(区分 thing / stuff,见 L53-L60); - SemSegEvaluator 与 CityscapesInstanceEvaluator / CityscapesSemSegEvaluator:面向语义分割与 Cityscapes 数据集;
- RotatedCOCOEvaluator:面向旋转框检测(对应
RRPN); - PascalVOCDetectionEvaluator:VOC 数据集的 mAP 评估;
- fast_eval_api.py 中的
COCOeval_opt:把官方 COCO API 的evaluateImg()与accumulate()用 C++ 实现加速,绕开 Python 层的evalImgs计算瓶颈,且直接输出与官方一致的 precision/recall 数据结构。
评估结果的格式化与校验工具
testing.py 提供三个高频工具:
print_csv_format(results)(L9-L28):将{task: {metric: score}}形式的评估结果打印为以copypaste:前缀开头的 CSV 行,便于直接粘贴进表格,且自动跳过含-的逐类指标;verify_results(cfg, results)(L31-L65):读取cfg.TEST.EXPECTED_RESULTS中声明的[task, metric, expected, tolerance]列表,逐一比对实际指标,超出容差即打印错误并以sys.exit(1)失败退出,常用于回归测试;flatten_results_dict(results)(L68-L85):把层级嵌套的结果字典展开为"k1/k2/k3": v形式的扁平字典,便于 TensorBoard 等标量记录。
与训练引擎的集成:EvalHook 与 build_evaluator
评估并非只能手动调用。在 DefaultTrainer 中,训练流程通过 hooks.EvalHook(cfg.TEST.EVAL_PERIOD, test_and_save_results) 周期性触发评估;其默认实现要求子类实现 build_evaluator(cfg, dataset_name)(L563-L576),并在 test() 中对 cfg.DATASETS.TEST 中的每个数据集执行 inference_on_dataset(model, data_loader, evaluator)(L619)。
相关配置项集中在 det/detectron2/config/defaults.py:
TEST.EVAL_PERIOD(默认 0):训练中每隔多少 step 评估一次,0 表示关闭;TEST.EXPECTED_RESULTS(默认空列表):形如[['bbox', 'AP', 38.5, 0.2]]的期望结果校验项,配合verify_results使用;INPUT.MIN_SIZE_TEST(默认 800)/INPUT.MAX_SIZE_TEST(默认 1333):测试期图像缩放约束,直接影响推理与评估结果。
两种官方入口脚本
- tools/train_net.py 的
build_evaluator依据数据集元数据中的evaluator_type自动选择评估器:sem_seg/coco_panoptic_seg挂SemSegEvaluator,coco挂COCOEvaluator,cityscapes_instance/cityscapes_sem_seg/pascal_voc/lvis分别对应各自评估器,多个评估器时用DatasetEvaluators聚合;默认输出目录为cfg.OUTPUT_DIR/inference; - tools/plain_train_net.py 提供无框架依赖的自写训练循环示范,其
do_test(cfg, model)手动构建 test loader 与评估器并调用inference_on_dataset,随后在主进程打印 CSV 格式结果。
在 Vision Mamba(VimDet)项目中的实际应用
本仓库将上述评估体系用于 Vision Mamba 骨干网的检测任务评测。以 det/scripts/eval_vim_tiny_vimdet.sh 为例,离线评估命令为:
python3 tools/lazyconfig_train_net.py \
--config-file /mnt/bn/lianghuidata/Vim/det/projects/ViTDet/configs/COCO/cascade_mask_rcnn_vimdet_t_100ep_adj1.py \
--eval-only train.init_checkpoint="/mnt/bn/lianghuidata/Vim/det/released_ckpt/vimdet.pth"
其中 --eval-only 让训练脚本跳过训练直接进入评估路径,train.init_checkpoint 覆盖配置文件中的初始权重为已发布的 VimDet 检查点。对应配置 cascade_mask_rcnn_vimdet_t_100ep.py 通过继承 base 配置并设置 embed_dim = 192、depth = 24 等参数定义 ViM-Tiny 骨干,评估时会经由 lazyconfig_train_net 内部的 build_evaluator 为 COCO 验证集构造 COCOEvaluator,最终输出 bbox / segm 的 AP 指标族。这正体现了"评估模块复用 + 骨干网络可插拔"的工程组织方式:评估链路完全复用 detectron2 标准体系,Vim 只需作为 backbone 实现接入(见 det/detectron2/modeling/backbone/vim.py)。
测试验证与一致性保证
仓库测试对评估模块的正确性做了两层保障:
- 评估器接口测试:在 det/tests/data/test_coco_evaluation.py 中,直接实例化
COCOEvaluator,构造包含随机pred_boxes、scores与已知类别 id 的Instances,调用process()后验证非法类别 id 会触发断言——确保类别映射的边界行为可预期; - 快慢实现一致性测试:同一文件的
test_fast_eval对比官方COCOeval与加速版COCOeval_opt的precision/recall,断言差异小于 1e-4,为use_fast_impl=True的工程加速提供了数值正确性背书。
小结:一套可复用的评估抽象
detectron2.evaluation 模块的核心价值在于将"跑推理"与"算指标"彻底解耦:DatasetEvaluator 三方法抽象让新评估器只需关注数据累积与指标汇总,inference_on_dataset 统一承担预热、计时、聚合与回调,而 build_evaluator 工厂让数据集类型到评估器的映射开箱即用。无论是复现 det/scripts 中的 Vim 检测评估,还是为自定义数据集接入 COCO 风格指标,都可以直接复用本模块,并将其作为了解 detectron2 评估体系设计的最佳参考。