目标检测超好用框架MMDetection保姆级教程(一)—— 框架安装并用自己的数据集训练测试

233 阅读16分钟

今天三水儿给大家介绍一个目标检测领域十分好用的框架MMDetection。在我自己使用的过程中也踩不少坑,在这里总结一下,帮助大家更快的上手这款非常有用的工具。

首先来介绍一下MMDetection。

MMDetection 是一个基于 PyTorch开源目标检测工具箱和基准测试(benchmark)平台。它由国内领先的计算机视觉研究团队 OpenMMLab 开发和维护。

顾名思义,它的核心功能是目标检测(Object Detection),同时也扩展支持了实例分割(Instance Segmentation)全景分割(Panoptic Segmentation) 等相关的视觉感知任务。

其核心特点及优势有:

  1. 模块化设计

    这是 MMDetection 最核心的设计理念。它将整个检测系统解耦成独立的模块,例如:

    • 主干网络(Backbone):如 ResNet、Swin Transformer、Vision Transformer (ViT) 等。
    • 颈部网络(Neck):如 FPN、PAFPN 等,用于融合不同尺度的特征。
    • 检测头(Head):如 Anchor-based (RetinaNet、Faster R-CNN)、Anchor-free (FCOS)、Dense (DETR) 等。
    • 损失函数(Loss)训练策略(Schedule)数据增强(Data Augmentation) 等。

    用户可以像搭积木一样,通过配置文件自由组合不同的模块,轻松构建和实验自己的检测模型。

  2. 高性能与高精度

    MMDetection 提供了大量预训练模型(Model Zoo),覆盖了几乎所有主流和最新的检测算法。

    这些官方实现的模型性能通常都非常优异,在许多基准(如 COCO)上都达到了State-of-the-Art (SOTA) 或与之相当的水平,是学术研究和论文复现的可靠基础。

  3. 算法丰富,覆盖全面

    它支持超过 400+ 个预训练模型和 20+ 种目标检测算法。

    • 经典算法:Faster R-CNN、Mask R-CNN、RetinaNet、SSD、YOLOv3、Cascade R-CNN 等。
    • 前沿算法:DETR、Deformable DETR、Sparse R-CNN、YOLOX、YOLOF、Swin Transformer 等。
  4. 训练速度快,效率高

    框架底层进行了大量优化,支持分布式训练混合精度训练,能够充分利用 GPU 资源,大幅缩短模型训练和实验迭代的时间。

  5. 强大的生态系统

    作为 OpenMMLab 家族的核心成员,它与家族其他成员无缝衔接,例如:

    • MMPretrain:提供强大的预训练主干网络。
    • MMYOLO:专注于 YOLO 系列算法的实现和优化。
    • MMDeploy:提供模型部署工具,支持转换到 ONNX、TensorRT、OpenVINO 等格式。
    • MMEngine:提供了统一的训练流程和基础模块。

    这使得从研究、训练到部署的流程非常顺畅。

    这是MMDection的官方文档

概述 — MMDetection 3.3.0 文档

但里面的一些内容写的不是很清楚,不能做到上手即用,大家可以参考官方文档并结合我这个文档来进行实践。

1. 框架安装并验证

首先我们从框架的安装和测试这一步开始,三水儿在自己的电脑上和服务器上都安装过这里贴一下配置让大家有个参考。

  • Macbook Air(不是很推荐,可以用CPU运行,但对MPS不支持会报错,目前还没有找到解决办法)
    • 芯片:Apple M2
    • 操作系统:Sequoia 15.5
  • 服务器
    • GPU:RTX 3090
    • CPU:14 vCPU Intel(R) Xeon(R) Gold 6330 CPU @ 2.00GHz
    • CUDA版本:11.8

其实各操作系统的安装流程都一致,只要CUDA、PyTorch、Python版本匹配就没有多大的问题。

1.1 安装

  1. 安装Miniconda

  2. 创建conda环境

    conda create --name mmdet python=3.8 -y
    conda activate mmdet
    

    注:此处的python版本可以在3.8~3.10之间,不能超过3.10,建议直接推荐的3.8。激活后你的命令行前面会有(mmdet)。

  3. 安装PyTorch

    conda install pytorch torchvision -c pytorch
    
  4. 安装MIM、MMEngine、MMCV

    pip install -U openmim
    mim install mmengine
    mim install "mmcv<2.2.0"
    

    注:官方文档中 mim install "mmcv>=2.0.0" 的写法回导致mmcv的安装版本不对,在后续的测试会报错。

  5. 安装MMDetection

    git clone https://github.com/open-mmlab/mmdetection.git
    cd mmdetection
    pip install -v -e .
    # "-v" 指详细说明
    # "-e" 表示在可编辑模式下安装项目,因此对代码所做的任何本地修改都会生效,从而无需重新安装。
    

1.2 验证

上面的步骤完成后我们就完成了MMDetection框架的安装,接下来我们来验证我们安装的框架是否可用。

  1. 下载配置文件和模型权重文件

    # 在mmdetection目录下
    mim download mmdet --config rtmdet_tiny_8xb32-300e_coco --dest .
    
  2. 验证

    #保持在mmdetection目录下
    python demo/image_demo.py demo/demo.jpg rtmdet_tiny_8xb32-300e_coco.py --weights rtmdet_tiny_8xb32-300e_coco_20220902_112414-78e30dcc.pth --device cpu
    

    注:命令的含义是,运行当前目录下demo文件夹下的image_demo.py文件,对demo文件夹下的demo.jpg进行检测。 使用rtmdet_tiny_8xb32-300e_coco.py的配置和rtmdet_tiny_8xb32-300e_coco_20220902_112414-78e30dcc.pth的权重进行检测,使用的设备为cpu。

  3. 结果

    1. 检测的结果将会输出到当前文件夹中的outputs/vis中,图像中包含检测框。

demo.jpg

2.用自己的数据集进行训练

在开始准备训练之前,我们先来认识一下MMDetection各目录的主要存放的内容:

mmdetection/
├── configs/         # (核心)所有配置文件
├── mmdet/           # (核心)框架源代码
├── tools/           # (核心)训练、测试、部署等工具脚本
├── data/            # (通常由用户创建)存放数据集
├── work_dirs/       # (自动生成)存放训练日志、模型权重
├── docs/            # 文档和教程
├── projects/        # 一些特殊或实验性的项目
├── tests/           # 单元测试
├── demo/            # 演示用的示例脚本和图片
└── requirements/    # 依赖文件

2.1 准备自己的配置文件

接下来我们要用自己的数据集基于faster-rcnn来做训练。首先先创建我们的配置文件,我们一般把自己的实验创建在configs目录下,与项目目录存放的内容保持一致,当然你也可以在其他路径下创建,或者直接修改已有的配置文件(不是很推荐)。configs目录下的主要存放内容如下:

mmdetection/
└── configs/                          # 主配置目录
    ├── _base_/                       # 基础配置目录,包含可复用的组件配置
    │   ├── datasets/                 # 数据集配置
    │   │   ├── coco_detection.py     # COCO 检测数据集配置
    │   │   ├── coco_instance.py      # COCO 实例分割配置
    │   │   ├── voc0712.py            # VOC 数据集配置
    │   │   └── ...
    │   ├── models/                   # 模型基础配置
    │   │   ├── faster_rcnn_r50_fpn.py     # Faster R-CNN 模型配置
    │   │   ├── mask_rcnn_r50_fpn.py       # Mask R-CNN 模型配置
    │   │   ├── retinanet_r50_fpn.py       # RetinaNet 模型配置
    │   │   └── ...
    │   ├── schedules/                # 训练调度策略
    │   │   ├── schedule_1x.py        # 1x 训练策略 (12 epochs)
    │   │   ├── schedule_2x.py        # 2x 训练策略 (24 epochs)
    │   │   ├── schedule_20e.py       # 20 epochs 训练策略
    │   │   └── ...
    │   └── default_runtime.py        # 默认运行时设置(日志、钩子等)
    │
    ├── faster_rcnn/                  # Faster R-CNN 算法系列配置
    │   ├── faster_rcnn_r50_fpn_1x_coco.py
    │   ├── faster_rcnn_r50_fpn_2x_coco.py
    │   ├── faster_rcnn_r101_fpn_1x_coco.py
    │   └── ...
    │
    ├── mask_rcnn/                    # Mask R-CNN 算法系列配置
    │   ├── mask_rcnn_r50_fpn_1x_coco.py
    │   ├── mask_rcnn_r50_fpn_2x_coco.py
    │   └── ...
    │
    ├── retinanet/                    # RetinaNet 算法系列配置
    │   ├── retinanet_r50_fpn_1x_coco.py
    │   ├── retinanet_r50_fpn_2x_coco.py
    │   └── ...
    ├── ...                           # 其他算法目录

