注册器设计模式,以SparseInst(detectron2)代码为例

news2024/11/18 3:23:19

注册器设计模式

from detectron2.utils.registry import Registry

这里面的Registry实际上就是注册器设计模式

1.举一个简单版的小例子来理解注册器设计模式

参考:Python注册器设计模式_python 注册类-CSDN博客

# 这一行代码是从Python的 typing 模块中导入了一些类型提示(type hint)相关的工具。
# Python的 typing 模块提供了静态类型检查的支持,这对提高代码的可读性和可靠性很有帮助
from typing import Any, Callable, Dict, List, Optional, Type, Union

# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
# pyre-ignore-all-errors[2,3]
from typing import Any, Dict, Iterable, Iterator, Tuple

from tabulate import tabulate


class Registry(Iterable[Tuple[str, Any]]):
    """
    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: str) -> None:
        """
        Args:
            name (str): the name of this registry
        """
        self._name: str = name
        self._obj_map: Dict[str, Any] = {}

    def _do_register(self, name: str, obj: Any) -> None:
        assert (
            name not in self._obj_map
        ), "An object named '{}' was already registered in '{}' registry!".format(
            name, self._name
        )
        self._obj_map[name] = obj

    def register(self, obj: Any = None) -> Any:
        """
        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: Any) -> Any:
                name = func_or_class.__name__
                self._do_register(name, func_or_class)
                return func_or_class

            return deco

        # used as a function call
        name = obj.__name__
        self._do_register(name, obj)

    def get(self, name: str) -> Any:
        ret = self._obj_map.get(name)
        if ret is None:
            raise KeyError(
                "No object named '{}' found in '{}' registry!".format(name, self._name)
            )
        return ret

    def __contains__(self, name: str) -> bool:
        return name in self._obj_map

    def __repr__(self) -> str:
        table_headers = ["Names", "Objects"]
        table = tabulate(
            self._obj_map.items(), headers=table_headers, tablefmt="fancy_grid"
        )
        return "Registry of {}:\n".format(self._name) + table

    def __iter__(self) -> Iterator[Tuple[str, Any]]:
        return iter(self._obj_map.items())

    def build(self, cfg: Dict[str, Any]) -> Any:
        if not isinstance(cfg, dict) or 'type' not in cfg:#检查字典是否符合规定,规定中,键值要写为 type
            raise TypeError('cfg must be a dict and contain the key "type"')
        module_type = cfg.pop('type')#获取模块类型
        module_cls = self.get(module_type)#获取模块类
        if module_cls is None:#如果模块不存在,报错
            raise KeyError(f'{module_type} is not registered in {self._name}')
        return module_cls(**cfg)#实例化模块并且返回
    # pyre-fixme[4]: Attribute must be annotated.
    __str__ = __repr__





# 用法示例
if __name__ == '__main__':
    # 第二步、定义一个注册表
    MODELS = Registry("SPARSE_INST_ENCODER")


    # 第三步、使用装饰器在注册表注册模块,比如一个类
    @MODELS.register()
    class ResNet:
        def __init__(self, depth):
            self.depth = depth

    # 使用装饰器注册模块,比如一个函数
    @MODELS.register()
    def resnet50():
        return ResNet(depth=50)

    # 使用普通函数注册模块,比如一个类,先声明一个类
    class MobileNet:
        def __init__(self, width_multiplier):
            self.width_multiplier = width_multiplier
    #注册到注册表中
    MODELS.register(MobileNet)#或者直接在MobileNet类声明上面用装饰器@MODELS.register_module()


    # 第四步、使用build函数,构建模型(其实是各个已注册模块的实例化)
    resnet = MODELS.build(dict(type='ResNet', depth=18))
    print(f'ResNet: depth = {resnet.depth}')  # 输出: ResNet: depth = 18

    mobilenet = MODELS.build(dict(type='MobileNet', width_multiplier=1.0))
    print(f'MobileNet: width_multiplier = {mobilenet.width_multiplier}')  # 输出: MobileNet: width_multiplier = 1.0

    resnet_instance = MODELS.build(dict(type='resnet50'))
    print(
        f'ResNet instance from function: depth = {resnet_instance.depth}')  # 输出: ResNet instance from function: depth = 50

注册器模式实现的四个步骤:

1、定义注册器类


注册器类比较关键,需要实现了好几个功能,各种模块的
注册:内部函数_do_register负责具体注册的实现;外部函数register暴漏给编码人员,写代码的时候用

储存:将被注册的模块(类、函数、等)存在注册器类的字典中。所以一般__init__() 里会初始化一个字典

获取:使用函数get,获取已注册对象,传入类的名称,返回这个类的实际实现的引用

实例化:创建build函数,实例化被注册的模块

2、初始化注册器

