在众多深度学习开源库的代码中经常出现Registry代码块,例如OpenMMlabfacebookresearchBasicSR中都使用了注册器机制。这块的代码经常会让新使用这些库的初学者感到一头雾水,本篇博客来分析一下注册器机制的原理与好处。


1. 为什么使用registry

在讲解registry原理前,我们先介绍一下,为何使用registry。registry的中文翻译是注册器。对于一个好用的深度学习代码库来说,通常都会内置多种损失函数,多种网络结构,以及多种优化器等。同时这类的库一般都支持从配置文件中,直接解析出模型结构与训练策略。那么如何优雅的从配置文件解析到具体的代码实现呢?这就是引入注册操作的意义,简而言之,注册器是为了方便找到相关模块。

2. registry代码阅读

在实现上不同代码库略有差异,但原理相同,所以这里就以BasicSR为例。

class Registry():
"""
The registry that provides name -> object mapping, to support third-party
users' custom modules.
To create a registry (e.g. a backbone registry):
.. code-block:: python
BACKBONE_REGISTRY = Registry('BACKBONE')
To register an object:
.. code-block:: python
@BACKBONE_REGISTRY.register()
class MyBackbone():
...
Or:
.. code-block:: python
BACKBONE_REGISTRY.register(MyBackbone)
""" def __init__(self, name):
"""
Args:
name (str): the name of this registry
"""
self._name = name
self._obj_map = {} def _do_register(self, name, obj, suffix=None):
if isinstance(suffix, str):
name = name + '_' + suffix assert (name not in self._obj_map), (f"An object named '{name}' was already registered "
f"in '{self._name}' registry!")
self._obj_map[name] = obj def register(self, obj=None, suffix=None):
"""
Register the given object under the the name `obj.__name__`.
Can be used as either a decorator or not.
See docstring of this class for usage.
"""
if obj is None:
# used as a decorator
def deco(func_or_class):
name = func_or_class.__name__
self._do_register(name, func_or_class, suffix)
return func_or_class return deco # used as a function call
name = obj.__name__
self._do_register(name, obj, suffix) def get(self, name, suffix='basicsr'):
ret = self._obj_map.get(name)
if ret is None:
ret = self._obj_map.get(name + '_' + suffix)
print(f'Name {name} is not found, use name: {name}_{suffix}!')
if ret is None:
raise KeyError(f"No object named '{name}' found in '{self._name}' registry!")
return ret def __contains__(self, name):
return name in self._obj_map def __iter__(self):
return iter(self._obj_map.items()) def keys(self):
return self._obj_map.keys() DATASET_REGISTRY = Registry('dataset')
ARCH_REGISTRY = Registry('arch')
MODEL_REGISTRY = Registry('model')
LOSS_REGISTRY = Registry('loss')
METRIC_REGISTRY = Registry('metric')

上面的代码为数据集,架构,网络,损失以及度量方式都创建了一个注册器对象。核心代码在register函数里,register函数使用了装饰器的设计,也就是只要在功能模块前进行@xx.register()进行装饰,就会对原有功能模块进行注册,并且最终返回原始的功能模块,不修改其原有功能。

在更下层的_do_register()可以看到,这里使用的是一个字典来执行注册操作,记录的键值对分别是模块的名称以及模块本身。这样一来,读取配置文件中的模块字符串后,我们就能够直接通过函数名或者类名找到其具体实现。

