python通过注册表动态管理组件

mmengine.registry 是一个在多个开源项目(如 MMEngine 和 MM系列工具包,例如 MMDetection、MMClassification 等)中使用的模块化管理机制,旨在通过注册表动态管理不同的组件,例如模型、算法、损失函数或插件等。这个机制极大地增强了项目的灵活性和扩展性。

1 基本概念

1.1 Registry 类

Registry是一个存储映射关系的容器,它将字符串类型的键(通常是组件的名字)映射到具体的 Python 对象(如类或函数)。使用注册表的主要优势是可以在运行时动态创建对象,从而实现高度可配置和可扩展的设计。

1.2 核心功能

  1. 注册机制

    提供了一个 register_module 方法,允许开发者将类或函数注册到注册表中。这通常通过装饰器的形式实现,使得代码更加简洁和直观。注册时可以指定一个或多个名称作为键,关联到相应的 Python 类或函数。

  2. 动态创建实例

    注册表可以使用 build 方法根据配置动态创建类的实例。这通常需要配置信息包括键名 type(对应注册的名称)和其他用于初始化对象的参数。通过读取配置文件(通常是 JSON 或 YAML 格式),可以在不修改代码的情况下轻松切换使用的组件或调整参数。

  3. 作用域管理

    在某些复杂的应用场景中,Registry 可能需要处理多个域(scope)下的注册问题,例如不同的模块可能需要有各自独立的注册表。Registry 类可以通过指定 scope 参数来实现作用域管理,使得同一个名字在不同的作用域下可以关联到不同的对象。

  4. 继承

    注册表可以设置父注册表,使得查找过程可以在当前注册表未找到对应键值时回溯到父注册表中查找。这为模块间的依赖提供了方便,也允许更灵活的重载和扩展。

2 实现示例

2.1 简化的Registry类实现

展示了如何定义这个类,以及如何注册和创建对象:

python 复制代码
class Registry:
    def __init__(self, name, scope=None, parent=None):
        self.name = name
        self.scope = scope
        self.parent = parent
        self._module_dict = {}

    def register_module(self, name=None):
        def _register(cls):
            module_name = name or cls.__name__
            if module_name in self._module_dict:
                raise KeyError(f'{module_name} is already registered in {self.scope}::{self.name}')
            self._module_dict[module_name] = cls
            return cls
        return _register

    def get(self, name):
        if name in self._module_dict:
            return self._module_dict[name]
        elif self.parent:
            return self.parent.get(name)
        else:
            raise KeyError(f'{name} is not registered in {self.scope}::{self.name} and no parent registry to fallback.')

    def build(self, cfg):
        module_name = cfg['type']
        module_cls = self.get(module_name)
        return module_cls(**{k: v for k, v in cfg.items() if k != 'type'})

2.2 这个注册表类

python 复制代码
from torch import nn

# 创建父注册表
MODELS = Registry('models', scope='mmengine')

# 注册一个模块到父注册表
@MODELS.register_module()
class ResNet(nn.Module):
    def __init__(self, layers):
        self.layers = layers

    def forward(self, x):
        return x

# 创建子注册表,指定 MODELS 为父注册表
DETECTORS = Registry('detectors', scope='mmengine', parent=MODELS)

# 注册一个模块只到子注册表
@DETECTORS.register_module()
class FasterRCNN(nn.Module):
    def __init__(self, num_classes):
        self.num_classes = num_classes

    def forward(self, x):
        return x

# 从子注册表构建 ResNet 实例,尽管它是在父注册表中注册的
resnet_instance = DETECTORS.build({'type': 'ResNet', 'layers': 50})
print(resnet_instance)

# 直接从子注册表构建 FasterRCNN 实例
fasterrcnn_instance = DETECTORS.build({'type': 'FasterRCNN', 'num_classes': 80})
print(fasterrcnn_instance)
相关推荐
Rick19934 分钟前
Spring AI 如何进行权限控制
人工智能·python·spring
码界筑梦坊4 分钟前
302-基于Python的安卓应用市场数据可视化分析推荐系统
开发语言·python·信息可视化·毕业设计·fastapi
齐鲁大虾14 分钟前
新人编程语言选择指南
javascript·c++·python·c#
Absurd58723 分钟前
Redis如何限制列表最大长度_利用LTRIM指令截断List保留最新记录
jvm·数据库·python
2401_8822737223 分钟前
SQL函数面试题解析_函数性能与设计考点
jvm·数据库·python
knight_9___26 分钟前
RAG面试题5
人工智能·python·agent·rag
a95114164227 分钟前
mysql查询分析中如何快速识别全表扫描_通过EXPLAIN中的type列检查
jvm·数据库·python
Irene199130 分钟前
使用Python进行文件读写的API或方法及其注意事项
python·文件读写
weixin_4249993630 分钟前
mysql如何防止索引被错误使用_mysql查询计划强制约束
jvm·数据库·python
旦莫1 小时前
测试工程师如何用AI生成测试用例?我的提示词模板分享
人工智能·python·测试开发·自动化·测试用例·ai测试