Shortcuts

备注

您正在阅读 MMClassification 0.x 版本的文档。MMClassification 0.x 会在 2022 年末被切换为次要分支。建议您升级到 MMClassification 1.0 版本,体验更多新特性和新功能。请查阅 MMClassification 1.0 的安装教程迁移教程以及更新日志

教程 1:如何编写配置文件

MMClassification 主要使用 python 文件作为配置文件。其配置文件系统的设计将模块化与继承整合进来,方便用户进行各种实验。所有配置文件都放置在 configs 文件夹下,主要包含 _base_ 原始配置文件夹 以及 resnet, swin_transformervision_transformer 等诸多算法文件夹。

可以使用 python tools/misc/print_config.py /PATH/TO/CONFIG 命令来查看完整的配置信息,从而方便检查所对应的配置文件。

配置文件以及权重命名规则

MMClassification 按照以下风格进行配置文件命名,代码库的贡献者需要遵循相同的命名规则。文件名总体分为四部分:算法信息,模块信息,训练信息和数据信息。逻辑上属于不同部分的单词之间用下划线 '_' 连接,同一部分有多个单词用短横线 '-' 连接。

{algorithm info}_{module info}_{training info}_{data info}.py
  • algorithm info:算法信息,算法名称或者网络架构,如 resnet 等;

  • module info: 模块信息,因任务而异,用以表示一些特殊的 neck、head 和 pretrain 信息;

  • training info:一些训练信息,训练策略设置,包括 batch size,schedule 数据增强等;

  • data info:数据信息,数据集名称、模态、输入尺寸等,如 imagenet, cifar 等;

算法信息

指论文中的算法名称缩写,以及相应的分支架构信息。例如:

  • resnet50

  • mobilenet-v3-large

  • vit-small-patch32 : patch32 表示 ViT 切分的分块大小

  • seresnext101-32x4d : SeResNet101 基本网络结构,32x4d 表示在 Bottleneckgroupswidth_per_group 分别为32和4

模块信息

指一些特殊的 neckhead 或者 pretrain 的信息, 在分类中常见为预训练信息,比如:

  • in21k-pre : 在 ImageNet21k 上预训练

  • in21k-pre-3rd-party : 在 ImageNet21k 上预训练,其权重来自其他仓库

训练信息

训练策略的一些设置,包括训练类型、 batch sizelr schedule、 数据增强以及特殊的损失函数等等,比如: Batch size 信息:

  • 格式为{gpu x batch_per_gpu}, 如 8xb32

训练类型(主要见于 transformer 网络,如 ViT 算法,这类算法通常分为预训练和微调两种模式):

  • ft : Finetune config,用于微调的配置文件

  • pt : Pretrain config,用于预训练的配置文件

训练策略信息,训练策略以复现配置文件为基础,此基础不必标注训练策略。但如果在此基础上进行改进,则需注明训练策略,按照应用点位顺序排列,如:{pipeline aug}-{train aug}-{loss trick}-{scheduler}-{epochs}

  • coslr-200e : 使用 cosine scheduler, 训练 200 个 epoch

  • autoaug-mixup-lbs-coslr-50e : 使用了 autoaugmixuplabel smoothcosine scheduler, 训练了 50 个轮次

数据信息

  • in1k : ImageNet1k 数据集,默认使用 224x224 大小的图片

  • in21k : ImageNet21k 数据集,有些地方也称为 ImageNet22k 数据集,默认使用 224x224 大小的图片

  • in1k-384px : 表示训练的输出图片大小为 384x384

  • cifar100

配置文件命名案例:

repvgg-D2se_deploy_4xb64-autoaug-lbs-mixup-coslr-200e_in1k.py
  • repvgg-D2se: 算法信息

    • repvgg: 主要算法名称。

    • D2se: 模型的结构。

  • deploy:模块信息,该模型为推理状态。

  • 4xb64-autoaug-lbs-mixup-coslr-200e: 训练信息

    • 4xb64: 使用4块 GPU 并且 每块 GPU 的批大小为64。

    • autoaug: 使用 AutoAugment 数据增强方法。

    • lbs: 使用 label smoothing 损失函数。

    • mixup: 使用 mixup 训练增强方法。

    • coslr: 使用 cosine scheduler 优化策略。

    • 200e: 训练 200 轮次。

  • in1k: 数据信息。 配置文件用于 ImageNet1k 数据集上使用 224x224 大小图片训练。

备注

部分配置文件目前还没有遵循此命名规范,相关文件命名近期会更新。

权重命名规则

权重的命名主要包括配置文件名,日期和哈希值。

{config_name}_{date}-{hash}.pth

配置文件结构

configs/_base_ 文件夹下有 4 个基本组件类型,分别是:

你可以通过继承一些基本配置文件轻松构建自己的训练配置文件。由来自_base_ 的组件组成的配置称为 primitive

为了帮助用户对 MMClassification 检测系统中的完整配置和模块有一个基本的了解,我们使用 ResNet50 原始配置文件 作为案例进行说明并注释每一行含义。更详细的用法和各个模块对应的替代方案,请参考 API 文档。

_base_ = [
    '../_base_/models/resnet50.py',           # 模型
    '../_base_/datasets/imagenet_bs32.py',    # 数据
    '../_base_/schedules/imagenet_bs256.py',  # 训练策略
    '../_base_/default_runtime.py'            # 默认运行设置
]

下面对这四个部分分别进行说明,仍然以上述 ResNet50 原始配置文件作为案例。

模型

模型参数 model 在配置文件中为一个 python 字典,主要包括网络结构、损失函数等信息:

  • type : 分类器名称, 目前 MMClassification 只支持 ImageClassifier, 参考 API 文档

  • backbone : 主干网类型,可用选项参考 API 文档

  • neck : 颈网络类型,目前 MMClassification 只支持 GlobalAveragePooling, 参考 API 文档

  • head : 头网络类型, 包括单标签分类与多标签分类头网络,可用选项参考 API 文档

  • train_cfg :训练配置, 支持 mixup, cutmix 等训练增强。

备注

配置文件中的 ‘type’ 不是构造时的参数,而是类名。

model = dict(
    type='ImageClassifier',     # 分类器类型
    backbone=dict(
        type='ResNet',          # 主干网络类型
        depth=50,               # 主干网网络深度, ResNet 一般有18, 34, 50, 101, 152 可以选择
        num_stages=4,           # 主干网络状态(stages)的数目,这些状态产生的特征图作为后续的 head 的输入。
        out_indices=(3, ),      # 输出的特征图输出索引。越远离输入图像,索引越大
        frozen_stages=-1,       # 网络微调时,冻结网络的stage(训练时不执行反相传播算法),若num_stages=4,backbone包含stem 与 4 个 stages。frozen_stages为-1时,不冻结网络; 为0时,冻结 stem; 为1时,冻结 stem 和 stage1; 为4时,冻结整个backbone
        style='pytorch'),       # 主干网络的风格,'pytorch' 意思是步长为2的层为 3x3 卷积, 'caffe' 意思是步长为2的层为 1x1 卷积。
    neck=dict(type='GlobalAveragePooling'),    # 颈网络类型
    head=dict(
        type='LinearClsHead',     # 线性分类头,
        num_classes=1000,         # 输出类别数,这与数据集的类别数一致
        in_channels=2048,         # 输入通道数,这与 neck 的输出通道一致
        loss=dict(type='CrossEntropyLoss', loss_weight=1.0), # 损失函数配置信息
        topk=(1, 5),              # 评估指标,Top-k 准确率, 这里为 top1 与 top5 准确率
    ))

数据

数据参数 data 在配置文件中为一个 python 字典,主要包含构造数据集加载器(dataloader)配置信息:

  • samples_per_gpu : 构建 dataloader 时,每个 GPU 的 Batch Size

  • workers_per_gpu : 构建 dataloader 时,每个 GPU 的 线程数

  • train val test : 构造数据集

    • type : 数据集类型, MMClassification 支持 ImageNetCifar 等 ,参考API 文档

    • data_prefix : 数据集根目录

    • pipeline : 数据处理流水线,参考相关教程文档 如何设计数据处理流水线

