BEV感知:MMCV/MMDetection 系列框架的注册器(Registry)插件化设计

BEV感知:MMCV/MMDetection 系列框架的注册器(Registry)插件化设计

MMCV/MMDetection 核心:Registry 注册器插件化完整解析

MM 系列(mmcv、mmdet、mmseg、mmcls 等)整套生态完全基于 Registry 实现插件化、模块化、可配置化,是整个框架最底层、最核心的解耦设计,实现「代码实现与配置文件解耦」,新增模型 / 数据集 / 损失无需修改框架主逻辑,仅注册即可通过 config 调用。

一、Registry 本质作用

  1. 全局字典容器:维护{name: class/func}映射表;

  2. 装饰器注册:用@registry.register_module()把自定义类 / 函数存入容器;

  3. 统一构建接口registry.build(cfg)读取配置字典,自动实例化对应模块;

  4. 插件化核心:新增组件不用改工厂类、不用写大量 if-else 判断,完全开闭原则。

对比传统硬编码 vs Registry

传统写法(耦合难扩展)

def build_model(cfg): if cfg.type == "FasterRCNN": return FasterRCNN(cfg) elif cfg.type == "YOLO": return YOLO(cfg) # 每新增模型都要改此处,臃肿难维护

Registry 写法(插件化)

# 统一入口,永远不用修改 def build_model(cfg): return MODELS.build(cfg)

二、Registry 基础源码结构(mmcv/registry.py)

1. 核心类Registry