即执行脚本:

 cd configs
 mkdir my_project
 cd my_project
 touch faster_rcnn_r50_fpn_1x_coco_my_project.py

我们上述的命名含义为:

  1. faster_rcnn

    含义:这指定了所使用的核心算法架构

    说明:表示这个配置文件是基于 Faster R-CNN 这个两阶段目标检测器的。

  2. r50

    含义:这指定了所用的主干网络 (Backbone)

    说明r50resnet50的缩写,表示使用 50 层的深度残差网络 (ResNet-50) 作为主干特征提取器。

  3. fpn

    含义:这指定了所用的颈部网络 (Neck)

    说明fpnFeature Pyramid Network的缩写,表示使用了特征金字塔网络。这是一个非常重要的组件,它融合了来自主干网络不同深度的特征,使模型能够更好地处理不同尺度的目标。

  4. 1x

    含义:这指定了训练策略 (Schedule)

    说明1x是 MMDetection 中的一个标准训练周期约定,通常代表在 COCO 数据集上训练 12 个周期 (epochs)。类似的还有 2x(24 epochs)、20e(20 epochs) 等。它隐含了学习率下降的时机和总的迭代次数。

  5. coco

    含义:这指定了数据集 (Dataset)

    说明:表示该模型是在 MS COCO 数据集上进行训练和评估的。这个部分决定了数据加载、类别定义和评估指标(如 mAP)。

  6. my_project

    含义:这是我们自己的项目。

整个文件名基本阐述清楚了我们这个项目的模型,建议大家也保持这种风格,可以很清晰的区分自己的每次实验。

2.1.1 数据集

创建完我们的配置文件我们先来构建自己的数据集。

MMDetection支持COCO格式,我们将数据集准备好后可以存放在任意目录(一般为上述的项目根目录下的data文件夹下)。目录结构一般设置为

my_coco_data/
├── annotations/              # 存放所有标注文件的目录
│   ├── train.json    # 训练集的实例标注文件
│   ├── val.json      # 验证集的实例标注文件
│   └── test.json      # 测试集的实例标注文件(可选,通常无标注)
└── train/                # 训练集图像目录(目录名通常与JSON文件中的前缀对应)
    ├── 000000000009.jpg
    ├── 000000000025.jpg
    ├── 000000000030.jpg
    └── ...
└── val/                  # 验证集图像目录
    ├── 000000000139.jpg
    ├── 000000000285.jpg
    ├── 000000000632.jpg
    └── ...
└── test/                 # (可选)测试集图像目录(通常无公开标注)
    ├── 000000000001.jpg
    ├── 000000000016.jpg
    └── ...

数据集放置好了以后我们来编写config告诉框架要去哪里读取我们的数据集:

# 1.首先我们是基于faster-rcnn构建的配置文件,所以我们要先继承原有的配置文件,然后做必要的修改
_base_ = '../faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py' #相对我们当前的目录,找到要继承的配置文件
# 2.声明我们使用数据类型
dataset_type = 'CocoDataset' 
# 3.配置数据根目录
data_root = '/root/autodl-tmp/dataset/coco/my_coco_data/' # 配置我们的数据根目录,我这边放到了另一个目录下,因为这个目录挂在固态上,读取速度更快一点
# 4.修改类别,检测框颜色等信息
metainfo = {
    'classes': ('11','12','13','14','15','16','17',
                '21','22','23','24','25','26','27',
                '31','32','33','34','35','36','37','38',
                '41','42','43','44','45','46','47','48',
                '51','52','53','54','55',
                '61','62','63','64','65',
                '71','72','73','74','75',
                '81','82','83','84','85',
                '9',
                ),
    'palette': [
        (230, 50, 80), (60, 180, 75), (0, 130, 200), (245, 150, 0), (145, 30, 180),
    (70, 240, 120), (220, 190, 40), (170, 110, 80), (30, 200, 220), (255, 0, 100),
    (40, 90, 160), (210, 80, 150), (100, 200, 0), (180, 0, 90), (50, 160, 200),
    (255, 120, 60), (10, 140, 70), (200, 50, 120), (80, 180, 220), (240, 60, 180),
    (120, 200, 50), (160, 30, 150), (20, 220, 160), (255, 90, 30), (70, 130, 210),
    (0, 180, 240), (220, 140, 100), (50, 70, 190), (180, 200, 40), (130, 0, 120),
    (200, 180, 0), (90, 50, 140), (30, 240, 100), (255, 70, 150), (110, 160, 60),
    (0, 100, 220), (240, 200, 80), (150, 80, 170), (70, 0, 160), (255, 160, 20),
    (40, 200, 140), (190, 60, 110), (80, 220, 180), (230, 0, 70), (120, 120, 200),
    (60, 150, 30), (210, 100, 180), (10, 80, 130), (255, 130, 90), (170, 160, 50),
    (0, 200, 100)
    ]
}

2.1.2 数据加载和预处理

配置好了数据集后,我们要进入的下一个阶段就是数据加载和预处理。如果你的数据不需要预处理,可以直接跳过这个配置,删除掉dataset中的pipeline属性。同样我们还是修改我们的配置文件。

预处理我们将原本的随机翻转去掉添加一个Pad操作。这个的写法有两种一个是按照MMEngine中的配置写delete,这个我会在下面附上链接(个人不是很推荐,感觉有点过度封装了,使用不是很方便)。另一种就是找到继承的原始文件,把想改的那段复制出来,直接调整。

# 1.数据加载
train_dataloader = dict(
    batch_size=8,                    # 每个批次的样本数量为8
    num_workers=2,                   # 使用2个子进程来加载数据
    persistent_workers=True,         # 在训练周期之间保持工作进程活跃,避免反复创建和销毁进程的开销
    sampler=dict(type='DefaultSampler', shuffle=True),  # 使用默认采样器,并且打乱数据顺序
    batch_sampler=dict(type='AspectRatioBatchSampler'), # 根据图像宽高比对批次进行采样,有助于减少填充和提高训练效率
    dataset=dict(                    # 数据集配置
        type=dataset_type,           # 数据集类型(如CocoDataset、VOCDataset等)
        metainfo=metainfo,           # 数据集的元信息,通常包含类别名称等
        data_root=data_root,         # 数据集根目录路径
        ann_file='annotations/train.json',  # 标注文件路径(相对于data_root)
        data_prefix=dict(img='preprocessing_images/'),  # 图像文件路径前缀(相对于data_root)
        filter_cfg=dict(filter_empty_gt=True, min_size=32),  # 过滤配置:过滤掉没有真实标注框和目标太小的样本
        pipeline=train_pipeline     # 训练时的数据预处理流程(包括数据增强)
    )
)
val_dataloader = dict(
    batch_size=1,                    # 验证时批次大小为1(通常验证时不需批量处理)
    num_workers=2,                   # 使用2个子进程加载数据
    persistent_workers=True,         # 保持工作进程活跃
    drop_last=False,                 # 不丢弃最后一个不完整的批次(确保所有数据都被评估)
    sampler=dict(type='DefaultSampler', shuffle=False),  # 使用默认采样器,但不打乱数据顺序
    dataset=dict(
        type=dataset_type,           # 数据集类型(应与训练集一致)
        metainfo=metainfo,           # 与训练集相同的元信息
        data_root=data_root,         # 相同的数据集根目录
        ann_file='annotations/val.json',  # 验证集标注文件路径
        data_prefix=dict(img='preprocessing_images/'),  # 相同的图像路径前缀
        test_mode=True,              # 设置为测试模式(不会应用训练特有的数据增强)
        pipeline=test_pipeline      # 验证时的数据预处理流程(通常不包含随机增强)
    )
)
test_dataloader = val_dataloader  # 测试集使用与验证集相同的配置

# 2.预处理
# 训练文件的数据处理流水线
train_pipeline = [
    # 1. 从文件加载图像
    dict(type='LoadImageFromFile', backend_args=backend_args),
    
    # 2. 加载标注信息(边界框)
    dict(type='LoadAnnotations', with_bbox=True),
    
    # 3. 调整图像大小,保持宽高比
    dict(type='Resize', scale=(1333, 800), keep_ratio=True),
    
    # 4. 填充图像到指定倍数
    dict(type='Pad', size_divisor=32),
    
    # 5. 随机翻转(当前被注释掉了)
    # dict(type='RandomFlip', prob=0.5),
    
    # 6. 将数据打包成模型需要的格式
    dict(type='PackDetInputs')
]
# 测试和验证的数据处理流水线
test_pipeline = [
    # 1. 从文件加载图像
    dict(type='LoadImageFromFile', backend_args=backend_args),
    
    # 2. 调整图像大小,保持宽高比
    dict(type='Resize', scale=(1333, 800), keep_ratio=True),
    
    # 3. 加载标注信息(如果有的话)
    dict(type='LoadAnnotations', with_bbox=True),
    
    # 4. 将数据打包成模型需要的格式,并保留更多元信息
    dict(
        type='PackDetInputs',
        meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
                   'scale_factor'))
]