评估参数 evaluation 也是一个字典, 为 evaluation hook 的配置信息, 主要包括评估间隔、评估指标等。

# dataset settings
dataset_type = 'ImageNet'  # 数据集名称,
img_norm_cfg = dict(       #图像归一化配置,用来归一化输入的图像。
    mean=[123.675, 116.28, 103.53],  # 预训练里用于预训练主干网络模型的平均值。
    std=[58.395, 57.12, 57.375],     # 预训练里用于预训练主干网络模型的标准差。
    to_rgb=True)                     # 是否反转通道,使用 cv2, mmcv 读取图片默认为 BGR 通道顺序,这里 Normalize 均值方差数组的数值是以 RGB 通道顺序, 因此需要反转通道顺序。
# 训练数据流水线
train_pipeline = [
    dict(type='LoadImageFromFile'),                # 读取图片
    dict(type='RandomResizedCrop', size=224),      # 随机缩放抠图
    dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),  # 以概率为0.5随机水平翻转图片
    dict(type='Normalize', **img_norm_cfg),        # 归一化
    dict(type='ImageToTensor', keys=['img']),      # image 转为 torch.Tensor
    dict(type='ToTensor', keys=['gt_label']),      # gt_label 转为 torch.Tensor
    dict(type='Collect', keys=['img', 'gt_label']) # 决定数据中哪些键应该传递给检测器的流程
]
# 测试数据流水线
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='Resize', size=(256, -1)),
    dict(type='CenterCrop', crop_size=224),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='Collect', keys=['img'])             # test 时不传递 gt_label
]
data = dict(
    samples_per_gpu=32,    # 单个 GPU 的 Batch size
    workers_per_gpu=2,     # 单个 GPU 的 线程数
    train=dict(            # 训练数据信息
        type=dataset_type,                  # 数据集名称
        data_prefix='data/imagenet/train',  # 数据集目录,当不存在 ann_file 时,类别信息从文件夹自动获取
        pipeline=train_pipeline),           # 数据集需要经过的 数据流水线
    val=dict(              # 验证数据集信息
        type=dataset_type,
        data_prefix='data/imagenet/val',
        ann_file='data/imagenet/meta/val.txt',   # 标注文件路径,存在 ann_file 时,不通过文件夹自动获取类别信息
        pipeline=test_pipeline),
    test=dict(             # 测试数据集信息
        type=dataset_type,
        data_prefix='data/imagenet/val',
        ann_file='data/imagenet/meta/val.txt',
        pipeline=test_pipeline))
evaluation = dict(       # evaluation hook 的配置
    interval=1,          # 验证期间的间隔,单位为 epoch 或者 iter, 取决于 runner 类型。
    metric='accuracy')   # 验证期间使用的指标。

训练策略

主要包含 优化器设置、 optimizer hook 设置、学习率策略和 runner设置:

  • optimizer : 优化器设置信息, 支持 pytorch 所有的优化器,参考相关 mmcv 文档

  • optimizer_config : optimizer hook 的配置文件,如设置梯度限制,参考相关 mmcv 代码

  • lr_config : 学习率策略,支持 “CosineAnnealing”、 “Step”、 “Cyclic” 等等,参考相关 mmcv 文档

  • runner : 有关 runner 可以参考 mmcv 对于 runner 介绍文档

# 用于构建优化器的配置文件。支持 PyTorch 中的所有优化器,同时它们的参数与 PyTorch 里的优化器参数一致。
optimizer = dict(type='SGD',         # 优化器类型
                lr=0.1,              # 优化器的学习率,参数的使用细节请参照对应的 PyTorch 文档。
                momentum=0.9,        # 动量(Momentum)
                weight_decay=0.0001) # 权重衰减系数(weight decay)。
 # optimizer hook 的配置文件