关键属性:

  • _name:注册器名称(如modelsdatasetsbackboneslosses

  • _module_dict:核心存储字典{str: class}

关键方法:

  1. register_module(name=None, force=False):装饰器,注册类 / 函数

  2. get(name):根据名字取出类

  3. build(cfg, *args, **kwargs):配置驱动实例化模块

  4. __contains____iter__:支持判断、遍历已注册模块

2. 全局常用注册器(MMDetection 内置)

from mmcv.ops import Registry # 检测器主模型 MODELS = Registry('models') # 骨干网络 BACKBONES = Registry('backbone') # 颈部网络(FPN、PAFPN) NECKS = Registry('neck') # 检测头(RPN、RoIHead、YOLOHead) HEADS = Registry('head') # 损失函数 LOSSES = Registry('loss') # 数据集 DATASETS = Registry('dataset') # 数据增强流水线 PIPELINES = Registry('pipeline') # 优化器 OPTIMIZERS = Registry('optimizer') # 学习率调度器 LR_SCHEDULERS = Registry('lr_scheduler')

三、完整使用流程:注册 → 构建 → config 调用

步骤 1:定义 Registry 容器

from mmcv import Registry # 创建骨干网络注册器 BACKBONES = Registry("backbone")

步骤 2:装饰器注册自定义模块(两种写法)

方式 1:默认以类名小写注册

@BACKBONES.register_module() class ResNet: def __init__(self, depth): self.depth = depth

等价注册 key:resnet

方式 2:自定义注册名称(多别名、重名覆盖)

@BACKBONES.register_module(name="MyResNet", force=True) class ResNet: pass

配置中type="MyResNet"即可调用

函数也可注册(loss、aug 常用)

@LOSSES.register_module() def l1_loss(pred, target): return abs(pred - target).mean()

步骤 3:通过 Registry.build () 基于配置实例化

config 本质是字典,约定 **type字段对应注册名 **,其余字段为构造参数:

cfg = dict( type="ResNet", depth=50 ) # 自动查找 ResNet 类并实例化 backbone = BACKBONES.build(cfg) print(backbone.depth) # 50

步骤 4:嵌套构建(MMDet 最常用,多层 Registry 嵌套)

检测模型由 backbone + neck + head 组成,嵌套 cfg 自动递归构建:

model_cfg = dict( type="FasterRCNN", backbone=dict(type="ResNet", depth=50), neck=dict(type="FPN", in_channels=[256,512,1024]), rpn_head=dict(type="RPNHead", num_anchors=3) ) model = MODELS.build(model_cfg)

build内部会递归解析子 dict,调用对应子 Registry 构建子模块。

四、Registry.build 底层执行逻辑

简化源码流程:

def build(self, cfg, *args, **kwargs): # 1. 深拷贝 cfg,防止修改原配置 cfg = cfg.copy() # 2. 取出 type 字段,对应注册名称 module_type = cfg.pop("type") # 3. 从注册表获取对应类 module_cls = self.get(module_type) # 4. 递归构建内部子模块(dict/list 自动 build) for key, val in cfg.items(): if isinstance(val, dict) and "type" in val: cfg[key] = build_from_cfg(val, self) elif isinstance(val, list): cfg[key] = [build_from_cfg(v, self) if isinstance(v, dict) and "type" in v else v for v in val] # 5. 实例化并返回 return module_cls(*args, **cfg, **kwargs)

核心函数:build_from_cfg(cfg, registry),全局统一构建入口。

MMCV Registry 在 BEV 感知(PETR)中的分层落地与完整应用

BEVFormer、PETR 均基于MMDetection3D + MMCV Registry实现全链路插件化,针对多视图 BEV 复杂 Transformer 架构做了多层级细分注册器,把 2D 图像支路、视图变换、BEV 编码器、时序注意力、3D 检测头、位置编码全部解耦;仅修改 config 即可替换任意模块,是自动驾驶 BEV 工程化的核心基础。

一、BEV 感知专属分层注册器体系(MMDet3D 扩展)

MMDet3D 在原生 MMCV 注册器基础上,新增大量 BEV/Transformer 专用注册表,按网络层级隔离命名空间,避免模块重名冲突:

1. 顶层全局注册表(继承 MMCV 原生)

# mmdet3d/registry.py from mmcv import Registry # 总模型容器(所有检测器、BEV主干、Transformer、Head都归属MODELS) MODELS = Registry('models') # 数据集、数据增强流水线(多相机图像预处理、标定解码) DATASETS = Registry('dataset') PIPELINES = Registry('pipeline') # 损失(3D分类、3D框回归、深度损失、Occupancy占用损失) LOSSES = Registry('loss') # 优化器、学习率调度 OPTIMIZERS = Registry('optimizer') LR_SCHEDULERS = Registry('lr_scheduler')

二、Registry 在 BEV 算法中解决的三大工程痛点

1. 模块化消融实验(工业 BEV 迭代刚需)

仅修改 config 的type字段,无需改动一行代码,快速对比不同组件:

  • 骨干网络:type=ResNet/type=Swin/type=ConvNeXt

  • 视图变换:LSSViewTransform/PETRViewTransform/BEVFormerSampling

  • Transformer 层:BEVFormerLayer(时序)/PETRLayer(纯空间)

  • 位置编码:2D 平面编码 / 3D 栅格编码 / 相机光线编码

2. 多任务分支统一扩展(检测 / 分割 / 占用预测)

同一套注册体系兼容多任务头:

# 3D检测头 pts_bbox_head=dict(type='BEVFormerHead') # 占用预测头(Occ) occ_head=dict(type='BEVFormerOccHead') # 道路分割头 seg_head=dict(type='BEVSegHead')

全部注册至HEADS注册表,主检测器通过 cfg 按需构建分支。

3. 自定义插件零侵入框架(自动驾驶定制化开发)

新增自研 BEV 模块仅两步,不修改 mmdet3d 底层代码:

  1. 编写自定义类,用对应注册器装饰;

  2. config 添加custom_imports自动导入触发注册。

实战示例:自定义轻量化 BEV 注意力层

# custom_bev_layer.py from mmdet3d.registry import TRANSFORMER_LAYERS # 注册到Transformer单层注册表 @TRANSFORMER_LAYERS.register_module(name='LightBEVLayer') class LightBEVLayer(BaseTransformerLayer): """自研轻量化可变形注意力""" def forward(self, bev_feat, query_embed, ...): pass

config 导入生效:

custom_imports = dict( imports=['projects.custom.custom_bev_layer'], allow_failed_imports=False ) # 直接替换原有BEVFormerLayer transformer.encoder.layers=[dict(type='LightBEVLayer')]