@LOSS_REGISTRY.register()
class L1Loss(nn.Module):
"""L1 (mean absolute error, MAE) loss.
Args:
loss_weight (float): Loss weight for L1 loss. Default: 1.0.
reduction (str): Specifies the reduction to apply to the output.
Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'.
""" def __init__(self, loss_weight=1.0, reduction='mean'):
super(L1Loss, self).__init__()
if reduction not in ['none', 'mean', 'sum']:
raise ValueError(f'Unsupported reduction mode: {reduction}. Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight
self.reduction = reduction def forward(self, pred, target, weight=None, **kwargs):
"""
Args:
pred (Tensor): of shape (N, C, H, W). Predicted tensor.
target (Tensor): of shape (N, C, H, W). Ground truth tensor.
weight (Tensor, optional): of shape (N, C, H, W). Element-wise weights. Default: None.
"""
return self.loss_weight * l1_loss(pred, target, weight, reduction=self.reduction)

注册器机制Registry的更多相关文章

  1. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  2. day91 DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  3. 深入理解Eureka - Eureka Client获取注册信息机制

    深入理解Eureka - Eureka Client获取注册信息机 Eureka Client提供了定时获取注册信息的机制.Eureka Client获取注册信息的所有逻辑都在DiscoveryCli ...

  4. php设计模式之单例(多例),注册器,观察者模式

    单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量.如模式名称,单例只能实例化一次,只有一个对象,多例模式可以多次实例化. 基于Singleton的特性,我们 ...

  5. 20.DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    一 认证组件 1. 局部认证组件 我们知道,我们不管路由怎么写的,对应的视图类怎么写的,都会走到dispatch方法,进行分发, 在咱们看的APIView类中的dispatch方法的源码中,有个sel ...

  6. SpringBoot 应用篇之从 0 到 1 实现一个自定义 Bean 注册器

    191213-SpringBoot 应用篇之从 0 到 1 实现一个自定义 Bean 注册器 我们知道在 spring 中可以通过@Component,@Service, @Repository 装饰 ...

  7. day 89 DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  8. DLL组件注册器

    在实际程序运行中,尤其是绿色软件,都需要对DLL进行注册才能够使用.下面就是笔者开发的一款简单的DLL注册器. http://pan.baidu.com/s/1mhbrN1e

  9. Tomcat类加载器机制

    Tomcat为什么需要定制自己的ClassLoader: 1.定制特定的规则:隔离webapp,安全考虑,reload热插拔 2.缓存类 3.事先加载 要说Tomcat的Classloader机制,我 ...

随机推荐

  1. python基础练习题(暂停一秒输出,并格式化当前时间)

    day5 --------------------------------------------------------------- 实例010:给人看的时间 题目 暂停一秒输出,并格式化当前时间 ...

  2. 论文解读(GCC)《Graph Contrastive Clustering》

    论文信息 论文标题:Graph Contrastive Clustering论文作者:Huasong Zhong, Jianlong Wu, Chong Chen, Jianqiang Huang, ...

  3. 【面试普通人VS高手系列】请说一下你对分布式锁的理解,以及分布式锁的实现

    一个工作了7年的Java程序员,私信我关于分布式锁的问题. 一上来就两个灵魂拷问: Redis锁超时怎么办? Redis主从切换导致锁失效怎么办? 我说,别着急,这些都是小问题. 那么,关于" ...

  4. Mysql数据库基础_复习思维导图

    Mysql复习的一个小总结,用xmind写的.(字数没有都不给我发博客) 下面是一些备注 子查询 MySQL子查询称为内部查询,而包含子查询的查询称为外部查询. 子查询可以在使用表达式的任何地方使用, ...

  5. 一篇文章说清 webpack、vite、vue-cli、create-vue 的区别

    webpack.vite.vue-cli.create-vue 这些都是什么?看着有点晕,不要怕,我们一起来分辨一下. 先看这个表格: 脚手架 vue-cli create-vue 构建项目 vite ...

  6. grpc-java源码环境编译

    1. Clone 1.1 git clone https://github.com/grpc/grpc-java.git 1.2 idea 打开grpc-java工程 2.compile 2.1 ja ...

  7. OAuth2.0之OLTU实现举例

    一.场景 三个角色:用户(user),web应用(client),资源服务器和授权服务器合为服务器(server) 用户登录登录后可查看自己的信息 二.准备 2.1 数据库 schema drop t ...

  8. linux篇-linux iptables配置

    1 iptables默认系统自带 setup 2重启防火墙 /etc/init.d/iptables restart 3接受端口 Vi /etc/sysconfig/iptables -A INPUT ...

  9. 好客租房4-react的基本使用 方法说明

    2.2方法说明 React.createElement //第二步创建react元素         //参数1:元素名称         //参数2:元素属性         //参数3:元素的子节 ...

  10. Linux系统执行命令方法

    现在我们无论是工作中还是学习中很多情况下用到Linux系统,当我们需要在C#代码中调用类似与cmd窗口执行命令时候,就需要用到此方法 public static Process CommitComma ...