optimizer_config = dict(grad_clip=None)  # 大多数方法不使用梯度限制(grad_clip)。
# 学习率调整配置,用于注册 LrUpdater hook。
lr_config = dict(policy='step',          # 调度流程(scheduler)的策略,也支持 CosineAnnealing, Cyclic, 等。
                 step=[30, 60, 90])      # 在 epoch 为 30, 60, 90 时, lr 进行衰减
runner = dict(type='EpochBasedRunner',   # 将使用的 runner 的类别,如 IterBasedRunner 或 EpochBasedRunner。
            max_epochs=100)              # runner 总回合数, 对于 IterBasedRunner 使用 `max_iters`

运行设置

本部分主要包括保存权重策略、日志配置、训练参数、断点权重路径和工作目录等等。

# Checkpoint hook 的配置文件。
checkpoint_config = dict(interval=1)   # 保存的间隔是 1,单位会根据 runner 不同变动,可以为 epoch 或者 iter。
# 日志配置信息。
log_config = dict(
    interval=100,                      # 打印日志的间隔, 单位 iters
    hooks=[
        dict(type='TextLoggerHook'),          # 用于记录训练过程的文本记录器(logger)。
        # dict(type='TensorboardLoggerHook')  # 同样支持 Tensorboard 日志
    ])

dist_params = dict(backend='nccl')   # 用于设置分布式训练的参数,端口也同样可被设置。
log_level = 'INFO'             # 日志的输出级别。
resume_from = None             # 从给定路径里恢复检查点(checkpoints),训练模式将从检查点保存的轮次开始恢复训练。
workflow = [('train', 1)]      # runner 的工作流程,[('train', 1)] 表示只有一个工作流且工作流仅执行一次。
work_dir = 'work_dir'          # 用于保存当前实验的模型检查点和日志的目录文件地址。

继承并修改配置文件

为了精简代码、更快的修改配置文件以及便于理解,我们建议继承现有方法。

对于在同一算法文件夹下的所有配置文件,MMClassification 推荐只存在 一个 对应的 原始配置 文件。 所有其他的配置文件都应该继承 原始配置 文件,这样就能保证配置文件的最大继承深度为 3。

例如,如果在 ResNet 的基础上做了一些修改,用户首先可以通过指定 _base_ = './resnet50_8xb32_in1k.py'(相对于你的配置文件的路径),来继承基础的 ResNet 结构、数据集以及其他训练配置信息,然后修改配置文件中的必要参数以完成继承。如想在基础 resnet50 的基础上将训练轮数由 100 改为 300 和修改学习率衰减轮数,同时修改数据集路径,可以建立新的配置文件 configs/resnet/resnet50_8xb32-300e_in1k.py, 文件中写入以下内容:

_base_ = './resnet50_8xb32_in1k.py'

runner = dict(max_epochs=300)
lr_config = dict(step=[150, 200, 250])

data = dict(
    train=dict(data_prefix='mydata/imagenet/train'),
    val=dict(data_prefix='mydata/imagenet/train', ),
    test=dict(data_prefix='mydata/imagenet/train', )
)

使用配置文件里的中间变量

用一些中间变量,中间变量让配置文件更加清晰,也更容易修改。

例如数据集里的 train_pipeline / test_pipeline 是作为数据流水线的中间变量。我们首先要定义 train_pipeline / test_pipeline,然后将它们传递到 data 中。如果想修改训练或测试时输入图片的大小,就需要修改 train_pipeline / test_pipeline 这些中间变量。

img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='RandomResizedCrop', size=384, backend='pillow',),
    dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='ToTensor', keys=['gt_label']),
    dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='Resize', size=384, backend='pillow'),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='Collect', keys=['img'])
]
data = dict(
    train=dict(pipeline=train_pipeline),
    val=dict(pipeline=test_pipeline),
    test=dict(pipeline=test_pipeline))

忽略基础配置文件里的部分内容

有时,您需要设置 _delete_=True 去忽略基础配置文件里的一些域内容。 可以参照 mmcv 来获得一些简单的指导。

