当前位置: 首页 > 工具软件 > registry > 使用案例 >

Detectron2和fvcore中的Registry机制详解

甄霖
2023-12-01

为什么要有Registry机制

Registry机制原本是fvcore框架里面的功能,因为fvcore是一个轻量级的核心库,它提供了在FAIR开发的各种计算机视觉框架(如Detectron2、PySlowFast和ClassyVision)中共享的最常见和最基本的功能。所以Detectron2里面有很多功能都是直接从fvcore框架里面直接拿过来用的。

由于Detectron2是在pytorch的基础上进行再次封装的深度学习框架,其必须具有兼容多种算法的能力,也就是说,基本上常用的算法都要能够在这个框架上方便地实现才行,不然就失去了这个框架的意义。

这么多深度学习算法都要在这个框架上实现,那是不是我每跑一次算法,都要去调用一下这个深度学习算法的实现代码(也就是利用nn.Module写网络框架的那个文件)。按照最原始的方法来调用,我是不是首先要找到这个实现文件在哪里,然后再去寻找实现这个网络的类在哪里,然后利用类名去初始化这个网络,再去训练、推理等等。

这就会导致一个问题,如果框架里的算法很多,这样找来找去会很麻烦,于是就可以利用Registry机制来简化这个过程,将字符串命名与对象(Object)建立一对一的映射关系,也就是将名字与算法模型建立一一对应关系。然后我下次要调用这个算法的时候,我就不需要管这个算法被写在哪个地方了,直接调用这个名字即可。

如何使用Registry机制

比如我要实现一个功能:建立一个目标检测算法映射,即框架里所有的目标检测算法对应一个名字,然后通过这些名字就可以一一对应地调用目标检测算法

首先我们需要初始化Registry类

from detectron2.utils.registry import Registry
#或者用:from fvcore.common import registry
OBGECT_DETECTION_REGISTRY = Registry("object_detection")

然后,我们需要将算法实现代码与名字建立映射关系

@OBGECT_DETECTION_REGISTRY.register()
class MyObjectDetectionAlgorithm():
	...

或者用如下方法建立映射关系

OBGECT_DETECTION_REGISTRY.register(MyObjectDetectionAlgorithm)

建立映射关系之后,这个算法的名字就是MyObjectDetectionAlgorithm。将所有目标检测算法都一一映射成这种名字之后,然后将这些名字都记录配置文件里面,之后就可以通过查询配置文件,来决定调用哪个算法了。

用如下代码实现通过名字调用算法

model = OBGECT_DETECTION_REGISTRY.get(MyObjectDetectionAlgorithm)(cfg) #其中的cfg是初始化算法需要传入的参数

Registry机制内部是怎么实现的

Registry机制实现的源代码见:
https://detectron2.readthedocs.io/en/latest/_modules/fvcore/common/registry.html.
也可以看下面:

# 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__
 类似资料: