mmcv之Registry类解读


前言

 本文主要介绍mmcv的Registry类。建议读者先配置下mmcv环境:mmcv源码安装。我相信读者大多数对于Registry类有点儿迷,主要涉及python中装饰器的知识。因此,本文尽量做到面面俱到,会简要介绍一部分装饰器的用法。

1、Registry作用

 Registry类可以简单理解为一个字典,举个例子,在mmdetection中,比如说创建了名为dataset的注册器对象,则注册器dataset中包含(CocoDataset类,VOCDataset类,Lvis类);同理,detector注册器对象中包含(FasterRcnn类,SSD类,YOLO类等)。因此,Registry对象完全可以理解为一个字典,里面存储着同系列的类

2、源码分析

 Registry虽说是一个字典,但是得实现增删改查的功能。即往字典中添加新的类;即查询字典中是否有这个类。那么在Registry类中如何实现这些功能呢?

2.1.初始化部分

class Registry:
    """A registry to map strings to classes.

    Args:
        name (str): Registry name.
    """

    def __init__(self, name):
        self._name = name
        self._module_dict = dict()

    def __len__(self):
        return len(self._module_dict)

    def __contains__(self, key):
        return self.get(key) is not None

    def __repr__(self):
        format_str = self.__class__.__name__ + \
                     f'(name={self._name}, ' \
                     f'items={self._module_dict})'
        return format_str

 这部分比较简单,就是传入了一个name并内部定义了一个self._module_dict字典

2.2.查

 查找self._module_dict存在一个某个类 实现也比较简单:

    def get(self, key):
        return self._module_dict.get(key, None)

 主要借助get方法,若有key则返回对应的value;若无key则返回None。

2.3.增

 增的方法mmdetection中提供了两种方式,区别是方法_register_module()是否指定了module参数:
在这里插入图片描述

 该函数主要往self._module_dict中添加。注意,往字典里面添加的是类。以下代码包含了上图中两种方式。这里我截取了核心代码:

    def _register_module(self, module_class, module_name=None, force=False):

        if module_name is None:
            module_name = module_class.__name__
        if isinstance(module_name, str):
            module_name = [module_name]
            
        self._module_dict[name] = module_class

    def register_module(self, name=None, force=False, module=None):
		# 若指定module,则执行if语句,执行完后完成module类添加
        if module is not None:
            self._register_module(
                module_class=module, module_name=name, force=force)
            return module

        # 若没有指定module,则执行_register函数。
        def _register(cls):
            self._register_module(
                module_class=cls, module_name=name, force=force)
            return cls

        return _register

 我将分两小节来介绍这两种方式。

2.3.1 指定module参数

  现在我们想往字典self._module_dict字典中添加新类。最容易想到方法就是下面这样:

if __name__ == '__main__':
    backbones = Registry('backbone')
    class MobileNet:
        pass
    backbones.register_module(module=MobileNet)
    print(backbones)

 即直接指定参数module=MobileNet。内部通过self._module_dict[name]=module_class完成注册。

2.3.2 不指定module参数

 上节提供方法完全可以,但是在利用mmdetection拓展新模型的时候,如果每次创建完一个类之后,然后通过上述方法注册,着实不方便。势必会影响mmdetection拓展性。而装饰器可以很方便给类拓展新功能,装饰器有机会我会单独出一篇文章,
 这里简单记住装饰器用法:funB = funA(funB),即被装饰函数funB,经过装饰器funA的装饰,中间可能发生了一些其他事情,最终funA的return funB。
 首先看用法:比如我想注册ResNet。

if __name__ == '__main__':
    backbones = Registry('backbone')
    @backbones.register_module()
    class ResNet:
        pass
    print(backbones)

 这里内部实质上经过了下面函数:

        def _register(cls):
            self._register_module(
                module_class=cls, module_name=name, force=force)
            return cls

在这个过程中,funB相当于cls。而_register函数相当于funA。中间往self._module_dict字典中注册了类cls。然后return cls。即funB

总结

 本文主要介绍了Registry类的增查功能。若有问题,欢迎留言交流+Q:2541612007。

Supongo que te gusta

Origin blog.csdn.net/wulele2/article/details/114186921
Recomendado
Clasificación