原文链接:Tutorial 0: Learn about Configs — mmflow documentation
教程0:了解配置文件
我们把模块化和集成设计整合到我们的配置系统中,以便进行不同的实验。如果你想查看配置文件,只需要运行 python tools/misc/print_config.py /PATH/To/Config命令,就能查看完整的配置文件内容。
配置文件结构
在config/_base_目录下有四个基础部件,即datasets数据集,models模型,schedules训练策略和default_runtime默认的运行器。许多方法可以使用其中的模型(例如PWC_net)很容易地构建起来。由_base_中组成的配置称为原始配置或基础配置primitive。
对于相同路径下的所有配置,推荐只保留一个基础配置。其他所有的配置应该从基础配置中继承,最大的继承层数就是3。
为了便于理解,我们推荐贡献者们从现有的方法中继承。例如,如果你基于PWC-net进行了修改,你首先需要继承基础的PWC-Net结构,具体是通过指定
_base_ = ../pwcnet/pwnvet_slong_8x1_flyingchairs_384x448.py
然后再修改配置文件中必要的项。
当然如果你构建了一个全新的方法,和现有的的方法没有任何共享的结构,你可以在configs下创建一个新的xxx目录用于存放你的新方法。
参考MMCV Config — mmcv 1.7.0 documentation以获取详细文档。
配置文件命名规则
我们遵循一下风格来命名配置文件,建议贡献者们也使用下面的风格命名。
{model}_{schedule}_[gpu x batch_per_gpu]_{training datasets}_[input_size].py
其中{xxx}是必填项,[yyy]是可选项。
{model}: 模型类型,像pwcnet, flownet等;
{schedule}:训练策略,遵循flownet2的规则,我们使用slong, sfine和sshort,或者指明迭代次数,例如150k;
[gpu x batch_per_gpu]:GPU数量和每个GPU上的样本数,例如8x1;
{training datasets}:训练集;
[input_size]:训练数据的大小
配置系统
为了帮助使用者对mmflow中完整的配置和模块有一个基础的概念,我们对在FlyingChairs数据集上,使用PWCNet网络,以slong策略训练的配置文件做了一个简介。至于更详细的用法和对应的每个模块的其他一些操作,请参考API文档和MMDetection的教程:https://github.com/open-mmlab/mmdetection/blob/master/docs/tutorials/config.md
_base_ = [
'../_base_/models/pwcnet.py', '../_base_/datasets/flyingchairs_384x448.py',
'../_base_/schedules/schedule_s_long.py', '../_base_/default_runtime.py'
]# base config file which we build new config file on.
_base_/models/pwc_net.py是PWCNet的一个基础模型配置文件。
model = dict(
type='PWCNet', # 算法名称
encoder=dict( # 编码器的模块配置
type='PWCNetEncoder', # PWC-Net中编码器名称.
in_channels=3, # 输入通道数
# 子模块的类型,如果网络类型是基础类型Basic, 每一层金字塔的卷积层数量就是3,
# 如果网络类型是小网络Small, 每一层金字塔的卷积层数量就是2.
net_type='Basic',
pyramid_levels=[
'level1', 'level2', 'level3', 'level4', 'level5', 'level6'
], # 特征金字塔层级的列表,也就是输出字典的键值.
out_channels=(16, 32, 64, 96, 128, 196), # 每个金字塔层级的输出通道数的列表.
strides=(2, 2, 2, 2, 2, 2), # 每层金字塔的步长.
dilations=(1, 1, 1, 1, 1, 1), # 每层金字塔的扩展值.
act_cfg=dict(type='LeakyReLU', negative_slope=0.1)), # ConvModule模块中每个激活层的配置字典.
decoder=dict( # 解码器的模块配置.
type='PWCNetDecoder', # PWC-Net中解码器名称.
in_channels=dict(
level6=81, level5=213, level4=181, level3=149, level2=117), # 基础密集块的输入通道数.
flow_div=20., # 对应于真值的常数,一个尺度缩放因子.
corr_cfg=dict(type='Correlation', max_displacement=4, padding=0),
warp_cfg=dict(type='Warp'),
act_cfg=dict(type='LeakyReLU', negative_slope=0.1),
scaled=False, # 是否利用 计算相关性步骤中每个元素数量 进行尺度化
post_processor=dict(type='ContextNet', in_channels=565), # 后处理配置.
flow_loss=dict( # 损失函数配置.
type='MultiLevelEPE',
p=2,
reduction='sum',
weights={ # 不同层光流的权重.
'level2': 0.005,
'level3': 0.01,
'level4': 0.02,
'level5': 0.08,
'level6': 0.32
}),
),
# 模型训练和测试相关的配置
train_cfg=dict(),
test_cfg=dict(),
init_cfg=dict(
type='Kaiming',
nonlinearity='leaky_relu',
layer=['Conv2d', 'ConvTranspose2d'],
mode='fan_in',
bias=0))
在_base_/datasets/flyingchairs_384x448.py中,
dataset_type = 'FlyingChairs' # 数据集名称
data_root = 'data/FlyingChairs/data' # 数据集根目录
img_norm_cfg = dict(mean=[0., 0., 0.], std=[255., 255., 255], to_rgb=False)#图像归一化配置
train_pipeline = [ # 训练流程
dict(type='LoadImageFromFile'), # 载入图像
dict(type='LoadAnnotations'), # 载入光流
dict(type='ColorJitter', # 随机改变图像亮度、对比度、饱和度和色相(数据增强操作).
brightness=0.5, # 亮度改变量.
contrast=0.5, # 对比度改变量.
saturation=0.5, # 饱和度改变量.
hue=0.5), # 色相改变量.
dict(type='RandomGamma', gamma_range=(0.7, 1.5)), # 对图像随机gamma校正.
dict(type='Normalize', **img_norm_cfg), # 归一化配置,从img_norm_cfg字典中读取
dict(type='GaussianNoise', sigma_range=(0, 0.04), clamp_range=(0., 1.)), # 添加高斯噪声和在[0, 0.04]sigama范围内均匀采样;
dict(type='RandomFlip', prob=0.5, direction='horizontal'), # 随机水平翻转
dict(type='RandomFlip', prob=0.5, direction='vertical'), # 随机垂直翻转
# 随机仿射变换
# global_transform 和 relative_transform 的键值应该是下属子集
# ('translates', 'zoom', 'shear', 'rotate'). 每个键值关系必须满足下列规则:
# - translates: the translation ratios along x axis and y axis. Defaults
# to(0., 0.).
# - zoom: the min and max zoom ratios. Defaults to (1.0, 1.0).
# - shear: the min and max shear ratios. Defaults to (1.0, 1.0).
# - rotate: the min and max rotate degree. Defaults to (0., 0.).
dict(type='RandomAffine',
global_transform=dict(
translates=(0.05, 0.05),
zoom=(1.0, 1.5),
shear=(0.86, 1.16),
rotate=(-10., 10.)
),
relative_transform=dict(
translates=(0.00375, 0.00375),
zoom=(0.985, 1.015),
shear=(1.0, 1.0),
rotate=(-1.0, 1.0)
)),
dict(type='RandomCrop', crop_size=(384, 448)), # 随机裁剪图像和光流到大小为 (384, 448)
dict(type='DefaultFormatBundle'), # 简化格式化公共名称(包括 "img1", "img2" 和"flow_gt".)的流程,
dict(
type='Collect', # 从与特定任务相关的数据载入器中采集数据.
keys=['imgs', 'flow_gt'],
meta_keys=('img_fields', 'ann_fields', 'filename1', 'filename2',
'ori_filename1', 'ori_filename2', 'filename_flow',
'ori_filename_flow', 'ori_shape', 'img_shape',
'img_norm_cfg')),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations'),
dict(type='InputResize', exponent=4),
dict(type='Normalize', **img_norm_cfg),
dict(type='TestFormatBundle'), # # 简化格式化公共名称(包括 "img1", "img2")的流程
dict(
type='Collect',
keys=['imgs'], # 从与特定任务相关的数据载入器中采集数据.
meta_keys=('flow_gt', 'filename1', 'filename2', 'ori_filename1',
'ori_filename2', 'ori_shape', 'img_shape', 'img_norm_cfg',
'scale_factor', 'pad_shape')) # 图像元数据中的‘flow_gt'用于在线评估
]
data = dict(
train_dataloader=dict(
samples_per_gpu=1, # 单个GPU上批量大小batch size
workers_per_gpu=5, # 单个gpu上预抓取数据的个数
drop_last=True), # 是否丢弃最后一个非满的数据批次
val_dataloader=dict(
samples_per_gpu=1,
workers_per_gpu=2,
shuffle=False), # 是否对数据集重排序(洗牌).
test_dataloader=dict(
samples_per_gpu=1,
workers_per_gpu=2,
shuffle=False),
train=dict( # 训练集配置
type=dataset_type,
pipeline=train_pipeline,
data_root=data_root,
split_file='data/FlyingChairs_release/FlyingChairs_train_val.txt', # 训练和验证划分的文件
),
val=dict(
type=dataset_type,
pipeline=test_pipeline,
data_root=data_root,
test_mode=True),
test=dict(
type=dataset_type,
pipeline=test_pipeline,
data_root=data_root,
test_mode=True)
)
在_base_/schedules/schedule_s_long.py中,
# 优化器
optimizer = dict(
type='Adam', lr=0.0001, weight_decay=0.0004, betas=(0.9, 0.999))
optimizer_config = dict(grad_clip=None)
# 训练中的学习策略
lr_config = dict(
policy='step',
by_epoch=False,
gamma=0.5,
step=[400000, 600000, 800000, 1000000])
runner = dict(type='IterBasedRunner', max_iters=1200000)
checkpoint_config = dict(by_epoch=False, interval=100000)
evaluation = dict(interval=100000, metric='EPE')
在_base_/default_runtime.py中,
log_config = dict( # 注册日志的配置
interval=50, # 打印日志的间隔
hooks=[
dict(type='TextLoggerHook'),
dict(type='TensorboardLoggerHook')
]) # The logger used to record the training process.
dist_params = dict(backend='nccl') # 分布式训练的参数,可指定接口.
log_level = 'INFO' # 日志层级.
load_from = None # 从给定路径加载预训练模型,不会重置训练
workflow = [('train', 1)] # 运行器的流程. [('train', 1)] 表明只有一个流程,名称为train,只被执行一次
通过脚本参数修改配置
当使用 “tools/train.py” 或 “tools/test.py”脚本来提交任务时,可以指定--cfg-options参数就地修改配置。
*更新字典中配置的键值
配置选项可以通过在原始配置文件中,根据下列字典键值的顺序进行指定。例如--cfg-option model.encoder.in_channels=6
.
*更新一个配置列表中的键值
你的配置中有些配置的字典对象是由列表组成的。例如,训练流程train pipeline中data.train.pipelines一般就是一个list列表。例如,[dict(type='LoadImageFromFile'), ...]
如果在这个流程中你想把'LoadImageFromFile'
改为 'LoadImageFromWebcam',可以通过指定
--cfg-options data.train.pipeline.0.type=LoadImageFromWebcam来实现
*更新list列表或tuple元组的值
如果被更新的值是列表或元组,例如配置文件通常会设置workflow=[('train', 1)]。如果你想修改键值,可以通过--cfg-options workflow="[(train,1),(val,1)]"实现。注意,引号"不可缺少,并且没有空格。