BEV感知:MMCV/MMDetection 系列框架的注册器(Registry)插件化设计
MMCV/MMDetection 核心:Registry 注册器插件化完整解析
MM 系列(mmcv、mmdet、mmseg、mmcls 等)整套生态完全基于 Registry 实现插件化、模块化、可配置化,是整个框架最底层、最核心的解耦设计,实现「代码实现与配置文件解耦」,新增模型 / 数据集 / 损失无需修改框架主逻辑,仅注册即可通过 config 调用。
一、Registry 本质作用
全局字典容器:维护
{name: class/func}映射表;装饰器注册:用
@registry.register_module()把自定义类 / 函数存入容器;统一构建接口:
registry.build(cfg)读取配置字典,自动实例化对应模块;插件化核心:新增组件不用改工厂类、不用写大量 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:注册器名称(如models、datasets、backbones、losses)_module_dict:核心存储字典{str: class}
关键方法:
register_module(name=None, force=False):装饰器,注册类 / 函数get(name):根据名字取出类build(cfg, *args, **kwargs):配置驱动实例化模块__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/BEVFormerSamplingTransformer 层:
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 底层代码:
编写自定义类,用对应注册器装饰;
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, ...): passconfig 导入生效:
custom_imports = dict( imports=['projects.custom.custom_bev_layer'], allow_failed_imports=False ) # 直接替换原有BEVFormerLayer transformer.encoder.layers=[dict(type='LightBEVLayer')]