mmdection的注冊模塊Registry解讀


理解mmdection模塊基礎:

1. @ 的裝飾器需理解(很重要)。

2.class 類簡單實列化等操作。

 

簡單應用類的裝飾器的一個列子,理解注冊模塊:

簡單說明:注冊模塊實際是通過字典保存名字對應類地址,其中最重要的是Registry類中

self._module_dict = dict()未定義的的字典中添加注冊類的地址,以便於后續訪問。
而添加類對象地址通過該函數添加 _register_module(self, module_class)。
如下FOOD實列中添加了Rice與Noodles類的地址。

builder.py 文件代碼如下:

from registry import Registry, build_from_cfg

FRUIT = Registry('fruit')
FOOD = Registry('food')
def build(cfg, registry, default_args=None):
    return build_from_cfg(cfg, registry, default_args)

def build_fruit(cfg):
    return build(cfg, FRUIT)
def build_food(cfg):
    return build(cfg, FOOD)
@FOOD.register_module
class Rice():
    def __init__(self, name):
        self.name = name
@FOOD.register_module
class Noodles(): # 實際FOOD實列化后的
    def __init__(self):
        pass
@FRUIT.register_module
class Apple():
    def __init__(self, name):
        self.name = name

 



registry.py文件代碼如下:

import inspect
import six

def is_str(x):
    """Whether the input is an string instance."""
    return isinstance(x, six.string_types)


class Registry(object):

    def __init__(self, name):
        self._name = name    # 此處的self,是個對象(Object),是當前類的實例,name即為傳進來的'detector'值
        self._module_dict = dict()  # 定義的屬性,是一個字典

    @property
    def name(self):  # 把方法變成屬性,通過self.name 就能獲得name的值。我感覺是一個私有函數
        return self._name

    @property
    def module_dict(self):
        return self._module_dict

    def get(self, key):
        return self._module_dict.get(key, None)

    def _register_module(self, module_class):
        """
        關鍵的一個方法,作用就是Register a module.
        在model文件夾下的py文件中,里面的class定義上面都會出現 @DETECTORS.register_module,意思就是將類當做形參,
        將類送入了方法register_module()中執行。@的具體用法看后面解釋。
        Register a module.

        Args:
            module (:obj:`nn.Module`): Module to be registered.
        """
        # if not inspect.isclass(module_class):  # 判斷是否為類,是類的話,就為True,否則報錯
        #     raise TypeError('module must be a class, but got {}'.format(
        #         type(module_class)))
        module_name = module_class.__name__  # 獲取類名
        if module_name in self._module_dict:  # 看該類是否已經登記在屬性_module_dict中
            raise KeyError('{} is already registered in {}'.format(
                module_name, self.name))
        self._module_dict[module_name] = module_class  # 在module中dict新增key和value。key為類名,value為類對象

    def register_module(self, cls):  # 對上面的方法,修改了名字,添加了返回值,即返回類本身
        self._register_module(cls)
        return cls

def build_from_cfg(cfg, registry, default_args=None):
    """Build a module from config dict.

    Args:
        cfg (dict): Config dict. It should at least contain the key "type".
        registry (:obj:`Registry`): The registry to search the type from.
        default_args (dict, optional): Default initialization arguments.

    Returns:
        obj: The constructed object.
    """
    assert isinstance(cfg, dict) and 'type' in cfg
    assert isinstance(default_args, dict) or default_args is None
    args = cfg.copy()
    obj_type = args.pop('type')
    if is_str(obj_type):
        obj_cls = registry.get(obj_type)
        if obj_cls is None:
            raise KeyError('{} is not in the {} registry'.format(
                obj_type, registry.name))
    elif inspect.isclass(obj_type):
        obj_cls = obj_type
    else:
        raise TypeError('type must be a str or valid type, but got {}'.format(
            type(obj_type)))
    if default_args is not None:
        for name, value in default_args.items():
            args.setdefault(name, value)


    return obj_cls(**args)

lunch.py文件代碼如下:
lunch=dict(
    food=dict(type='Rice', name='東北大米'),
    fruit=dict(type='Apple', name='青蘋果')
)

 



demo.py文件代碼如下:

from build import build_fruit, build_food
from lunch import lunch


class COOKER():
    def __init__(self,food, fruit):
        print('今日飲食清單:{}, {}'.format(food, fruit))
        self.food = build_food(food)
        self.fruit = build_fruit(fruit)

    def run(self):
        print('具體飲食計划')
        print('主食吃: {}'.format(self.food.name))
        print('水果吃: {}'.format(self.fruit.name))

cook = COOKER(**lunch)
cook.run()

 



結果如下:

 

 

 

mmdection的注冊使用:

 

Registry.py文件用來添加模塊注冊機制的,實際是通過registry類建立的實列如BACKNONE實列中添加模塊,如resnet等

並通過self._module_dict 字典保存,該文件與上面的registry.py文件相同,不貼代碼了。

 

builders.py 文件用來讀取config信息,並通過registry文件中build_from_cfg函數來保存信息,實際保存為類中初始化變量信息(參數),

通過賦值調用注冊模塊中符合要求的類。

 

from torch import nn

from mmdet.utils import build_from_cfg
from .registry import (BACKBONES, DETECTORS, HEADS, LOSSES, NECKS,
                       ROI_EXTRACTORS, SHARED_HEADS)


def build(cfg, registry, default_args=None):
    if isinstance(cfg, list):
        modules = [
            build_from_cfg(cfg_, registry, default_args) for cfg_ in cfg
        ]
        return nn.Sequential(*modules)
    else:
        return build_from_cfg(cfg, registry, default_args)
    # default_args 來自config的train_cfg與test_cfg


def build_backbone(cfg):
    return build(cfg, BACKBONES)


def build_neck(cfg):
    return build(cfg, NECKS)


def build_roi_extractor(cfg):
    return build(cfg, ROI_EXTRACTORS)


def build_shared_head(cfg):
    return build(cfg, SHARED_HEADS)


def build_head(cfg):
    return build(cfg, HEADS)


def build_loss(cfg):
    return build(cfg, LOSSES)


def build_detector(cfg, train_cfg=None, test_cfg=None):
    return build(cfg, DETECTORS, dict(train_cfg=train_cfg, test_cfg=test_cfg))

 

 
        

 

model/registry.py文件純粹是用來實列化模塊的,也是這樣的實列化,通過@符號添加模塊的

from mmdet.utils import Registry

BACKBONES = Registry('backbone')
NECKS = Registry('neck')
ROI_EXTRACTORS = Registry('roi_extractor')
SHARED_HEADS = Registry('shared_head')
HEADS = Registry('head')
LOSSES = Registry('loss')
DETECTORS = Registry('detector')

 

模塊添加就是通過@ ,如同上個列子中的FOOD添加模塊一樣,而mmdection添加如同下圖。

 

 

 

 

 

 

以上大致為mmdection代碼注冊模塊。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM