mmcv之Config类介绍

准备资料

 本系列文章主要介绍mmcv及mmdetection源码解读。因此,建议读者首先在本地装好mmdetection环境。安装教程:mmdet2.8最新版安装教程!


前言

  本篇是mmcv源码解读的Config类介绍。代码地址在mmcv/utils/config.py文件中。


1、FasterRcnn为例

  网上大多数Config类讲解是特别干的代码介绍,缺乏一个具像的例子来深刻理解。因此,本文以mmdetection中的FasterRcnn网络为例来介绍Config类。(当然,Config类还有好多功能,还需学习探索,欢迎交流:Q2541612007)。
 贴下FasterRcnn的配置文件mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py):

_base_ = [
    '../_base_/models/faster_rcnn_r50_fpn.py',
    '../_base_/datasets/coco_detection.py',
    '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]

  上述配置文件中,_base_是个长度为4的list:模型,数据集,优化器,训练方式。这里说下Config类作用:“将配置文件中的字段转成字典的形式”。举个简单例子:以coco_detection.py部分文件字段为例:

dataset_type = 'CocoDataset'
data_root = 'data/coco/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)

 感性上来说:就是将 上述 “=”左边的视为字典的key;“=”右边的内容视为value。我把其成为“等号规则”。最终经过Config类返回的就是一个实例化的cfg对象,用_cfg_dict初始化Config类,变成一个属性。实际上_cfg_dict依旧是一个字典。
在这里插入图片描述

2、实现流程

 从第一部分可以看出:Config类实际上完成两部分工作:
 (1)将配置文件按照“等号规则“将配置文件的内容放入一个字典_cfg_dict。
 (2)用字典_cfg_dict完成Config类的初始化,使其成为Config类的一个属性。
  因此,对于第一部分工作实际上属于Config类的一个公用方法。因此,可以用Python中的静态方法 @staticmethod完成。第二部分则直接init类即可。接下来我会用两部分分别介绍。流程见下图:

在这里插入图片描述

2.1. 配置文件转入字典(_file2dict函数)

 从faster_rcnn的配置文件中看出:其实一个以 _base_字段开头的列表。而列表中元素是四个路径。因此,函数程序需要遍历4个路径,然后添加进一个字典中。函数整体逻辑如下(用ppt画的,见谅~):
在这里插入图片描述
 整体逻辑厘清之后,看代码就容易多了。我这里仅贴部分核心的(很多细节我也看不懂,大佬写的太牛了)。

    @staticmethod
    def _file2dict(filename, use_predefined_variables=True):
        filename = osp.abspath(osp.expanduser(filename))      # filename: py文件的绝对路径
                # 将file转入一个字典
                cfg_dict = {
    
    
                    name: value
                    for name, value in mod.__dict__.items()
                    if not name.startswith('__')
                }
        if BASE_KEY in cfg_dict:   # 判断是否有_base_字段
            base_filename = cfg_dict.pop(BASE_KEY)      # base_filename = ['../_base_/models/faster_rcnn_r50_fpn.py','../_base_/datasets/coco_detection.py','','']
            cfg_dict_list = list()                      # 存储最终结果
            cfg_text_list = list()
            for f in base_filename:
                _cfg_dict, _cfg_text = Config._file2dict(osp.join(cfg_dir, f))  # 遍历递归调用file2path
                cfg_dict_list.append(_cfg_dict)
                cfg_text_list.append(_cfg_text)
            # 遍历结束后,cfg_dict_list=[{},{},{},{}] , cfg_text_list = ['','','',''] 里面存储的是 四个配置文件中内容
            base_cfg_dict = dict()
            for c in cfg_dict_list:
                if len(base_cfg_dict.keys() & c.keys()) > 0:
                    raise KeyError('Duplicate key is not allowed among bases')
                base_cfg_dict.update(c)
        return cfg_dict, cfg_text

 大致应该没问题。比较容易理解。

2.2. Config类初始化

 2.1得到了cfg_dict,然后就可以用其完成初始化了。

   def __init__(self, cfg_dict=None, cfg_text=None, filename=None):
        super(Config, self).__setattr__('_cfg_dict', ConfigDict(cfg_dict))# Config类设置一个_cfg_dict属性,并将cfg_dict实例为ConfigDict类。
        super(Config, self).__setattr__('_filename', filename)            # Config类设置一个_filename属性。
        super(Config, self).__setattr__('_text', text)                    # Config在添加一个'_text'属性
    def __setattr__(self, name, value):
        if isinstance(value, dict):
            value = ConfigDict(value)
        self._cfg_dict.__setattr__(name, value)

  代码中重写了__setattr__方法。简单就是将cfg_dict变成了一个ConfigDict类。实质还是一个字典,只不过重写了__getattr__方法,在根据key索引时加入了一些逻辑判断(keyerror啥的),这里将其依旧理解成一个普通字典就行。

class ConfigDict(Dict):

    def __missing__(self, name):
        raise KeyError(name)

    def __getattr__(self, name):
        try:
            value = super(ConfigDict, self).__getattr__(name)
        except KeyError:
            ex = AttributeError(f"'{self.__class__.__name__}' object has no "
                                f"attribute '{name}'")
        except Exception as e:
            ex = e
        else:
            return value
        raise ex

总结

 本篇主要介绍的是Config类的设计理念把。实际上Config类还有好多方法,比如_merge_a_to_b等。不过都逃不过那两部分:根据等号规则将字段变成dict,然后利用dict初始化Config类。
 如有问题, 欢迎提问交流Q2541612007。

Guess you like

Origin blog.csdn.net/wulele2/article/details/113870217