注册器又称注册表,创建一个注册器:用注册器类新建一个对象。
MODELS = Registry(‘models’)

3、注册可调用对象

将模块(类、函数、等)注册到注册器中去

可以用隐式的方法:装饰器挂在类的声明实现的头上,就可以完成注册了

@MODELS.register_module()
class ResNet:

如以上代码,能把ResNet类注册到注册表中。

也可以使用显示的注册方式,如

    # 使用普通函数注册模块,比如一个类,先声明一个类
    class MobileNet:
        def __init__(self, width_multiplier):
            self.width_multiplier = width_multiplier
    #注册到注册表中
    MODELS.register(MobileNet)#或者直接在MobileNet类声明上面用装饰器@MODELS.register_module()

这两种写法都是可以的,底层实现是一样的。

4、使用注册器构建对象

也就是已经被注册到注册表中的模块(类、函数、等)的实例化,实例化用的是build函数
比如可以这么写:

resnet_cfg = {'type': 'ResNet', 'depth': 18}
resnet = MODELS.build(resnet_cfg)

也可

resnet = MODELS.build(dict(type='ResNet', depth=18))

2.detectron2里的注册器设计模式

detectron2第一步定义注册器类的代码:

# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
# pyre-ignore-all-errors[2,3]
from typing import Any, Dict, Iterable, Iterator, Tuple

from tabulate import tabulate


class Registry(Iterable[Tuple[str, Any]]):
    """
    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: str) -> None:
        """
        Args:
            name (str): the name of this registry
        """
        self._name: str = name
        self._obj_map: Dict[str, Any] = {}

    def _do_register(self, name: str, obj: Any) -> None:
        assert (
            name not in self._obj_map
        ), "An object named '{}' was already registered in '{}' registry!".format(
            name, self._name
        )
        self._obj_map[name] = obj

    def register(self, obj: Any = None) -> Any:
        """
        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: Any) -> Any:
                name = func_or_class.__name__
                self._do_register(name, func_or_class)
                return func_or_class

            return deco

        # used as a function call
        name = obj.__name__
        self._do_register(name, obj)

    def get(self, name: str) -> Any:
        ret = self._obj_map.get(name)
        if ret is None:
            raise KeyError(
                "No object named '{}' found in '{}' registry!".format(name, self._name)
            )
        return ret

    def __contains__(self, name: str) -> bool:
        return name in self._obj_map

    def __repr__(self) -> str:
        table_headers = ["Names", "Objects"]
        table = tabulate(
            self._obj_map.items(), headers=table_headers, tablefmt="fancy_grid"
        )
        return "Registry of {}:\n".format(self._name) + table

    def __iter__(self) -> Iterator[Tuple[str, Any]]:
        return iter(self._obj_map.items())

    # pyre-fixme[4]: Attribute must be annotated.
    __str__ = __repr__

第二步初始化注册器的代码:

以初始化BACKBONE_REGISTRY注册器为例 

第三步注册可调用对象: 

第四步使用注册器构建对象:

实际上构建对象就只有一句话

 model = META_ARCH_REGISTRY.get(meta_arch)(cfg)

传入参数meta_arch的值为字字符串'SparseInst'。所以META_ARCH_REGISTRY.get(meta_arch)得到了SparseInst类名,META_ARCH_REGISTRY.get(meta_arch)(cfg)实际上就是SparseInst(cfg),也就是上面这句代码跟这句代码等价

model=SparseInst(cfg)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2175558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3分钟教程,手把手教你使用腾讯元宝定制属于自己的AI助手

在今天这个市场,竞争激烈的不得了,大家每天都必想的问题是啥?是“降本增效”,都在想把一个人当两个人用! 但老板有秘书,领导有员工,作为牛马的我呢?我左顾右盼之后发现背后空荡荡的…

大数据毕业设计选题推荐-重庆旅游景点数据分析系统-Python-Hive-Hadoop-Spark

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

JavaScript网页设计案例:互动式简历网站

JavaScript网页设计案例:互动式简历网站 在现代网页设计中,JavaScript 是实现交互和动态效果的关键技术。本文将通过一个完整的案例,展示如何使用 JavaScript 构建一个交互式的个人简历网页。本文不仅会涵盖 HTML 和 CSS 的使用,…

机器学习:探索未知边界,解锁智能潜力

欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 在这个日新月异的科技时代,机器学习作为人工智能领域的核心驱动力,正以前所未有的速度改变着我们的世界。从智能家居的个性化推荐到自动驾驶汽车的精准导航,从医疗诊断的辅助…

【数据结构与算法】基本概念

数据结构与算法——绪论 文章目录 一.数据结构的研究内容1.1数值计算1.2非数值计算 二.基本概念和术语2.1数据,数据元素,数据项和数据对象2.2数据结构2.2.1逻辑结构2.2.2存储结构(物理结构)2.2.3运算和实现 三.抽象数据类型的表示…

安装管理K8S的开源项目KubeClipper介绍

安装管理K8S的开源项目KubeClipper介绍 1. 概述 KubeClipper是九州云开源的一个图形化界面 Kubernetes 多集群管理工具,旨在提供易使用、易运维、极轻量、生产级的 Kubernetes 多集群全生命周期管理服务。让运维工程师从繁复的配置和晦涩的命令行中解放出来&#…

VMware下的ubuntu显示文字太小的自适应显示调整

我的情况 我使用的是4K的32寸显示器,分辨率为 3840 x 2160,ubuntu版本为18.04,默认的情况下系统分辨率为 3466 x 1842。 ​ 此时,显示的文字很小,虽然可以看清,但也比较吃力,在VMware窗口…

深入探索机器学习中的目标分类算法

在当今数据驱动的世界中,机器学习(Machine Learning, ML)正逐渐成为解决问题的重要工具。在众多机器学习任务中,目标分类(Classification)算法尤其受到关注。本文将深入探讨目标分类算法的基本概念、常见类…

828华为云征文|部署开源超轻量中文OCR项目 TrWebOCR

828华为云征文|部署开源超轻量中文OCR项目 TrWebOCR 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 TrWebOCR3.1 TrWebOCR 介绍3.2 TrWebOCR 部署3.3 TrWebOCR…

解压视频素材下载网站推荐

在制作抖音小说推文或其他短视频时,找到合适的解压视频素材非常重要。以下是几个推荐的网站,可以帮助你轻松下载高质量的解压视频素材: 蛙学网 蛙学网是国内顶尖的短视频素材网站,提供大量4K高清无水印的解压视频素材,…

C++:STL(四)之vector的基本介绍与使用方式|容器接口

✨ Blog’s 主页: 白乐天_ξ( ✿>◡❛) 🌈 个人Motto:他强任他强,清风拂山冈! 🔥 所属专栏:C深入学习笔记 💫 欢迎来到我的学习笔记! 一、C/C中的字符串 1.1. C语言中的…

【机器学习】——决策树以及随机森林

文章目录 1. 决策树的基本概念与结构1.1 决策树的构建过程 2. 决策树的划分标准2.1 信息增益(Information Gain)2.2 信息增益比(Information Gain Ratio)2.3 基尼指数(Gini Index)2.4 均方误差(…

极限基本类型小结

极限基本类型小结 在之前的文章中已经看过了极限的多种基本类型,下面展示一些各种基本类型的代表性的图像,通过观察下面的图像可以帮助我们回顾函数在趋近于某一点时函数值的行为(这也叫极限值),也生动的描述了各种极…

老古董Lisp实用主义入门教程(12):白日梦先生的白日梦

白日梦先生的白日梦 白日梦先生已经跟着大家一起学Lisp长达两个月零五天! 001 粗鲁先生Lisp再出发002 懒惰先生的Lisp开发流程003 颠倒先生的数学表达式004 完美先生的完美Lisp005 好奇先生用Lisp来探索Lisp006 好奇先生在Lisp的花园里挖呀挖呀挖007 挑剔先生给出…

关于工作虚拟组的一些思考

这是学习笔记的第 2493篇文章 因为各种工作协作,势必要打破组织边界,可能会存在各种形态的虚拟组。 近期沉淀了一些虚拟组的管理方式,在一定时间范围内也有了一些起色,所以在不断沉淀的过程中,也在不断思考。 这三个虚…

企业级版本管理工具(1)----Git

目录 1.Git是什么 2.Git的安装和使用 在Ubuntu下安装命令如下: 使用git --version查看已安装git的版本: 使用git init初始化仓库: 使用tree .git列出目录: 使用git config命令设置姓名和邮箱: 加入--global选项…

WPF MVVM入门系列教程(一、MVVM模式介绍)

前言 还记得早些年刚工作的那会,公司的产品从Delphi转成了WPF(再早些年是mfc)。当时大家也是处于一个对WPF探索的阶段,所以有很多概念都不是非常清楚。 但是大家都想堆技术,就提出使用MVVM,我那会是第一次…

想做个WPS的自动化代码,参考如下:

🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&am…

水仙花数求解-C语言

1.问题&#xff1a; 输出100-1000之间所有的“水仙花数”。 2.解答&#xff1a; “水仙花数”是指一个3位数&#xff0c;其各位数字立方和等于该数本身&#xff0c;逐个位数判断即可&#xff0c;写代码的时候要考虑到每一位。 3.代码&#xff1a; #include<stdio.h>//…

9.28QT基础

widget.cpp widegt.h .pro main.cpp 一个仿QQ登录界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->setFixedSize(350,500);this->setStyleSheet("background-color:#e5f0ff;");QLineEdit *edit1 new QLine…