理解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代碼注冊模塊。