- 人工智能
- 计算机视觉
- 深度学习
- 模型评测
【免费下载链接】mmdetection
OpenMMLab Detection Toolbox and Benchmark
MMDetection 在 COCO 等大规模数据集上预训练的检测器,可以作为 Cityscapes、KITTI 等数据集的优质预训练模型,大幅提升目标域上的收敛速度与最终精度。本文以 Cityscapes 数据集微调 Mask R-CNN 为例,完整讲解 MMDetection 中基于配置继承(_base_)实现模型微调的五个核心步骤——继承基础配置、修改 Head 类别数、替换数据集、调整训练策略、加载预训练权重,并结合作者仓库(gh_mirrors/mm/mmdetection)中的真实配置文件与源码实现进行深度佐证。读完本文,你将掌握一套可复制的微调流程,能够把官方 ModelZoo 中的任何预训练模型迁移到自己的数据集上。
一、微调的整体思路:两个必要步骤
把预训练模型迁移到新数据集,本质上需要做两件事:
- 按 教程2:自定义数据集 中的方法对新数据集添加支持,即准备数据集并编写对应的数据集配置文件(
_base_/datasets/下的数据集定义); - 按照本教程讨论的方法修改模型配置,即通过继承与覆盖的方式,让模型结构、训练策略与预训练权重适配新数据集。
下文以Cityscapes Dataset 上的微调为具体例子,详细讲述用户需要在配置中修改的五个部分。Cityscapes 是面向城市街景语义理解的公开数据集,实例分割任务包含 8 个类别(person、rider、car、truck、bus、train、motorcycle、bicycle),远少于 COCO 的 80 类,因此是验证微调流程的理想示例。
二、第一步:继承基础配置(_base_机制)
为了减轻编写整个配置的负担并减少出错的可能性,MMDetection 支持从多个现有配置中继承配置信息。微调 Mask R-CNN 模型时,新的配置信息需要使用从_base_/models/中继承的配置来构建模型的基本结构;使用 Cityscapes 数据集时,可以简便地从_base_/datasets/cityscapes_instance.py继承;训练过程的运行设置(如日志 logger 设置)可以从_base_/default_runtime.py继承;训练计划配置则从_base_/schedules/schedule_1x.py继承。这些基础配置文件存放于configs/_base_/目录下,用户既可以选择继承,也可以全部重新编写。
典型的继承写法如下:
_base_ = [ '../_base_/models/mask_rcnn_r50_fpn.py', '../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py', '../_base_/schedules/schedule_1x.py' ]配置继承的覆盖规则:_base_中列出的配置会被逐字段解析并合并,新配置文件中定义的字段会覆盖被继承配置中的同名字段;字典按 key 深度合并,列表整体替换。因此我们只需要在子配置中"增量修改"少量字段,就能在完整基础配置之上定制微调方案。
需要说明的是,从当前仓库源码结构看,实际的基础模型文件名为 configs/base/models/mask-rcnn_r50_fpn.py(文件名中带连字符),文档中的mask_rcnn_r50_fpn.py写法在较新版本中已统一为mask-rcnn_r50_fpn.py,真实微调配置 configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py 中引用的即是后者。该基础配置定义了完整的 Mask R-CNN 模型:ResNet骨干(depth=50、frozen_stages=1、init_cfg使用 torchvision 预训练权重)、FPN颈部(in_channels=[256, 512, 1024, 2048]、out_channels=256、num_outs=5)、RPNHead与StandardRoIHead(bbox_head 为Shared2FCBBoxHead,in_channels=256、fc_out_channels=1024、roi_feat_size=7、num_classes=80)。
其余被继承的基础配置要点:
- configs/base/datasets/cityscapes_instance.py:定义
dataset_type = 'CityscapesDataset'、data_root = 'data/cityscapes/',训练/测试 pipeline(训练采用RandomResize尺度[(2048, 800), (2048, 1024)],测试Resize到(2048, 1024))、train_dataloader(batch_size=1、RepeatDatasettimes=8)以及val_evaluator(CocoMetric+CityScapesMetric双指标评估); - configs/base/default_runtime.py:
default_scope = 'mmdet'、各类 hooks(CheckpointHookinterval=1、LoggerHookinterval=50)、env_cfg、vis_backends/visualizer、log_level = 'INFO'、load_from = None、resume = False; - configs/base/schedules/schedule_1x.py:
EpochBasedTrainLoop(max_epochs=12、val_interval=1)、LinearLR+MultiStepLR(milestones=[8, 11])、SGD 优化器(lr=0.02、momentum=0.9、weight_decay=0.0001),并带有auto_scale_lr(base_batch_size=16)自动学习率缩放声明。
三、第二步:Head 的修改(num_classes)
新的配置还需要根据新数据集的类别数量修改 Head。只需要修改roi_head中 bbox_head 和 mask_head 的num_classes。修改后,除了最后的预测 Head 之外,预训练模型权重的大部分都会被重新使用(即除分类/回归输出层之外的骨干、颈部、RPN 等权重均可完整迁移复用)。
model = dict( roi_head=dict( bbox_head=dict( type='Shared2FCBBoxHead', in_channels=256, fc_out_channels=1024, roi_feat_size=7, num_classes=8, bbox_coder=dict( type='DeltaXYWHBBoxCoder', target_means=[0., 0., 0., 0.], target_stds=[0.1, 0.1, 0.2, 0.2]), reg_class_agnostic=False, loss_cls=dict( type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), mask_head=dict( type='FCNMaskHead', num_convs=4, in_channels=256, conv_out_channels=256, num_classes=8, loss_mask=dict( type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))))由于_base_采用字段级合并,真实微调配置 configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py 中只写了差异部分,语义与本例等价:
model = dict( backbone=dict(init_cfg=None), # 避免覆盖 load_from 的预训练权重初始化 roi_head=dict( bbox_head=dict( type='Shared2FCBBoxHead', num_classes=8, loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), mask_head=dict(num_classes=8)))这里backbone=dict(init_cfg=None)是一个关键细节:它显式关闭骨干网络的Pretrained初始化(基础配置中为init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),避免其与下文load_from加载的 COCO 预训练权重发生冲突,从而保证以 COCO 预训练检测器权重(而非仅 torchvision 骨干权重)作为整体初始化。从源码结构看,这一约定在 MMDetection 各微调配置中普遍使用。
四、第三步:数据集的修改
用户可能还需要准备数据集并编写数据集配置,详细信息可参考 Customize Datasets。目前 MMDetection 的配置文件已经支持 VOC、WIDERFACE、COCO、LVIS、OpenImages、DeepFashion、Objects365 和 Cityscapes 等数据集,基础数据集定义均位于 configs/base/datasets 目录,例如voc0712.py、wider_face.py、coco_instance.py、lvis_v1_instance.py、openimages_detection.py、deepfashion.py、objects365v2_detection.py、cityscapes_instance.py。
以 Cityscapes 为例,需要先准备数据:将数据集按照 数据集准备指南 放入data/cityscapes/,并利用仓库提供的转换脚本 tools/dataset_converters/cityscapes.py 将原始 Cityscapes 标注转换为 COCO 格式的 JSON 标注文件(如instancesonly_filtered_gtFine_train.json、instancesonly_filtered_gtFine_val.json)。
configs/base/datasets/cityscapes_instance.py 中的数据集配置包含以下关键元素:
- 数据源:
ann_file指向转换后的标注文件,data_prefix=dict(img='leftImg8bit/train/')指定图像前缀; - pipeline:
LoadImageFromFile→LoadAnnotations(with_bbox=True, with_mask=True)→RandomResize→RandomFlip(prob=0.5)→PackDetInputs(训练);测试管线为Resize(scale=(2048, 1024), keep_ratio=True)等; - 过滤:
filter_cfg=dict(filter_empty_gt=True, min_size=32)丢弃无标注或尺寸过小的样本; - repeat:
RepeatDataset将训练集重复 8 次(Cityscapes 训练集较小,重复以平衡迭代步数); - 评估器:
val_evaluator同时使用CocoMetric(metric=['bbox', 'segm'],输出 COCO 风格 AP)和CityScapesMetric(官方 Cityscapes 评估,带seg_prefix与outfile_prefix)。
若使用自定义数据集且尚未提供现成的_base_数据集配置,则需要按照 Customize Datasets 自行编写dataset_type、data_root、train_pipeline/test_pipeline、三个 dataloader 与 evaluator 配置块。
五、第四步:训练策略的修改
微调的超参数与默认训练策略不同,通常需要更小的学习率和更少的训练回合。因为预训练模型已经具备了良好的特征表达能力,过大学习率容易破坏已有权重,过多训练回合则易过拟合小规模数据集。
# 优化器 # batch size 为 8 时的 lr 配置 optim_wrapper = dict(optimizer=dict(lr=0.01)) # 学习率 param_scheduler = [ dict( type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500), dict( type='MultiStepLR', begin=0, end=8, by_epoch=True, milestones=[7], gamma=0.1) ] # 设置 max epoch train_cfg = dict(max_epochs=8) # 设置 log config default_hooks = dict(logger=dict(interval=100))逐项解读这些微调策略参数:
- 学习率:基础配置
schedule_1x.py中 SGD 的 lr 为 0.02(batch size 16 基准),微调时改为0.01(batch size 8 基准),符合线性缩放规则(learning rate scaling rule),即学习率与总 batch size 近似成正比; - LinearLR 预热:
LinearLR在训练的前 500 次迭代(by_epoch=False,按 iter 计)从start_factor=0.001线性升至 1.0,起到 warmup 作用,避免训练初期大学习率冲击预训练权重; - MultiStepLR 衰减:训练共 8 个 epoch,在
milestones=[7]处以gamma=0.1将学习率衰减为原来的 1/10(真实 Cityscapes 配置注释说明[7]比[6]性能更高); - max_epochs=8:配合
cityscapes_instance.py中的RepeatDataset(times=8),实际迭代量相当于 8×8=64 个原始 epoch(与 Mask R-CNN 论文中约 24k 迭代的原始 schedule 相当); - 日志间隔:
default_hooks = dict(logger=dict(interval=100))覆盖基础运行时中的 interval=50,每 100 次迭代输出一次日志。
注意:与optim_wrapper、param_scheduler、train_cfg直接覆盖不同,default_hooks与_base_/default_runtime.py中的同名字段是字段级合并,此处只覆盖logger子字段,其余 hooks 保持基础配置不变。
六、第五步:使用预训练模型(load_from)
如果要使用预训练模型,可以在配置中通过load_from指定权重文件。建议在训练开始之前预先下载好模型权重,避免训练过程中因下载而浪费时间。
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth' # noqa在模型微调中,选择预训练权重的基本原则:权重对应的模型结构要与当前配置结构一致(或高度兼容),类别数不一致没有关系(分类层会按新 num_classes 重建并被随机初始化),但骨干、颈部、RPN 等结构的通道数必须匹配。当前仓库中的真实 Cityscapes 配置 configs/cityscapes/mask-rcnn_r50_fpn_1x_coco.py 使用的是 COCO 1x 的mask_rcnn_r50_fpn_1x_coco权重:
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth' # noqa关于权重加载的补充说明:
load_from在 configs/base/default_runtime.py 中默认值为None,微调配置中重新赋值即可生效;- 权重加载时,形状不匹配的参数(如因 num_classes 改变而尺寸变化的分类/回归层)会被自动跳过,这正是只需修改 num_classes 即可复用预训练权重的原因;
- 若将
load_from指向本地文件路径(如'./checkpoints/mask_rcnn_r50_fpn_1x_coco.pth'),可避免在线下载; - 类别数差异导致的 Head 随机初始化是正常的,微调的前几个 epoch 这部分参数会快速收敛。
七、完整的微调配置文件参考
将上述五个部分的修改汇总,即可得到一份完整的微调配置。仓库中现成的 Cityscapes 微调配置 configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py 全文如下(与实际文档示例相比,它是字段级合并的"最小差异"写法,同样覆盖了五个要点):
_base_ = [ '../_base_/models/mask-rcnn_r50_fpn.py', '../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py', '../_base_/schedules/schedule_1x.py' ] model = dict( backbone=dict(init_cfg=None), roi_head=dict( bbox_head=dict( type='Shared2FCBBoxHead', num_classes=8, loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), mask_head=dict(num_classes=8))) # optimizer # lr is set for a batch size of 8 optim_wrapper = dict(optimizer=dict(lr=0.01)) # learning rate param_scheduler = [ dict( type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500), dict( type='MultiStepLR', begin=0, end=8, by_epoch=True, # [7] yields higher performance than [6] milestones=[7], gamma=0.1) ] # actual epoch = 8 * 8 = 64 train_cfg = dict(max_epochs=8) # For better, more stable performance initialize from COCO load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth' # noqa # NOTE: `auto_scale_lr` is for automatically scaling LR, # USER SHOULD NOT CHANGE ITS VALUES. # base_batch_size = (8 GPUs) x (1 samples per GPU) # TODO: support auto scaling lr # auto_scale_lr = dict(base_batch_size=8)按照 configs/cityscapes/README.md 的说明,Cityscapes 上的基线模型均使用 8 张 GPU、batch size 8(每卡 1 张图)训练,学习率遵循线性缩放规则,统一在cityscapes_train上训练、在cityscapes_val上测试;所谓 "1x training schedule" 即 64 个 epoch,与 Mask R-CNN 论文中原始约 24k 迭代的 schedule 对应;COCO 预训练权重用于初始化。在双评估器下,bbox与segm是标准 COCO 风格的 AP,cityscapes为官方评估结果(通常略高于 COCO 指标)。
八、启动微调训练与测试
配置就绪后,即可通过仓库提供的 tools/train.py 启动微调训练:
# 单卡训练 python tools/train.py configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py # 多卡训练(8 卡) bash tools/dist_train.sh configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py 8 # Slurm 集群训练 bash tools/slurm_train.sh <partition> <job_name> configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py 8训练完成后,使用 tools/test.py 在验证集上评估微调效果:
python tools/test.py configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py work_dirs/mask-rcnn_r50_fpn_1x_cityscapes/epoch_8.pth更多训练参数(如--amp混合精度、--resume断点续训、--work-dir输出目录等)可参考 训练与测试指南。Cityscapes 微调配置的评估会同时输出 COCO 风格的 box/mask AP 与官方 Cityscapes 指标,便于从多个角度对比微调前后的性能提升。
九、微调实践要点与常见问题
- 类别数修改不遗漏:实例分割模型(如 Mask R-CNN)需要同时修改
bbox_head.num_classes与mask_head.num_classes;仅做检测(如 Faster R-CNN)则只需修改bbox_head.num_classes。可将 configs/base/models/faster-rcnn_r50_fpn.py 与对应检测数据集配置组合,参照同样流程微调检测器。 init_cfg=None的意图:微调时在子配置中为backbone设置init_cfg=None,避免与load_from的 COCO 预训练权重双重初始化相互干扰,这是 MMDetection 微调配置的标准约定。- 学习率与 epoch 的取舍:新数据集与 COCO 分布差异越大、数据量越少,学习率应越小(可尝试 0.005~0.01)、训练回合越短(如 8~24 epoch);若新数据集很大且与 COCO 分布接近,也可适当放宽。
- 重复数据集与 epoch 的关系:Cityscapes 训练集通过
RepeatDataset(times=8)扩充,配置中max_epochs=8指的是"重复后"的训练循环 epoch,因此实际遍历原始数据 8×8=64 遍。调整 repeat 次数时,应同步核算实际迭代量。 - 权重不匹配的告警:加载预训练权重时,日志中的 size mismatch 告警主要来自 num_classes 变化的 Head 层,属预期现象,无需处理。
- backbone 冻结策略:基础配置中
frozen_stages=1(冻结 stem 与 stage1)、norm_eval=True,微调时一般保持默认即可;若新数据集与 COCO 差异极大,可考虑减少frozen_stages以允许更多底层特征更新。
综上,MMDetection 的微调流程高度依赖其配置继承体系:以_base_组装模型、数据集、运行时与训练计划四类基础配置,再以字段级覆盖实现"五步定制"——改 Head、换数据、调策略、挂权重。本文以 Cityscapes 为例的完整流程可直接推广到 VOC、KITTI、自定义数据集等任意场景,只需替换_base_中的数据集定义与对应的num_classes即可快速完成预训练模型的迁移与二次开发。
- 人工智能
- 计算机视觉
- 深度学习
- 模型评测
【免费下载链接】mmdetection
OpenMMLab Detection Toolbox and Benchmark
相关推荐
MMDetection 模型微调完全指南:基于 COCO 预训练权重在新数据集上微调(以 Cityscapes 为例)
MMDetection 模型微调完全指南:基于 COCO 预训练权重在新数据集上微调(以 Cityscapes 为例) 在 MMDetection 中,使用在大
人工智能计算机视觉深度学习模型评测VoiceStudio 模型训练完全指南:从 Emilia 预训练到自定义数据微调
VoiceStudio 模型训练完全指南:从 Emilia 预训练到自定义数据微调 导读 VoiceStudio(开源全本地语音平台)不仅提供推理、克隆与配音能
人工智能语音音频本地部署MCP 服务桌面应用SSD-Keras权重采样终极指南:从预训练模型到自定义数据集的无缝迁移
SSD Keras权重采样终极指南:从预训练模型到自定义数据集的无缝迁移 引言:预训练模型迁移的痛点与解决方案 你是否曾因预训练模型的类别数量与实际需求不符而放
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考