文章目录

  • 前言
  • 为什么使用`Register`或`Registry`?
  • `Register`机制怎么用?
    • 定义`Register`
    • 使用`Register`
      • 使用装饰器注册模块
      • 将Register实例化,使用Register
  • 总结

前言

在之前接触到的一些比较大的开源工作中,如timm,detectron2,mmlab等项目,常常会遇见RegisterRegistry模块,中文称之为注册器注册机制。本篇Blog梳理一下注册器模块的使用机制,以及探讨为何要使用该模块。

为什么使用RegisterRegistry

在常见的CV模型中,例如分类、检测、分割等任务中,针对一个模型,(例如Faster-RCNN),可能在一个Head的基础上换多个Backbone(例如ResNet,DenseNet等)。或者说针对一套模型,可能会跑多个数据集。最简单的实现方式就是有多套代码,每套代码仅在Backbone部分或数据加载部分有差异。但是这样而言对于一个大型项目来说会过于繁琐,不够简洁,每新增一个新的模型,需要手动维护很多代码。因此,许多项目都使用了Register注册器机制。

使用Register注册器机制可以让项目易于扩展,当产品增加某个功能需要增加一些新函数或者类时,它可以保证我们可以复用之前的逻辑。

Register机制怎么用?

定义Register

首先我们需要定义一个注册器的Class,我们这里直接引用Python中的注册器模块的代码,代码示例如下所示:

class Register:    def __init__(self, registry_name):     # 可以将Register视为一个`dict`        self._dict = {}        self._name = registry_name    def __setitem__(self, key, value):        if not callable(value):            raise Exception(f"Value of a Registry must be a callable!\nValue: {value}")        if key is None:            key = value.__name__        if key in self._dict:            logging.warning("Key %s already in registry %s." % (key, self._name))        self._dict[key] = value    def register(self, target):        """Decorator to register a function or class."""# 关键函数,可以作为装饰器,注册一个函数或者一个类别。        def add(key, value):            self[key] = value            return value        if callable(target):            # @reg.register            return add(None, target)        # @reg.register('alias')        return lambda x: add(target, x)    def __getitem__(self, key):        return self._dict[key]    def __contains__(self, key):        return key in self._dict    def keys(self):        """key"""        return self._dict.keys()

使用Register

使用装饰器注册模块

首先补充一个知识点,@是python的装饰器语法糖。

@decoratedef func():pass#! 等价于func = decorate(func)

则使用Register时,可以用装饰器的方法来使用,示例如下所示:

# Define Register_funcRegister_func = Register()@Register_func.registerclass Modle1:

等价于Register_func.register(Model1),最终执行的是add(None, Model1)

@Register_func.register("model_one")class Model1:

等价于Register_func.register("model_one")(Model1),最终执行的是add("model_one", Model_1)

简而言之,Register类提供了方便的注册器来对模块进行注册。

将Register实例化,使用Register

为了更好的展示使用方式,我们定义一些简单的函数,例如加减乘除等函数,为了省略重复代码,我们就直接给他们用Register注册了。
代码示例如下所示:

注册Register。

Register_func = Register("Register_func")    @Register_func.registerdef add(x,y):    return x+y@Register_func.registerdef minus(x,y):    return x-y@Register_func.registerdef multi(x,y):    return x*y@Register_func.registerdef div(x,y):    return x/y

使用注册模块。

operation = Register_func["add"]result = operation(1,2)print(result)

总结

以上是最最基础的Register的使用方式,后续有更多有关Register的使用花活会增添到本内容中。