配置(Config) — mmengine 0.10.7 文档

2.1.3 模型

完成了数据的加载和预处理,下一步我们的数据就要送入模型进行训练了,目前我们就是基于Faster-RCNN进行训练的,不做其他的调整,这里我们只需要将目标的类型修改为和我们的数据集相同就可以。

# 将模型的目标类型数修改为和数据集相同
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=51)))

2.1.4 验证

模型训练完成后就是要验证了,我们使用的是Coco数据集,我们使用coco的评价标准来进行评价,配置文件编写如下。

val_evaluator = dict(
    type='CocoMetric',  # 使用COCO格式的评估指标
    ann_file=data_root + 'annotations/val.json',  # 验证集标注文件路径
    metric=['bbox', 'proposal'],  # 要计算的评估指标类型
    format_only=False,  # 不只格式化结果,而是直接计算指标
    classwise=True# 输出每个类别的详细评估结果
    backend_args=None # 文件后端参数
)

2.1.5 超参数

完成上面的验证后其实我们就把模型训练里的参数都配置完成了,接下来我们要调整一下超参数,这里以调整轮数为例子(自己修改时要记得保持命名规范哦)。

train_cfg = dict(
    type='EpochBasedTrainLoop',  # 使用基于训练轮次(epoch)的训练循环
    max_epochs=100,              # 最大训练轮次为100
    val_interval=1               # 每1个epoch验证一次
)

好的,到此为止我们已经修改了整个训练流程中的所有内容,我们可以开始我们自己的训练啦。

2.2 训练自己的模型

配置好文件后训练就变得特别简单,我们只需要进入项目的根目录,然后执行

python tools/train.py configs/my_project/faster-rcnn_r50_fpn_1x_coco_my_project.py --work-dir work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project

这里脚本的含义是运行tools目录下的train.py脚本,读取configs/my_project/faster-rcnn_r50_fpn_1x_coco_my_project.py为此次训练的配置文件,将训练日志等内容保存在根目录下 work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project文件夹内。

Tips:训练时间较长时可以使用如下的脚本

nohup python tools/train.py configs/my_project/faster-rcnn_r50_fpn_1x_coco_my_project.py --work-dir work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project > train.log 2>&1;

nohup表示在后台运行,我们将程序输出重定向到train.log文件中。

2.3 测试及推理

训练完成后我们可以对训练好的模型在我们的测试集进行测试,脚本如下:

python tools/test.py \
    work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project/faster-rcnn_r50_fpn_1x_coco_my_project.py \
    work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project/epoch_60.pth \
    --work-dir results \
    --out raw_predictions.pkl \
    --show-dir visualizations

这个脚本的含义是运行tools目录下的test.py脚本,读取我们刚刚训练生产的配置文work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project/faster-rcnn_r50_fpn_1x_coco_my_project.py 使用刚刚训练时第60轮保存的模型work_dirs/faster-rcnn_r50_fpn_1x_coco_my_project/epoch_60.pth。将测试结果保存在目录results下,将模型的原始输出保存到**raw_predictions.pkl** 文件中去。将带有预测结果可视化的图像保存在visualizations目录下。


到此为止我们完成了安装MMDetection框架,并用其构建好的模型在我们自己的数据集上进行训练的工作。可以看到MMDetection还是十分的方便的,熟悉以后我们只需要修改几个配置就可以快速的在多种检测模型上进行实验。但官方教程很多地方写的都比较模糊,可能开发人员默认很多前置知识我们是都懂的。至少我在刚上手时就很容易蒙圈,所以我按照自己的理解又详细的写了一遍,希望能帮助到刚入门朋友们。后面会继续更新如何进行模型的调整以及详细的测试以及分析还有框架源码的分析(疯狂挖坑中),需要的朋友们点个关注,后续不迷路。