本文主要介绍mmcv的Registry类。建议读者先配置下mmcv环境:mmcv源码安装。我相信读者大多数对于Registry类有点儿迷,主要涉及python中装饰器的知识。因此,本文尽量做到面面俱到,会简要介绍一部分装饰器的用法。
Registry类可以简单理解为一个字典,举个例子,在mmdetection中,比如说创建了名为dataset的注册器对象,则注册器dataset中包含(CocoDataset类,VOCDataset类,Lvis类);同理,detector注册器对象中包含(FasterRcnn类,SSD类,YOLO类等)。因此,Registry对象完全可以理解为一个字典,里面存储着同系列的类。
Registry虽说是一个字典,但是得实现增删改查的功能。增即往字典中添加新的类;查即查询字典中是否有这个类。那么在Registry类中如何实现这些功能呢?
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字典。
查找self._module_dict存在一个某个类 实现也比较简单:
def get(self, key):
return self._module_dict.get(key, None)
主要借助get方法,若有key则返回对应的value;若无key则返回None。
增的方法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
我将分两小节来介绍这两种方式。
现在我们想往字典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完成注册。
上节提供方法完全可以,但是在利用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类的增查功能。若有问题欢迎+vx:wulele2541612007,拉你进群探讨交流。