MMCV-Registry类代码详解(1)

目录

1.功能简介

2.初始化函数

参数说明:

构造函数优先级:

2.1self.infer_scope()方法

2.2_add_children()方法


源码在工程中的路径为mmcv/utils/registry.py,可对照源码阅读本文。

1.功能简介

简单地说,Registry类实现了字符串到类的一种映射。目的是仅使用字符串(例如某个模型的名字)来方便快捷地创建一个类实例。源码注释中给了这么一个例子:

"""
Example:
        >>> MODELS = Registry('models')
        >>> @MODELS.register_module()
        >>> class ResNet:
        >>>     pass
        >>> resnet = MODELS.build(dict(type='ResNet'))
"""

符号@表示装饰器,涉及Python的一些语法,可自行学习。在@MODELS.register_module()后定义模型,可理解为模型已经被MODELS.register_module()方法修饰,修饰过的模型可通过 MODELS.build()方法使用模型名称直接创建实例,具体使用实例可参考MMdetection自定义backbone。

2.初始化函数

"""
Args:
    name (str): Registry name.
    build_func(func, optional): Build function to construct instance from
        Registry, func:`build_from_cfg` is used if neither ``parent`` or
        ``build_func`` is specified. If ``parent`` is specified and
        ``build_func`` is not given,  ``build_func`` will be inherited
        from ``parent``. Default: None.
    parent (Registry, optional): Parent registry. The class registered in
        children registry could be built from parent. Default: None.
    scope (str, optional): The scope of registry. It is the key to search
        for children registry. If not specified, scope will be the name of
        the package where class is defined, e.g. mmdet, mmcls, mmseg.
        Default: None.

"""
def __init__(self, name, build_func=None, parent=None, scope=None):
    self._name = name
    self._module_dict = dict()
    self._children = dict()
    self._scope = self.infer_scope() if scope is None else scope

    # self.build_func will be set with the following priority:
    # 1. build_func
    # 2. parent.build_func
    # 3. build_from_cfg
    if build_func is None:
        if parent is not None:
            self.build_func = parent.build_func
        else:
            self.build_func = build_from_cfg
    else:
        self.build_func = build_func
    if parent is not None:
        assert isinstance(parent, Registry)
        parent._add_children(self)
        self.parent = parent
    else:
        self.parent = None

参数说明:

name(字符串类型):Registry类名称,例如源码示例中的'model';

build_func(函数类型,可选):构造Registry类实例的构造函数;

parent(Registry类型,可选,默认值为None):在子类中注册过的类,可以利用子类的父类的构造函数构建实例;

scope(字符串类型,可选,默认值为None):Registry类的作用域。如果未指定,作用域会是该类定义的库的名称,例如mmdet,mmcls,mmseg等。

构造函数优先级:

构造函数会按照如下优先级进行设置:

1. 参数中传入的build_func;

2. 父类的build_func;

3. 从配置文件中获取设置信息。

在初始化函数中出现了self.infer_scope()_add_children()方法,接下来依次进行说明。

2.1self.infer_scope()方法

功能:推测registry的作用域,返回registry被定义的的库的名称。

源码中提供了一个示例:

"""
Example:
    # in mmdet/models/backbone/resnet.py
    >>> MODELS = Registry('models')
    >>> @MODELS.register_module()
    >>> class ResNet:
    >>>     pass
    The scope of ``ResNet`` will be ``mmdet``.
"""

源码比较简单,而且涉及其他方法,不再展开,只需要知道功能就可以。

2.2_add_children()方法

参数:作为子类的Registry的实例对象。

功能:将参数中传入的Registry实例对象,根据其作用域被当做子类添加,父类registry可以从子类registry创建对象。

源码解析:

def _add_children(self, registry):
    # 判断传入的registry是不是Registry类,不是则报错
    assert isinstance(registry, Registry)
    # 判断传入的registry作用域是否为None,为None则报错
    assert registry.scope is not None
    # 若传入registry的作用域已经在self._children字典中,存在则报错
    assert registry.scope not in self.children, \
        f'scope {registry.scope} exists in {self.name} registry'
    # 将registry作用域作为键,registry作为值存入self._children字典中
    self.children[registry.scope] = registry

 注意:self.children方法就是返回self._children字典,类似用法的方法还有name,scope,module_dict。

 源码提供的示例:

"""
Example:
    >>> models = Registry('models')
    >>> mmdet_models = Registry('models', parent=models)
    >>> @mmdet_models.register_module()
    >>> class ResNet:
    >>>     pass
    >>> resnet = models.build(dict(type='mmdet.ResNet'))
"""

首先,创建了一个Registry类的实例models;

然后又创建了一个Registry类的实例mmdet_models,并将models实例(类型为Registry类)传递给形参parent,此时,在初始化函数中,如下代码会调用父类(即models)的_add_children()方法,将mmdet_models添加到models._children中:

if parent is not None:
    assert isinstance(parent, Registry)
    parent._add_children(self)
    self.parent = parent
else:
    self.parent = None

注意,此时的传入_add_children()方法中的self参数是指实例对象mmdet_models;

通过子类mmdet_models修饰,定义网络模型;

通过父类models从子类mmdet_models创建模型实例。

本期内容先写到这里,后期再继续更新剩余内容……

你可能感兴趣的:(目标检测,MMdetection,python,目标检测,深度学习)