mmpose/docs/zh_cn/user_guides/configs.md

503 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 如何看懂配置文件
MMPose 使用 Python 文件作为配置文件,将模块化设计和继承设计结合到配置系统中,便于进行各种实验。
## 目录结构
MMPose 的配置文件目录结构如下:
```shell
configs
|----_base_
|----datasets
|----default_runtime.py
|----animal_2d_keypoint
|----body_2d_keypoint
|----body_3d_keypoint
|----face_2d_keypoint
|----fashion_2d_keypoint
|----hand_2d_keypoint
|----hand_3d_keypoint
|----wholebody_2d_keypoint
```
## 简介
MMPose 拥有一套强大的配置系统,在注册器的配合下,用户可以通过一个配置文件来定义整个项目需要用到的所有内容,以 Python 字典形式组织配置信息,传递给注册器完成对应模块的实例化。
下面是一个常见的 Pytorch 模块定义的例子:
```Python
# 在loss_a.py中定义Loss_A类
Class Loss_A(nn.Module):
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def forward(self, x):
return x
# 在需要的地方进行实例化
loss = Loss_A(param1=1.0, param2=True)
```
只需要通过一行代码对这个类进行注册:
```Python
# 在loss_a.py中定义Loss_A类
from mmpose.registry import MODELS
@MODELS.register_module() # 注册该类到 MODELS 下
Class Loss_A(nn.Module):
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def forward(self, x):
return x
```
并在对应目录下的 `__init__.py` 中进行 `import`
```Python
# __init__.py of mmpose/models/losses
from .loss_a.py import Loss_A
__all__ = ['Loss_A']
```
我们就可以通过如下方式来从配置文件定义并进行实例化:
```Python
# 在config_file.py中定义
loss_cfg = dict(
type='Loss_A', # 通过type指定类名
param1=1.0, # 传递__init__所需的参数
param2=True
)
# 在需要的地方进行实例化
loss = MODELS.build(loss_cfg) # 等价于 loss = Loss_A(param1=1.0, param2=True)
```
MMPose 预定义的 Registry 在 `$MMPOSE/mmpose/registry.py` 中,目前支持的有:
- `DATASETS`:数据集
- `TRANSFORMS`:数据变换
- `MODELS`模型模块Backbone、Neck、Head、Loss等
- `VISUALIZERS`:可视化工具
- `VISBACKENDS`:可视化后端
- `METRICS`:评测指标
- `KEYPOINT_CODECS`:编解码器
- `HOOKS`:钩子类
```{note}
需要注意的是所有新增的模块都需要使用注册器Registry进行注册并在对应目录的 `__init__.py` 中进行 `import`,以便能够使用配置文件构建其实例。
```
## 配置系统
具体而言,一个配置文件主要包含如下五个部分:
- 通用配置:与训练或测试无关的通用配置,如时间统计,模型存储与加载,可视化等相关 Hook以及一些分布式相关的环境配置
- 数据配置数据增强策略Dataset和Dataloader相关配置
- 训练配置:断点恢复、模型权重加载、优化器、学习率调整、训练轮数和测试间隔等
- 模型配置:模型模块、参数、损失函数等
- 评测配置:模型性能评测指标
你可以在 `$MMPOSE/configs` 下找到我们提供的配置文件,配置文件之间通过继承来避免冗余。为了保持配置文件简洁易读,我们将一些必要但不常改动的配置存放到了 `$MMPOSE/configs/_base_` 目录下,如果希望查阅完整的配置信息,你可以运行如下指令:
```Bash
python tools/analysis/print_config.py /PATH/TO/CONFIG
```
### 通用配置
通用配置指与训练或测试无关的必要配置,主要包括:
- **默认Hook**迭代时间统计训练日志参数更新checkpoint 等
- **环境配置**分布式后端cudnn多进程配置等
- **可视化器**:可视化后端和策略设置
- **日志配置**:日志等级,格式,打印和记录间隔等
下面是通用配置的样例说明:
```Python
# 通用配置
default_scope = 'mmpose'
default_hooks = dict(
# 迭代时间统计,包括数据耗时和模型耗时
timer=dict(type='IterTimerHook'),
# 日志打印间隔,默认每 50 iters 打印一次
logger=dict(type='LoggerHook', interval=50),
# 用于调度学习率更新的 Hook
param_scheduler=dict(type='ParamSchedulerHook'),
checkpoint=dict(
# ckpt 保存间隔,最优 ckpt 参考指标。
# 例如:
# save_best='coco/AP' 代表以 coco/AP 作为最优指标,对应 CocoMetric 评测器的 AP 指标
# save_best='PCK' 代表以 PCK 作为最优指标,对应 PCKAccuracy 评测器的 PCK 指标
# 更多指标请前往 mmpose/evaluation/metrics/
type='CheckpointHook', interval=1, save_best='coco/AP',
# 最优 ckpt 保留规则greater 代表越大越好less 代表越小越好
rule='greater'),
# 分布式随机种子设置 Hook
sampler_seed=dict(type='DistSamplerSeedHook'))
env_cfg = dict(
# cudnn benchmark 开关,用于加速训练,但会增加显存占用
cudnn_benchmark=False,
# opencv 多线程配置,用于加速数据加载,但会增加显存占用
# 默认为 0代表使用单线程
mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
# 分布式训练后端设置,支持 nccl 和 gloo
dist_cfg=dict(backend='nccl'))
# 可视化器后端设置,默认为本地可视化
vis_backends = [dict(type='LocalVisBackend')]
# 可视化器设置
visualizer = dict(
type='PoseLocalVisualizer',
vis_backends=[dict(type='LocalVisBackend')],
name='visualizer')
log_processor = dict( # 训练日志格式、间隔
type='LogProcessor', window_size=50, by_epoch=True, num_digits=6)
# 日志记录等级INFO 代表记录训练日志WARNING 代表只记录警告信息ERROR 代表只记录错误信息
log_level = 'INFO'
```
```{note}
可视化器后端设置支持 LocalVisBackend 和 TensorboardVisBackend前者用于本地可视化后者用于 Tensorboard 可视化,你可以根据需要进行选择。详情见 [训练与测试](./train_and_test.md) 的 【可视化训练进程】。
```
通用配置一般单独存放到 `$MMPOSE/configs/_base_` 目录下,通过如下方式进行继承:
```Python
_base_ = ['../../../_base_/default_runtime.py'] # 以运行时的config文件位置为相对路径起点
```
### 数据配置
数据配置指数据处理相关的配置,主要包括:
- **数据后端**:数据供给后端设置,默认为本地硬盘,我们也支持从 LMDBS3 Bucket 等加载
- **数据集**:图像与标注文件路径
- **加载**:加载策略,批量大小等
- **流水线**:数据增强策略
- **编码器**:根据标注生成特定格式的监督信息
下面是数据配置的样例说明:
```Python
backend_args = dict(backend='local') # 数据加载后端设置,默认从本地硬盘加载
dataset_type = 'CocoDataset' # 数据集类名
data_mode = 'topdown' # 算法结构类型,用于指定标注信息加载策略
data_root = 'data/coco/' # 数据存放路径
# 定义数据编解码器用于生成target和对pred进行解码同时包含了输入图片和输出heatmap尺寸等信息
codec = dict(
type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2)
train_pipeline = [ # 训练时数据增强
dict(type='LoadImage', backend_args=backend_args, # 加载图片
dict(type='GetBBoxCenterScale'), # 根据bbox获取center和scale
dict(type='RandomBBoxTransform'), # 生成随机位移、缩放、旋转变换矩阵
dict(type='RandomFlip', direction='horizontal'), # 生成随机翻转变换矩阵
dict(type='RandomHalfBody'), # 随机半身增强
dict(type='TopdownAffine', input_size=codec['input_size']), # 根据变换矩阵更新目标数据
dict(
type='GenerateTarget', # 根据目标数据生成监督信息
# 监督信息类型
encoder=codec, # 传入编解码器,用于数据编码,生成特定格式的监督信息
dict(type='PackPoseInputs') # 对target进行打包用于训练
]
test_pipeline = [ # 测试时数据增强
dict(type='LoadImage', backend_args=backend_args), # 加载图片
dict(type='GetBBoxCenterScale'), # 根据bbox获取center和scale
dict(type='TopdownAffine', input_size=codec['input_size']), # 根据变换矩阵更新目标数据
dict(type='PackPoseInputs') # 对target进行打包用于训练
]
train_dataloader = dict( # 训练数据加载
batch_size=64, # 批次大小
num_workers=2, # 数据加载进程数
persistent_workers=True, # 在不活跃时维持进程不终止,避免反复启动进程的开销
sampler=dict(type='DefaultSampler', shuffle=True), # 采样策略,打乱数据
dataset=dict(
type=dataset_type , # 数据集类名
data_root=data_root, # 数据集路径
data_mode=data_mode, # 算法类型
ann_file='annotations/person_keypoints_train2017.json', # 标注文件路径
data_prefix=dict(img='train2017/'), # 图像路径
pipeline=train_pipeline # 数据流水线
))
val_dataloader = dict(
batch_size=32,
num_workers=2,
persistent_workers=True, # 在不活跃时维持进程不终止,避免反复启动进程的开销
drop_last=False,
sampler=dict(type='DefaultSampler', shuffle=False), # 采样策略,不进行打乱
dataset=dict(
type=dataset_type , # 数据集类名
data_root=data_root, # 数据集路径
data_mode=data_mode, # 算法类型
ann_file='annotations/person_keypoints_val2017.json', # 标注文件路径
bbox_file=
'data/coco/person_detection_results/COCO_val2017_detections_AP_H_56_person.json', # 检测框标注文件topdown方法专用
data_prefix=dict(img='val2017/'), # 图像路径
test_mode=True, # 测试模式开关
pipeline=test_pipeline # 数据流水线
))
test_dataloader = val_dataloader # 默认情况下不区分验证集和测试集,用户根据需要来自行定义
```
```{note}
常用功能可以参考以下教程:
- [恢复训练](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/train_and_test.html#id7)
- [自动混合精度训练](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/train_and_test.html#amp)
- [设置随机种子](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/train_and_test.html#id10)
```
### 训练配置
训练配置指训练策略相关的配置,主要包括:
- 从断点恢复训练
- 模型权重加载
- 训练轮数和测试间隔
- 学习率调整策略,如 warmupscheduler
- 优化器和学习率
- 高级训练策略设置,如自动学习率缩放
下面是训练配置的样例说明:
```Python
resume = False # 断点恢复
load_from = None # 模型权重加载
train_cfg = dict(by_epoch=True, max_epochs=210, val_interval=10) # 训练轮数,测试间隔
param_scheduler = [
dict( # warmup策略
type='LinearLR', begin=0, end=500, start_factor=0.001, by_epoch=False),
dict( # scheduler
type='MultiStepLR',
begin=0,
end=210,
milestones=[170, 200],
gamma=0.1,
by_epoch=True)
]
optim_wrapper = dict(optimizer=dict(type='Adam', lr=0.0005)) # 优化器和学习率
auto_scale_lr = dict(base_batch_size=512) # 根据batch_size自动缩放学习率
```
### 模型配置
模型配置指模型训练和推理相关的配置,主要包括:
- 模型结构
- 损失函数
- 数据解码策略
- 测试时增强策略
下面是模型配置的样例说明,定义了一个基于 HRNetw32 的 Top-down Heatmap-based 模型:
```Python
# 定义数据编解码器,如果在数据配置部分已经定义过则无需重复定义
codec = dict(
type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2)
# 模型配置
model = dict(
type='TopdownPoseEstimator', # 模型结构决定了算法流程
data_preprocessor=dict( # 数据归一化和通道顺序调整,作为模型的一部分
type='PoseDataPreprocessor',
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
bgr_to_rgb=True),
backbone=dict( # 骨干网络定义
type='HRNet',
in_channels=3,
extra=dict(
stage1=dict(
num_modules=1,
num_branches=1,
block='BOTTLENECK',
num_blocks=(4, ),
num_channels=(64, )),
stage2=dict(
num_modules=1,
num_branches=2,
block='BASIC',
num_blocks=(4, 4),
num_channels=(32, 64)),
stage3=dict(
num_modules=4,
num_branches=3,
block='BASIC',
num_blocks=(4, 4, 4),
num_channels=(32, 64, 128)),
stage4=dict(
num_modules=3,
num_branches=4,
block='BASIC',
num_blocks=(4, 4, 4, 4),
num_channels=(32, 64, 128, 256))),
init_cfg=dict(
type='Pretrained', # 预训练参数只加载backbone权重用于迁移学习
checkpoint='https://download.openmmlab.com/mmpose'
'/pretrain_models/hrnet_w32-36af842e.pth'),
),
head=dict( # 模型头部
type='HeatmapHead',
in_channels=32,
out_channels=17,
deconv_out_channels=None,
loss=dict(type='KeypointMSELoss', use_target_weight=True), # 损失函数
decoder=codec), # 解码器将heatmap解码成坐标值
test_cfg=dict(
flip_test=True, # 开启测试时水平翻转集成
flip_mode='heatmap', # 对heatmap进行翻转
shift_heatmap=True, # 对翻转后的结果进行平移提高精度
))
```
### 评测配置
评测配置指公开数据集中关键点检测任务常用的评测指标,主要包括:
- AR, AP and mAP
- PCK, PCKh, tPCK
- AUC
- EPE
- NME
下面是评测配置的样例说明定义了一个COCO指标评测器
```Python
val_evaluator = dict(
type='CocoMetric', # coco 评测指标
ann_file=data_root + 'annotations/person_keypoints_val2017.json') # 加载评测标注数据
test_evaluator = val_evaluator # 默认情况下不区分验证集和测试集,用户根据需要来自行定义
```
## 配置文件命名规则
MMPose 配置文件命名风格如下:
```Python
{{算法信息}}_{{模块信息}}_{{训练信息}}_{{数据信息}}.py
```
文件名总体分为四部分:算法信息,模块信息,训练信息和数据信息。不同部分的单词之间用下划线 `'_'` 连接,同一部分有多个单词用短横线 `'-'` 连接。
- **算法信息**:算法名称,如 `topdown-heatmap``topdown-rle` 等
- **模块信息**:按照数据流的顺序列举一些中间的模块,其内容依赖于算法任务,如 `res101``hrnet-w48`等
- **训练信息**:训练策略的一些设置,包括 `batch size``schedule` 等,如 `8xb64-210e`
- **数据信息**:数据集名称、模态、输入尺寸等,如 `ap10k-256x256``zebra-160x160` 等
有时为了避免文件名过长会省略模型信息中一些强相关的模块只保留关键信息如RLE-based算法中的`GAP`Heatmap-based算法中的 `deconv` 等。
如果你希望向MMPose添加新的方法你的配置文件同样需要遵守该命名规则。
## 常见用法
### 配置文件的继承
该用法常用于隐藏一些必要但不需要修改的配置,以提高配置文件的可读性。假如有如下两个配置文件:
`optimizer_cfg.py`:
```Python
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
```
`resnet50.py`:
```Python
_base_ = ['optimizer_cfg.py']
model = dict(type='ResNet', depth=50)
```
虽然我们在 `resnet50.py` 中没有定义 optimizer 字段,但由于我们写了 `_base_ = ['optimizer_cfg.py']`,会使这个配置文件获得 `optimizer_cfg.py` 中的所有字段:
```Python
cfg = Config.fromfile('resnet50.py')
cfg.optimizer # ConfigDict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
```
### 继承字段的修改
对于继承过来的已经定义好的字典,可以直接指定对应字段进行修改,而不需要重新定义完整的字典:
`resnet50_lr0.01.py`:
```Python
_base_ = ['optimizer_cfg.py']
model = dict(type='ResNet', depth=50)
optimizer = dict(lr=0.01) # 直接修改对应字段
```
这个配置文件只修改了对应字段`lr`的信息:
```Python
cfg = Config.fromfile('resnet50_lr0.01.py')
cfg.optimizer # ConfigDict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)
```
### 删除字典中的字段
如果不仅是需要修改某些字段,还需要删除已定义的一些字段,需要在重新定义这个字典时指定`_delete_=True`,表示将没有在新定义中出现的字段全部删除:
`resnet50.py`:
```Python
_base_ = ['optimizer_cfg.py', 'runtime_cfg.py']
model = dict(type='ResNet', depth=50)
optimizer = dict(_delete_=True, type='SGD', lr=0.01) # 重新定义字典
```
此时字典中除了 `type``lr` 以外的内容(`momentum`和`weight_decay`)将被全部删除:
```Python
cfg = Config.fromfile('resnet50_lr0.01.py')
cfg.optimizer # ConfigDict(type='SGD', lr=0.01)
```
```{note}
如果你希望更深入地了解配置系统的高级用法,可以查看 [MMEngine 教程](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)。
```