引言:
在上篇文章中,讲了train.py训练文件,主要是读取命令行函数和主函数main。main主要先做了一些config,work_dir以及log等操作(这些操作都是从命令行获得的,或者从命令行带有的文件里得到的参数等。)。最主要的三个步骤就是调用build_detector()来创建模型,然后同样调用build_dataset()对数据集创建模型,然后在训练检测器train_detector()。
注:build_dataset()和build_detector()不在同一个builder.py中实现,所以以下的builder.py实现的是build_detector(),是在mmdet/model/下的py文件。
具体详情看
本篇文章主要就是讲一下,搭建模型的思路,以及registry.py
和builder.py
中各个函数块的作用。
注:builder.py是在mmdet/model文件夹下,是用来创建BACKBONES、NECKS、ROI_EXTRACTORS、SHARED_HEADS、HEADS、LOSSES、DETECTORS的模型的。而关于build_dataset()(在mmdet/datasets/builder.py中),在后面讲到数据集的时候再来讲它。
在mmdet/utils文件夹下的registry.py
为主要的实现过程,后面详细讲解。
先来看在mmdet/models文件夹下的registry.py
,较简单,代码如下:
# -*- coding: utf-8 -*-
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')
#类的实例化,Registry是一个类,传入的是一个字符串。该字符串为Registry类的name属性值
举个例子:DETECTORS
为注册表Registry的实例化对象,DETECTORS .name = 'detector'
,Registry类的定义在mmdet/utils/文件中。
所以,根据上面代码,我们就应该知道了,不止一个名为
DETECTORS
的注册表Registry,后面还会有名为NECKS、ROI_EXTRACTORS 、SHARED_HEADS 、HEADS 、LOSSES 的注册表,这些注册表下的_module_dict属性,则是用来存对应的相同类对象的,举个例子:比如DETECTORS的_module_dict下就有可能有:Faster R-CNN、Cascade R-CNN、FPN、HTC等常见的检测器。到这或许你就明白了注册表的作用咯
而在mmdet/utils/Registry.py中,有一个类Registry
的定义和一个方法:build_from_cfg()
的实现。
build_from_cfg()
方法的作用是从 congfig/py配置文件中获取字典数据,创建module(其实也就是一个class类),然后将这个module添加到之前创建的注册表Registry的属性_module_dict中(这是一个字典,key为类名,value为具体的类),返回值是一个实例化后的类对象。
所以,可以这样理解,从config/py配置文件中,将字典提取出来,然后为其映射成一个类,放进Registry对象的_module_dict属性中。(具体看下面的代码)
Registry.py文件
以下代码分三部分
Part one:
inspect模块是针对模块,类,方法,功能等对象提供些有用的方法。例如可以帮助我们检查类的内容,检查方法的代码,提取和格式化方法的参数等。
# -*- coding: utf-8 -*-
import inspect
import mmcv
Part two:
通过前面第一段的代码段,我们知道DETECTORS = Registry('detector')
detector是干什么的 ???
其实,DETECTORS = Registry('detector')
只是注册了一个对象名为DETECTORS ,属性name为detector的对象。然后用属性_module_dict 来保存config配置文件中的对应的字典数据所对应的class类(看第三部分代码)。请看如下类Registry的定义代码:
class Registry(object):
def __init__(self, name): #此处的self,是个对象(Object),是当前类的实例,name即为传进来的'detector'值
self._name = name
self._module_dict = dict() #定义的属性,是一个字典
def __repr__(self):
#返回一个可以用来表示对象的可打印字符串,可以理解为java中的toString()。
format_str = self.__class__.__name__ + '(name={}, items={})'.format(
self._name, list(self._module_dict.keys()))
return format_str
@property #把方法变成属性,通过self.name 就能获得name的值。
def name(self):
return self._name
#因为没有定义它的setter方法,所以是个只读属性,不能通过 self.name = newname进行修改。