以下是一个简单应用案例。 如果在上述 ResNet50 案例中 使用 cosine schedule ,使用继承并直接修改会报 get unexcepected keyword 'step' 错, 因为基础配置文件 lr_config 域信息的 'step' 字段被保留下来了,需要加入 _delete_=True 去忽略基础配置文件里的 lr_config 相关域内容:

_base_ = '../../configs/resnet/resnet50_8xb32_in1k.py'

lr_config = dict(
    _delete_=True,
    policy='CosineAnnealing',
    min_lr=0,
    warmup='linear',
    by_epoch=True,
    warmup_iters=5,
    warmup_ratio=0.1
)

引用基础配置文件里的变量

有时,您可以引用 _base_ 配置信息的一些域内容,这样可以避免重复定义。 可以参照 mmcv 来获得一些简单的指导。

以下是一个简单应用案例,在训练数据预处理流水线中使用 auto augment 数据增强,参考配置文件 configs/_base_/datasets/imagenet_bs64_autoaug.py。 在定义 train_pipeline 时,可以直接在 _base_ 中加入定义 auto augment 数据增强的文件命名,再通过 {{_base_.auto_increasing_policies}} 引用变量:

_base_ = ['./pipelines/auto_aug.py']

# dataset settings
dataset_type = 'ImageNet'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='RandomResizedCrop', size=224),
    dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
    dict(type='AutoAugment', policies={{_base_.auto_increasing_policies}}),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='ToTensor', keys=['gt_label']),
    dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [...]
data = dict(
    samples_per_gpu=64,
    workers_per_gpu=2,
    train=dict(..., pipeline=train_pipeline),
    val=dict(..., pipeline=test_pipeline))
evaluation = dict(interval=1, metric='accuracy')

通过命令行参数修改配置信息

当用户使用脚本 “tools/train.py” 或者 “tools/test.py” 提交任务,以及使用一些工具脚本时,可以通过指定 --cfg-options 参数来直接修改所使用的配置文件内容。

  • 更新配置文件内的字典

    可以按照原始配置文件中字典的键的顺序指定配置选项。 例如,--cfg-options model.backbone.norm_eval=False 将主干网络中的所有 BN 模块更改为 train 模式。

  • 更新配置文件内列表的键

    一些配置字典在配置文件中会形成一个列表。例如,训练流水线 data.train.pipeline 通常是一个列表。 例如,[dict(type='LoadImageFromFile'), dict(type='TopDownRandomFlip', flip_prob=0.5), ...] 。如果要将流水线中的 'flip_prob=0.5' 更改为 'flip_prob=0.0',您可以这样指定 --cfg-options data.train.pipeline.1.flip_prob=0.0

  • 更新列表/元组的值。

    当配置文件中需要更新的是一个列表或者元组,例如,配置文件通常会设置 workflow=[('train', 1)],用户如果想更改, 需要指定 --cfg-options workflow="[(train,1),(val,1)]"。注意这里的引号 ” 对于列表以及元组数据类型的修改是必要的, 并且 不允许 引号内所指定的值的书写存在空格。

导入用户自定义模块

备注

本部分仅在当将 MMClassification 当作库构建自己项目时可能用到,初学者可跳过。

在学习完后续教程 如何添加新数据集如何设计数据处理流程如何增加新模块 后,您可能使用 MMClassification 完成自己的项目并在项目中自定义了数据集、模型、数据增强等。为了精简代码,可以将 MMClassification 作为一个第三方库,只需要保留自己的额外的代码,并在配置文件中导入自定义的模块。案例可以参考 OpenMMLab 算法大赛项目

只需要在你的配置文件中添加以下代码:

custom_imports = dict(
    imports=['your_dataset_class',
             'your_transforme_class',
             'your_model_class',
             'your_module_class'],
    allow_failed_imports=False)

常见问题

Read the Docs v: mmcls-0.x
Versions
latest
stable
mmcls-1.x
mmcls-0.x
dev
Downloads
pdf
html
epub
On Read the Docs
Project Home
Builds

Free document hosting provided by Read the Docs.