MMDetection Framework Getting Started Tutorial (3): Detailed Analysis of Configuration Files

  As mentioned in the previous blog , MMDetection only needs 3 steps to build the training algorithm: 1) Prepare the data set 2) Write the configuration file 3) Execute train.pythe file to start training. But the last blog only briefly introduced the general process. This article will analyze the configuration file construction mechanism from the perspective of source code. The main reference is the official documentation (it has to be said that there are so many tutorials on the Internet, and finally found that the best is the official document) .

  1. Official documentation - MMCV
  2. Official documentation - MMDetection
  3. Zhihu official - MMCV core component analysis (4): Config

1. File structure

  The configuration files that MMDetection has implemented are all located in ./configsfolders, and the configuration files are named according to uniform rules. You can refer to the official documentation for the meaning of specific fields.

# 配置文件命名规则
{
    
    model}_[model setting]_{
    
    backbone}_{
    
    neck}_[norm setting]_[misc]_[gpu x batch_per_gpu]_{
    
    schedule}_{
    
    dataset}

  These configuration files are obtained by inheriting the original configuration file./configs/_base_ . The original configuration file is located under the folder. There are 4 basic component types, namely datasets, models, training strategies (schedules) and runtime defaults. configuration (default_runtime). Generally speaking, when we create a new configuration file, we need to inherit an original configuration file from the above four components, and then adjust it according to our own needs. Of course, if you are building a brand new method that does not share structure with any existing methods, you can also create a new one without inheriting any original configuration files.

  In order to understand what necessary information is contained in a configuration file, here I create a new one test_config.py, which inherits at least 4 original configuration files:

_base_ = [
    'mmdetection/configs/_base_/models/fast_rcnn_r50_fpn.py',		# models
    'mmdetection/configs/_base_/datasets/coco_detection.py',		# datasets
    'mmdetection/configs/_base_/schedules/schedule_1x.py',			# schedules
    'mmdetection/configs/_base_/default_runtime.py',				# defualt_runtime
]

  Then use to mmdetection/tools/misc/print_config.pyprint the complete configuration file information. In order to make the entire configuration file structure look clearer, I replaced some unimportant information with ellipses:

# 1. 模型配置(models) =========================================
model = dict(
	type='FastRCNN',			# 模型名称是FastRCNN
	backbone=dict(				# BackBone是ResNet
        type='ResNet',
        ...,
    ),
    neck=dict(					# Neck是FPN
        type='FPN',
        ...,
    ),
    roi_head=dict(				# Head是StandardRoIHead
        type='StandardRoIHead',
        ...,
        loss_cls=dict(...),		# 分类损失函数
        loss_bbox=dict(...),	# 回归损失函数
    ),
    train_cfg=dict(				# 训练参数配置
    	assigner=dict(...),		# BBox Assigner
    	sampler=dict(...),		# BBox Sampler
    	...
	),
    test_cfg =dict(				# 测试参数配置
    	nms=dict(...),			# NMS后处理
    	...,
    )
)

# 2. 数据集配置(datasets) =========================================
dataset_type = '...'			# 数据集名称
data_root = '...'				# 数据集根目录
img_norm_cfg = dict(...)		# 图像归一化参数
train_pipeline = [				# 训练数据处理Pipeline
	...,
	dict(type='Normalize', **img_norm_cfg),
	...
]
test_pipeline = [...]			# 测试数据处理Pipeline
data = dict(
	samples_per_gpu=2,			# batch_size
    workers_per_gpu=2,			# GPU数量
	train=dict(					# 训练集配置
		type=dataset_type,
        ann_file=data_root + 'annotations/instances_train2017.json',	# 标注问加你
        img_prefix=data_root + 'train2017/',	# 图像前缀
		pipline=trian_pipline,					# 数据预处理pipeline
	),
	val=dict(					# 验证集配置
		...,
		pipline=test_pipline,
	),
	test=dict(					# 测试集配置
		...,
		pipline=test_pipline,
	)
)

# 3. 训练策略配置(schedules) =========================================
evaluation = dict(interval=1, metric='bbox')
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
lr_config = dict(
    policy='step',
    warmup='linear',
    warmup_iters=500,
    warmup_ratio=0.001,
    step=[8, 11])
runner = dict(type='EpochBasedRunner', max_epochs=12)

# 4. 运行配置(runtime) =========================================
checkpoint_config = dict(interval=1)
log_config = dict(interval=50, hooks=[dict(type='TextLoggerHook')])
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]

  The configuration file contains four basic components: datasets, models, schedules, and runtime. In addition to the network structure of the model itself, the model also includes configuration parameters such as bbox assigner, bbox sampler, and nms; data mainly includes relevant parameters of batch_size, training set, verification set, and test set; schedules include training such as optimizer, learning rate, and number of iterations Configuration information of process-related parameters; runtime is some configuration related to log printing, parameter saving, and distributed training. Combined with the algorithm flow chart in the previous blog post, the corresponding configuration parameters of each module can be found in the configuration file: the modules from Backbone to Loss are all in the configuration parameters of the model, and tricks are reflected in the configuration of schedules . So as long as the configuration file is written, the subsequent MMDetection framework will automatically parse the configuration file and construct the entire algorithm process.

  In general, the configuration file is dicta text file composed of a series of type variables, which also contains some intermediate variables, such as data_root, , test_pipelineetc. These intermediate variables can be dictreferenced by others. The configuration file can _base_ = ['...']inherit the parameters in other configuration files through the method, and then complete the modification of specific parameters by rewriting, and also create a blank file, and then complete the assignment of each parameter from scratch.

