MMYOLO配置详解
- 1. 简介
- 1.1 配置文件主要内容
- 1. 2 配置文件名称含义
- 2. 配置文件内容
- 2.1 重要参数
- 2.2 模型(model)配置
- 2.3 Dataloader
- 2.3.1 训练Dataloader (train_dataloader)
- 2.3.1 验证和评测Dataloader (val_dataloader+test_dataloader)
- 2.4 评测器(val_evaluator/test_evaluator)
- 2.5 训练、验证和测试配置(train_cfg, val_cfg, test_cfg)
- 2.6 优化相关配置 (optim_wrapper)
- 2.7 钩子配置 (default_hooks, custom_hooks)
- 2.7.1 default_hooks
- 2.7.2 custom_hooks
- 2.8 运行相关配置
1. 简介
1.1 配置文件主要内容
- model
- Dataloader
- train_dataloader
- val_dataloader
- test_dataloader
- Evaluator
- val_evaluator
- test_evaluator
- Configuration
- optim_wrapper
- Hooks
- default_hooks
- custom_hooks
1. 2 配置文件名称含义
{algorithm name}_{model component names [component1]_[component2]_[...]}-[version id]_[norm setting]_
[data preprocessor type]_{training settings}_{training dataset information}_
{testing dataset information}.py
- 文件名分为 8 个部分,其中 4 个必填部分、4 个可选部分。 每个部分用 _ 连接,每个部分内的单词应该用 - 连接。{} 表示必填部分,[] 表示选填部分。
- {algorithm name}: 算法的名称。 它可以是检测器名称,例如 yolov5, yolov6, yolox 等。
- {component names}: 算法中使用的组件名称,如 backbone、neck 等。
- [version_id] (可选): 由于 YOLO 系列算法迭代速度远快于传统目标检测算法,因此采用 version id 来区分不同子版本之间的差异。
- [norm_setting] (可选):
- bn 表示 Batch Normalization
- syncbn 表示 Synchronized Batch Normalization。
- [data preprocessor type] (可选): 数据预处理类型
- {training settings}: 训练设置的信息,例如 batch 大小、数据增强、损失、参数调度方式和训练最大轮次/迭代。
- {gpu x batch_per_gpu}: GPU 数和每个 GPU 的样本数。bN 表示每个 GPU 上的 batch 大小为 N。例如 4xb8 是 4 个 GPU 每个 GPU 8 张图的缩写。如果没有注明,默认为 8 卡每卡 2 张图。
- {schedule}: 训练方案。
- {training dataset information}: 训练数据集,例如 coco, cityscapes, voc-0712, wider-face, balloon。
- [testing dataset information] (可选): 测试数据集,用于训练和测试在不同数据集上的模型配置。 如果没有注明,则表示训练和测试的数据集类型相同
- 例子:
yolov5_s-v61_syncbn_8xb16-300e_coco.py
- 上述例子的详细说明:
- yolov5_s:
- deepen_factor=0.33
- widen_factor=0.5,
- 通过deepen_factor和widen_factor来控制模型的大小
- yolov5_m:
- deepen_factor = 0.67
- widen_factor = 0.75
- yolov5_l:
- deepen_factor = 1.0
- widen_factor = 1.0
- v61:YOLOv5 的 6.0 以后的版本采用 6x6 Conv 层作为第一个下采样层,而 3.0 版本采用 Focus 层作为第一个下采样层
- 8xb16:表示使用 8 个 gpu 每个 gpu 16 张图,并训练 300 个 epoch
- fast:不标 fast 默认使用 mmdet.DetDataPreprocessor,而 fast 表示调用 YOLOv5DetDataPreprocessor 并配合 yolov5_collate 进行数据预处理,训练速度较快(不慢于yolov5官方),但是对多任务处理的灵活性较低
- 300e: 表示训练 300 个 epoch
- coco: 表示 COCO2017 目标检测数据集。
2. 配置文件内容
2.1 重要参数
- 深度的缩放因子deepen_factor和宽度的缩放因子widen_factor:控制模型的大小
img_scale = (640, 640) # 高度,宽度
deepen_factor = 0.33 # 控制网络结构深度的缩放因子,YOLOv5-s 为 0.33
widen_factor = 0.5 # 控制网络结构宽度的缩放因子,YOLOv5-s 为 0.5
max_epochs = 300 # 最大训练轮次 300 轮
save_epoch_intervals = 10 # 验证间隔,每 10 个 epoch 验证一次
train_batch_size_per_gpu = 16 # 训练时单个 GPU 的 Batch size
train_num_workers = 8 # 训练时单个 GPU 分配的数据加载线程数
val_batch_size_per_gpu = 1 # 验证时单个 GPU 的 Batch size
val_num_workers = 2 # 验证时单个 GPU 分配的数据加载线程数
2.2 模型(model)配置
- 使用model字段来配置检测算法的组件
- backbone
- neck
- head
- data_preprocessor
- 负责对 dataloader 输出的每一批数据进行预处理
- 预处理包括:颜色空间变换,归一化,to cuda,pad 成一样大小方便组成 batch
- train_cfg:设置训练组件的超参数
- test_cfg:设置测试组件的超参数
anchors = [[(10, 13), (16, 30), (33, 23)], # 多尺度的先验框基本尺寸 [(30, 61), (62, 45), (59, 119)],[(116, 90), (156, 198), (373, 326)]]
strides = [8, 16, 32] # 先验框生成器的步幅model = dict(type='YOLODetector', #检测器名data_preprocessor=dict( # 数据预处理器的配置,通常包括图像归一化和 paddingtype='mmdet.DetDataPreprocessor', # 数据预处理器的类型,# 还可以选择 'YOLOv5DetDataPreprocessor' 训练速度更快mean=[0., 0., 0.], # 用于预训练骨干网络的图像归一化通道均值,按 R、G、B 排序std=[255., 255., 255.], # 用于预训练骨干网络的图像归一化通道标准差,按 R、G、B 排序bgr_to_rgb=True), # 是否将图像通道从 BGR 转为 RGBbackbone=dict( # 主干网络的配置文件type='YOLOv5CSPDarknet', # 主干网络的类别,目前可选用 'YOLOv5CSPDarknet', #'YOLOv6EfficientRep', 'YOLOXCSPDarknet' 3种deepen_factor=deepen_factor, # 控制网络结构深度的缩放因子widen_factor=widen_factor, # 控制网络结构宽度的缩放因子norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), # 归一化层(norm layer)的配置项act_cfg=dict(type='SiLU', inplace=True)), # 激活函数(activation function)的配置项neck=dict(type='YOLOv5PAFPN', # 检测器的 neck 是 YOLOv5FPN,# 我们同样支持 'YOLOv6RepPAFPN', 'YOLOXPAFPN'deepen_factor=deepen_factor, # 控制网络结构深度的缩放因子widen_factor=widen_factor, # 控制网络结构宽度的缩放因子in_channels=[256, 512, 1024], # 输入通道数,与 Backbone 的输出通道一致out_channels=[256, 512, 1024], # 输出通道数,与 Head 的输入通道一致num_csp_blocks=3, # CSPLayer 中 bottlenecks 的数量norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), # 归一化层(norm layer)的配置项act_cfg=dict(type='SiLU', inplace=True)), # 激活函数(activation function)的配置项bbox_head=dict(type='YOLOv5Head', # bbox_head 的类型是 'YOLOv5Head', # 我们目前也支持 'YOLOv6Head', 'YOLOXHead'head_module=dict(type='YOLOv5HeadModule', # head_module 的类型是 'YOLOv5HeadModule', # 我们目前也支持 'YOLOv6HeadModule', 'YOLOXHeadModule'num_classes=80, # 分类的类别数量in_channels=[256, 512, 1024], # 输入通道数,与 Neck 的输出通道一致widen_factor=widen_factor, # 控制网络结构宽度的缩放因子featmap_strides=[8, 16, 32], # 多尺度特征图的步幅num_base_priors=3), # 在一个点上,先验框的数量prior_generator=dict( # 先验框(prior)生成器的配置type='mmdet.YOLOAnchorGenerator', # 先验框生成器的类型是 mmdet 中的 'YOLOAnchorGenerator'base_sizes=anchors, # 多尺度的先验框基本尺寸strides=strides), # 先验框生成器的步幅, 与 FPN 特征步幅一致。# 如果未设置 base_sizes,则当前步幅值将被视为 base_sizes。),test_cfg=dict(multi_label=True, # 对于多类别预测来说是否考虑多标签,默认设置为 Truenms_pre=30000, # NMS 前保留的最大检测框数目score_thr=0.001, # 过滤类别的分值,低于 score_thr 的检测框当做背景处理nms=dict(type='nms', # NMS 的类型iou_threshold=0.65), # NMS 的阈值max_per_img=300)) # 每张图像 NMS 后保留的最大检测框数目
2.3 Dataloader
- 在使用执行器进行训练、测试、验证时,我们需要配置 Dataloader 。构建数据 dataloader 需要设置:
- 数据集(dataset)
- 数据处理流程(data pipeline)
- Dataloader包含dataset, dataset包含pipeline
2.3.1 训练Dataloader (train_dataloader)
dataset_type = 'CocoDataset' # 数据集类型,这将被用来定义数据集
data_root = 'data/coco/' # 数据的根路径
file_client_args = dict(backend='disk') # 文件读取后端的配置,默认从硬盘读取pre_transform = [ # 训练数据读取流程dict(type='LoadImageFromFile', # 第 1 个流程,从文件路径里加载图像file_client_args=file_client_args), # 文件读取后端的配置,默认从硬盘读取dict(type='LoadAnnotations', # 第 2 个流程,对于当前图像,加载它的注释信息with_bbox=True) # 是否使用标注框(bounding box),目标检测需要设置为 True
]albu_train_transforms = [ # YOLOv5-v6.1 仓库中,引入了 Albumentation 代码库进行图像的数据增广,# 请确保其版本为 1.0.+dict(type='Blur', p=0.01), # 图像模糊,模糊概率 0.01dict(type='MedianBlur', p=0.01), # 均值模糊,模糊概率 0.01dict(type='ToGray', p=0.01), # 随机转换为灰度图像,转灰度概率 0.01dict(type='CLAHE', p=0.01) # CLAHE(限制对比度自适应直方图均衡化) 图像增强方法,# 直方图均衡化概率 0.01
]train_pipeline = [ # 训练数据处理流程*pre_transform, # 引入前面定义的训练数据读取流程dict(type='Mosaic', # Mosaic 数据增强方法img_scale=img_scale, # Mosaic 数据增强后的图像尺寸pad_val=114.0, # 空区域填充像素值pre_transform=pre_transform), # 之前创建的 pre_transform 训练数据读取流程dict(type='YOLOv5RandomAffine', # YOLOv5 的随机仿射变换max_rotate_degree=0.0, # 最大旋转角度max_shear_degree=0.0, # 最大错切角度scaling_ratio_range=(0.5, 1.5), # 图像缩放系数的范围border=(-img_scale[0] // 2, -img_scale[1] // 2), # 从输入图像的高度和宽度两侧调整输出形状的距离border_val=(114, 114, 114)), # 边界区域填充像素值dict(type='mmdet.Albu', # mmdet 中的 Albumentation 数据增强transforms=albu_train_transforms, # 之前创建的 albu_train_transforms 数据增强流程bbox_params=dict(type='BboxParams',format='pascal_voc',label_fields=['gt_bboxes_labels', 'gt_ignore_flags']),keymap={'img': 'image','gt_bboxes': 'bboxes'}),dict(type='YOLOv5HSVRandomAug'), # HSV通道随机增强dict(type='mmdet.RandomFlip', prob=0.5), # 随机翻转,翻转概率 0.5dict( type='mmdet.PackDetInputs', # 将数据转换为检测器输入格式的流程meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 'flip','flip_direction'))
]train_dataloader = dict( # 训练 dataloader 配置batch_size=train_batch_size_per_gpu, # 训练时单个 GPU 的 Batch sizenum_workers=train_num_workers, # 训练时单个 GPU 分配的数据加载线程数persistent_workers=True, # 如果设置为 True,dataloader 在迭代完一轮之后不会关闭数据读取的子进程,可以加速训练pin_memory=True, # 开启锁页内存,节省 CPU 内存拷贝时间sampler=dict( # 训练数据的采样器type='DefaultSampler', # 默认的采样器,同时支持分布式和非分布式训练。#请参考 https://github.com/open-mmlab/mmengine/blob/main/mmengine/dataset/sampler.pyshuffle=True), # 随机打乱每个轮次训练数据的顺序dataset=dict( # 训练数据集的配置type=dataset_type,data_root=data_root,ann_file='annotations/instances_train2017.json', # 标注文件路径data_prefix=dict(img='train2017/'), # 图像路径前缀filter_cfg=dict(filter_empty_gt=False, min_size=32), # 图像和标注的过滤配置pipeline=train_pipeline)) # 这是由之前创建的 train_pipeline 定义的数据处理流程
2.3.1 验证和评测Dataloader (val_dataloader+test_dataloader)
- 评测和验证dataloader是一样的
- YOLOv5 测试阶段采用 Letter Resize 的方法来将所有的测试图像统一到相同尺度,进而有效保留了图像的长宽比。因此我们在验证和评测时,都采用相同的数据流进行推理。
test_pipeline = [ # 测试数据处理流程dict(type='LoadImageFromFile', # 第 1 个流程,从文件路径里加载图像file_client_args=file_client_args), # 文件读取后端的配置,默认从硬盘读取dict(type='YOLOv5KeepRatioResize', # 第 2 个流程,保持长宽比的图像大小缩放scale=img_scale), # 图像缩放的目标尺寸dict(type='LetterResize', # 第 3 个流程,满足多种步幅要求的图像大小缩放scale=img_scale, # 图像缩放的目标尺寸allow_scale_up=False, # 当 ratio > 1 时,是否允许放大图像,pad_val=dict(img=114)), # 空区域填充像素值dict(type='LoadAnnotations', with_bbox=True), # 第 4 个流程,对于当前图像,加载它的注释信息dict(type='mmdet.PackDetInputs', # 将数据转换为检测器输入格式的流程meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape','scale_factor', 'pad_param'))
]val_dataloader = dict(batch_size=val_batch_size_per_gpu, # 验证时单个 GPU 的 Batch sizenum_workers=val_num_workers, # 验证时单个 GPU 分配的数据加载线程数persistent_workers=True, # 如果设置为 True,dataloader 在迭代完一轮之后不会关闭数据读取的子进程,可以加速训练pin_memory=True, # 开启锁页内存,节省 CPU 内存拷贝时间drop_last=False, # 是否丢弃最后未能组成一个批次的数据sampler=dict(type='DefaultSampler', # 默认的采样器,同时支持分布式和非分布式训练shuffle=False), # 验证和测试时不打乱数据顺序dataset=dict(type=dataset_type,data_root=data_root,test_mode=True, # 开启测试模式,避免数据集过滤图像和标注data_prefix=dict(img='val2017/'), # 图像路径前缀ann_file='annotations/instances_val2017.json', # 标注文件路径pipeline=test_pipeline, # 这是由之前创建的 test_pipeline 定义的数据处理流程batch_shapes_cfg=dict( # batch shapes 配置type='BatchShapePolicy', # 确保在 batch 推理过程中同一个 batch 内的图像 pad 像素最少,# 不要求整个验证过程中所有 batch 的图像尺度一样batch_size=val_batch_size_per_gpu, # batch shapes 策略的 batch size,等于验证时单个 GPU 的 Batch sizeimg_size=img_scale[0], # 图像的尺寸size_divisor=32, # padding 后的图像的大小应该可以被 pad_size_divisor 整除extra_pad_ratio=0.5))) # 额外需要 pad 的像素比例
test_dataloader = val_dataloader
2.4 评测器(val_evaluator/test_evaluator)
- 评测器:用于计算训练模型在验证和测试数据集上的指标。评测器的配置由一个或一组评价指标(Metric)配置组成:
val_evaluator = dict( # 验证过程使用的评测器type='mmdet.CocoMetric', # 用于评估检测的 AR、AP 和 mAP 的 coco 评价指标proposal_nums=(100, 1, 10), # 用于评估检测任务时,选取的Proposal数量ann_file=data_root + 'annotations/instances_val2017.json', # 标注文件路径metric='bbox', # 需要计算的评价指标,`bbox` 用于检测
)
test_evaluator = val_evaluator # 测试过程使用的评测器
- 如果要保存在测试数据集上的检测结果,则可以像这样编写配置:
# 在测试集上推理,
# 并将检测结果转换格式以用于提交结果
test_dataloader = dict(batch_size=1,num_workers=2,persistent_workers=True,drop_last=False,sampler=dict(type='DefaultSampler', shuffle=False),dataset=dict(type=dataset_type,data_root=data_root,ann_file=data_root + 'annotations/image_info_test-dev2017.json',data_prefix=dict(img='test2017/'),test_mode=True,pipeline=test_pipeline))
test_evaluator = dict(type='mmdet.CocoMetric',ann_file=data_root + 'annotations/image_info_test-dev2017.json',metric='bbox',format_only=True, # 只将模型输出转换为coco的 JSON 格式并保存outfile_prefix='./work_dirs/coco_detection/test') # 要保存的 JSON 文件的前缀
2.5 训练、验证和测试配置(train_cfg, val_cfg, test_cfg)
- MMEngine 的 Runner 使用 Loop 来控制训练,验证和测试过程。
- 用户可以使用这些字段设置:
max_epochs = 300 # 最大训练轮次 300 轮
save_epoch_intervals = 10 # 验证间隔,每 10 轮验证一次train_cfg = dict(type='EpochBasedTrainLoop', # 训练循环的类型,请参考 #https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.pymax_epochs=max_epochs, # 最大训练轮次 300 轮val_interval=save_epoch_intervals) # 验证间隔,每 10 个 epoch 验证一次
val_cfg = dict(type='ValLoop') # 验证循环的类型
test_cfg = dict(type='TestLoop') # 测试循环的类型
- MMEngine 也支持动态评估间隔,例如你可以在前面 280 epoch 训练阶段中,每间隔 10 个 epoch 验证一次,到最后 20 epoch 训练中每隔 1 个 epoch 验证一次,则配置写法为:
max_epochs = 300 # 最大训练轮次 300 轮
save_epoch_intervals = 10 # 验证间隔,每 10 轮验证一次train_cfg = dict(type='EpochBasedTrainLoop', # 训练循环的类型,请参考 #https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.pymax_epochs=max_epochs, # 最大训练轮次 300 轮val_interval=save_epoch_intervals, # 验证间隔,每 10 个 epoch 验证一次dynamic_intervals=[(280, 1)]) # 到 280 epoch 开始切换为间隔 1 的评估方式
val_cfg = dict(type='ValLoop') # 验证循环的类型
test_cfg = dict(type='TestLoop') # 测试循环的类型
2.6 优化相关配置 (optim_wrapper)
- optim_wrapper 是配置优化相关设置的字段。优化器封装(OptimWrapper)不仅提供了优化器的功能,还支持梯度裁剪、混合精度训练等功能
optim_wrapper = dict( # 优化器封装的配置type='OptimWrapper', # 优化器封装的类型。可以切换至 AmpOptimWrapper 来启用混合精度训练optimizer=dict( # 优化器配置。支持 PyTorch 的各种优化器。请参考 #https://pytorch.org/docs/stable/optim.html#algorithmstype='SGD', # 随机梯度下降优化器lr=0.01, # 基础学习率momentum=0.937, # 带动量的随机梯度下降weight_decay=0.0005, # 权重衰减nesterov=True, # 开启Nesterov momentum,#公式详见 http://www.cs.toronto.edu/~hinton/absps/momentum.pdfbatch_size_per_gpu=train_batch_size_per_gpu), # 该选项实现了自动权重衰减系数缩放clip_grad=None, # 梯度裁剪的配置,设置为 None 关闭梯度裁剪。使用方法请见 # https://mmengine.readthedocs.io/en/latest/tutorials/optimizer.htmlconstructor='YOLOv5OptimizerConstructor') # YOLOv5 优化器构建器
- param_scheduler 字段
- 用于配置参数调度器(Parameter Scheduler)来调整优化器的超参数(例如学习率和动量)。
- 用户可以组合多个调度器来创建所需的参数调整策略。
- 在参数调度器教程和参数调度器 API 文档 中查找更多信息。
- 在 YOLOv5 中,参数调度实现比较复杂,难以 param_scheduler 实现。所以采用了 YOLOv5ParamSchedulerHook 来实现(见下节),这样做更简单但是通用性较差。
2.7 钩子配置 (default_hooks, custom_hooks)
- 用户可以在训练、验证和测试循环上添加钩子,以便在运行期间插入一些操作。配置中有两种不同的钩子字段:
- default_hooks
- custom_hooks
2.7.1 default_hooks
- default_hooks是一个字典,用于配置运行时必须使用的钩子。这些钩子具有默认优先级,如果未设置,runner 将使用默认值。如果要禁用默认钩子,用户可以将其配置设置为 None。
default_hooks = dict(param_scheduler=dict(type='YOLOv5ParamSchedulerHook', # MMYOLO 中默认采用 Hook 方式进行优化器超参数的调节scheduler_type='linear',lr_factor=0.01,max_epochs=max_epochs),checkpoint=dict(type='CheckpointHook', # 按照给定间隔保存模型的权重的 Hookinterval=save_epoch_intervals, # 每 10 轮保存 1 次权重文件max_keep_ckpts=3)) # 最多保存 3 个权重文件
2.7.2 custom_hooks
- custom_hooks 是一个列表。用户可以在这个字段中加入自定义的钩子,例如 EMAHook。
custom_hooks = [dict(type='EMAHook', # 实现权重 EMA(指数移动平均) 更新的 Hookema_type='ExpMomentumEMA', # YOLO 中使用的带动量 EMAmomentum=0.0001, # EMA 的动量参数update_buffers=True, # 是否计算模型的参数和缓冲的 running averagespriority=49) # 优先级略高于 NORMAL(50)
]
2.8 运行相关配置
default_scope = 'mmyolo' # 默认的注册器域名,默认从此注册器域中寻找模块。# 请参考 https://mmengine.readthedocs.io/en/latest/tutorials/registry.htmlenv_cfg = dict(cudnn_benchmark=True, # 是否启用 cudnn benchmark, 推荐单尺度训练时开启,可加速训练mp_cfg=dict( # 多进程设置mp_start_method='fork', # 使用 fork 来启动多进程。‘fork’ 通常比 ‘spawn’ 更快,#但可能存在隐患。请参考 https://github.com/pytorch/pytorch/issues/1355opencv_num_threads=0), # 关闭 opencv 的多线程以避免系统超负荷dist_cfg=dict(backend='nccl'), # 分布式相关设置
)vis_backends = [dict(type='LocalVisBackend')] # 可视化后端,请参考# https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/visualization.html
visualizer = dict(type='mmdet.DetLocalVisualizer', vis_backends=vis_backends, name='visualizer')
log_processor = dict(type='LogProcessor', # 日志处理器用于处理运行时日志window_size=50, # 日志数值的平滑窗口by_epoch=True) # 是否使用 epoch 格式的日志。需要与训练循环的类型保存一致。log_level = 'INFO' # 日志等级
load_from = None # 从给定路径加载模型检查点作为预训练模型。这不会恢复训练。
resume = False # 是否从 `load_from` 中定义的检查点恢复。 # 如果 `load_from` 为 None,它将恢复 `work_dir` 中的最新检查点。