2. Config class

  MMDetection uses the Config class in the MMCV library to complete the parsing of configuration files. The Config class is used to manipulate configuration files, and it supports loading configuration from a variety of file formats, including python, json and yaml. It provides a dictionary object-like interface to get and set values.

2.1 Read the configuration file

  Generally used Config.fromfile(filename)to read configuration files (or pass in a dict directly) and return a Config class:

from mmcv import Config

cfg = Config.fromfile('../configs/test_config.py')

  fromfile()The source code of the function is as follows, and its core function is _file2dict(). _file2dict()According to the text order, the configuration file will be parsed according to the format of key = value, and a cfg_dictdictionary named will be obtained. If there is a field, the function will be called again _base_for each file path included , and the configuration parameters contained in the file will be added to the , to implement the inheritance function of the configuration file. It should be noted that the key values ​​contained in different files will be verified internally , and duplicate key values ​​are not allowed in different base files , otherwise MMCV does not know which base file to take as the standard._base__file2dict()cfg_dict_file2dict()_base_

@staticmethod
def fromfile(filename,
             use_predefined_variables=True,
             import_custom_modules=True):
    cfg_dict, cfg_text = Config._file2dict(filename,
                                           use_predefined_variables)
    # import_modules_from_strings()是根据字符串列表对应的模块
    if import_custom_modules and cfg_dict.get('custom_imports', None):
        import_modules_from_strings(**cfg_dict['custom_imports'])
    return Config(cfg_dict, cfg_text=cfg_text, filename=filename)

test_config.pyFor example, after passing through the function   built above _file2dict(), the following dictionary data will be obtained, and then a Config object will be initialized and returned to fromfile()the superior call.

  There are two other points that need to be added. One is that when constructing the Config object, the python dictdata type will be converted into ConfigDicta type for processing. ConfigDictIt is a subclass in the third-party library addict Dict, because python's native dicttype does not support .属性the access method, especially dictwhen multiple layers of dict are nested inside, if the access method is based on the key, the code is very inefficient to write, and Dictthe class passes The overridden __getattr__()method implements .属性the access method. Therefore, the inherited Dictones ConfigDictalso support .属性access to each member value in the dictionary.

from mmcv import ConfigDict

model = ConfigDict(dict(backbone=dict(type='ResNet', depth=50)))

print(model.backbone.type)		# 输出 'ResNet'

  The second is that, in order to be compatible with the decimal point in the configuration file name, MMCV _file2dict()will 'C:/Users/ADMINI~1/AppData/Local/Temp/'create a temporary folder. If the C drive has access rights, an error may appear, but this problem will only appear in the Windows system.

2.2 Modify configuration parameters

  After knowing the internal logic of MMCV parsing configuration files, it is naturally clear how to modify the values ​​​​of configuration parameters. Because the dictionary _file2dict()is built according to the order of the text , the key value written later can overwrite the original value (if the variable type is list, the list will be replaced entirely, and a certain item cannot be modified) . Taking modifying the optimizer as an example, the original inherited optimizer is SGD with a learning rate of 0.02:

# 原来继承的优化器
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)

Now if you want to _base_adjust the inherited learning rate to 0.001, you can directly add a line to the current configuration file:

# 修改学习率
optimizer = dict(lr=0.001)

This will only modify the parameters in the optimizer key value lr, and other parameters will not be affected. The current optimizer configuration becomes:

# 修改学习率后的SGD
optimizer = dict(type='SGD', lr=0.001, momentum=0.9, weight_decay=0.0001)

  If you want to change to a new optimizer now, but the parameters of the two optimizers are not compatible, you need to delete the original key value and replace it with a new set of key values, which can be achieved through configuration _delete_=True:

# 将原来的SGD替换成AdamW
optimizer = dict(_delete_=True, type='AdamW', lr=0.0001, weight_decay=0.0001)

Then the optimizer replacement is completed. The optimizer parameters of the current configuration file are as follows:

# 当前优化器变为AdamW
optimizer = dict(type='AdamW', lr=0.0001, weight_decay=0.0001)

2.3 View configuration file information

  After the call, a Config object will be returned, which contains the two member variables besides the type Config.fromfile()obtained by parsing the configuration file mentioned above .ConfigDict_cfg_dicttextpretty_text

  textWhat is stored is _base_the original text information in each configuration file (files inherited in the include), which identifies the path of the configuration file.

  pretty_textIt is _cfg_dictthe formatted text of the dictionary content. MMCV internally uses Google's YAPF library to format the dictionary object so that the output conforms to people's reading habits. You can directly view the print(cfg.pretty_text)complete configuration file information, which mmdetection/tools/misc/print_config.pyis the same as MMDetection. .

  In addition, you can also view it conveniently by cfg.dump(filepath)storing pretty_textit in a file.

Guess you like

Origin blog.csdn.net/qq_16137569/article/details/121188974