## 一、MMDetection 概述
### 1.1 什么是 MMDetection
MMDetection 是一个基于 PyTorch 的开源目标检测工具箱,由 OpenMMLab 团队开发和维护。它包含了丰富的主流目标检测、实例分割和全景分割算法,支持 Faster R-CNN、Mask R-CNN、YOLO 系列、SSD、RetinaNet、DETR 等 20+ 种经典和现代模型。
整个 OpenMMLab 家族除了 MMDetection,还包含针对目标跟踪的 MMTracking、针对 3D 目标检测的 MMDetection3D 等开源项目,它们都以 PyTorch 和 MMCV/MMEngine 为基础。
### 1.2 框架核心优势
- **模块化架构**:将检测模型拆分为 Backbone、Neck、Head 等可独立替换的组件
- **丰富的预训练模型库**:提供 COCO、Pascal VOC 等数据集的预训练权重
- **高效的训练和推理**:支持多 GPU 训练和分布式训练
- **易于扩展**:提供清晰的接口和文档,方便添加新算法、数据集和评估指标
- **多硬件支持**:兼容 NVIDIA GPU、AMD GPU 及 CPU 推理
### 1.3 框架整体架构
MMDetection 主要由 7 个核心部分组成:
| 部分 | 功能 |
|------|------|
| **apis** | 提供模型推理的高层 API |
| **structures** | 提供 bbox、mask、DetDataSample 等数据结构 |
| **datasets** | 支持目标检测、实例分割、全景分割的各种数据集 |
| **transforms** | 包含丰富的数据增强变换 |
| **models** | 检测器的核心组件,包含 backbone、neck、dense_heads、roi_heads、losses 等 |
| **engine** | 运行时组件,包含 runner、schedulers、optimizers、hooks |
| **evaluation** | 提供不同的模型评估指标 |
## 二、环境搭建
### 2.1 安装 Anaconda
在搭建环境之前,需要先安装 Anaconda 或 Miniconda 来管理 Python 环境。从官方网站下载并安装 Miniconda。
### 2.2 创建并激活 Conda 环境
```bash
# 创建环境(Python 3.8)
conda create --name openmmlab python=3.8 -y
# 激活环境
conda activate openmmlab
```
### 2.3 安装 PyTorch
根据你的 CUDA 版本,从 PyTorch 官网选择合适的版本进行安装。以 CUDA 11.3 为例:
```bash
pip install torch==1.12.1+cu113 torchvision -f https://download.pytorch.org/whl/torch_stable.html
```
**注意**:安装 GPU 版本的 PyTorch 前,需要通过 `nvidia-smi` 查看显卡的 CUDA 版本是否支持。
### 2.4 安装 MMCV
MMCV 是 OpenMMLab 的基础库,提供了注册器、Runner、Hook 等核心功能。需要根据 PyTorch 和 CUDA 版本选择合适的 MMCV 版本。
```bash
pip install -U openmim
mim install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.12.0/index.html
```
### 2.5 安装 MMDetection
有两种安装方式:
**方式一:直接安装(适合快速使用)**
```bash
pip install mmdet
```
**方式二:源码安装(适合开发或修改代码)**
```bash
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -v -e .
```
### 2.6 验证安装
运行以下 Python 代码验证安装是否成功:
```python
from mmdet.apis import init_detector, inference_detector
print("MMDetection installed successfully!")
```
## 三、核心机制详解
### 3.1 注册机制(Registry)
注册机制是 MMDetection 管理模块的核心方式。在 MMCV 中,注册器可以看作一个**从字符串到类(或函数)的映射表**——一个注册器中的类通常有相似的接口,但实现不同的算法或支持不同的数据集。
#### 3.1.1 Registry 的工作原理
```python
from mmcv.utils import Registry
# 创建一个注册器
MODELS = Registry('models')
# 使用装饰器注册模块
@MODELS.register_module()
class MyBackbone:
def __init__(self, depth):
self.depth = depth
```
注册的核心逻辑是将模块名称(如 `'MyBackbone'`)和模块类保存到注册器的 `_module_dict` 字典中。之后,通过配置文件中的 `type` 字段(如 `type='MyBackbone'`),框架就能自动找到对应的类并实例化。
#### 3.1.2 常用的注册器
MMDetection 中预定义了多个注册器来管理不同类型的模块:
| 注册器 | 管理内容 |
|--------|----------|
| `DATASETS` | 数据集类 |
| `BACKBONES` | 主干网络 |
| `NECKS` | Neck 组件 |
| `HEADS` | Head 组件(分为 DenseHead 和 RoIHead) |
| `LOSSES` | 损失函数 |
#### 3.1.3 模块的调用
通过配置字典可以实例化已注册的模块:
```python
# 配置字典
cfg = dict(type='MyBackbone', depth=50)
# 从注册器构建模块
backbone = MODELS.build(cfg)
```
### 3.2 Hook 机制
Hook(钩子)是一种在训练流程的特定节点插入自定义操作的机制。它允许用户在训练的不同阶段执行额外逻辑,而无需修改核心训练代码。
#### 3.2.1 Hook 的执行节点
从训练开始到结束,共有约 20 个节点可以插入 Hook。常见的插入点包括:
- 训练开始/结束前
- 每个 Epoch 开始/结束前
- 每个 Iteration 开始/结束前
- 反向传播前后
- 优化器更新前后
#### 3.2.2 常用的内置 Hook
| Hook 名称 | 功能 |
|-----------|------|
| `CheckInvalidLossHook` | 检查损失是否为 NaN |
| `MemoryProfilerHook` | 记录内存使用信息 |
| `NumClassCheckHook` | 检查类别数配置是否正确 |
| `SyncNormHook` | 同步批归一化 |
| `YOLOXLrUpdaterHook` | YOLOX 学习率更新策略 |
#### 3.2.3 使用 Hook
在配置文件中通过 `custom_hooks` 字段添加 Hook:
```python
custom_hooks = [
dict(type='MemoryProfilerHook', interval=50),
]
```
### 3.3 Runner(执行器)
Runner 是控制训练流程的核心组件。MMDetection 中最常用的是 `EpochBasedRunner`,它按 Epoch 组织训练循环。Runner 负责调度训练过程,并在各个节点触发 Hook 的回调函数。
## 四、配置文件
配置文件是 MMDetection 的灵魂。通过配置文件,用户可以在不修改代码的情况下组合不同的数据集、模型、训练策略和运行时设置。
### 4.1 配置文件结构
配置文件的三个基本组件类型位于 `config/_base_` 目录下:
- **dataset**:数据集配置
- **model**:模型配置
- **default_runtime**:运行时默认设置(日志、检查点等)
- **schedule**:训练策略配置
### 4.2 配置继承
MMDetection 支持配置文件的继承机制,通过 `_base_` 字段实现:
```python
# 继承基础配置
_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
# 修改必要参数
model = dict(
roi_head=dict(
bbox_head=dict(
num_classes=5 # 修改为自定义数据集的类别数
)
)
)
data = dict(
train=dict(
ann_file='path/to/train/annotation.json',
img_prefix='path/to/train/images/'
)
)
```
### 4.3 配置文件命名规范
配置文件的命名遵循以下格式:
```
{model}_[model setting]_{backbone}_{neck}_[norm setting]_[misc]_[gpu x batch]_{schedule}_{dataset}
```
例如:`faster_rcnn_r50_fpn_1x_coco.py`
### 4.4 查看完整配置
可以通过以下命令查看经过继承合并后的完整配置:
```bash
python tools/misc/print_config.py /PATH/TO/CONFIG.py
```
### 4.5 通过命令行修改配置
运行训练或测试时,可以通过 `--cfg-options` 动态修改配置:
```bash
# 修改模型参数
python tools/train.py config.py --cfg-options model.backbone.norm_eval=False
# 修改数据流程
python tools/train.py config.py --cfg-options data.train.pipeline.0.type=LoadImageFromWebcam
```
## 五、数据集
### 5.1 使用标准数据集
MMDetection 内置支持 COCO、Pascal VOC、Cityscapes 等多个标准数据集。使用标准数据集时,只需在配置文件中指定数据集类型和标注文件路径即可。
### 5.2 自定义数据集
MMDetection 支持三种方式使用自定义数据集:
1. **转换为 COCO 格式**(推荐)
2. **转换为中间格式**
3. **实现新的 Dataset 类**
#### 5.2.1 方法一:转换为 COCO 格式
将数据转换为 COCO 格式是最简单的方式。COCO 格式的 JSON 标注文件需要包含三个必要的键:
```json
{
"images": [
{"file_name": "image001.jpg", "height": 427, "width": 640, "id": 1}
],
"annotations": [
{"bbox": [192.81, 224.8, 74.73, 33.43], "category_id": 0, "image_id": 1, "id": 1}
],
"categories": [
{"id": 0, "name": "cat"},
{"id": 1, "name": "dog"}
]
}
```
数据转换完成后,修改配置文件:
```python
_base_ = './cascade_mask_rcnn_r50_fpn_1x_coco.py'
# 定义类别
classes = ('cat', 'dog')
# 修改数据集配置
data = dict(
train=dict(
type='CocoDataset',
classes=classes,
ann_file='path/to/train.json',
img_prefix='path/to/train/images/'
),
val=dict(
type='CocoDataset',
classes=classes,
ann_file='path/to/val.json',
img_prefix='path/to/val/images/'
)
)
# 修改模型类别数
model = dict(
roi_head=dict(
bbox_head=dict(
num_classes=len(classes) # 2
)
)
)
```
#### 5.2.2 方法二:实现自定义 Dataset 类
如果需要更复杂的自定义逻辑,可以继承 `CustomDataset` 并重写相应方法:
```python
from mmdet.datasets import CustomDataset, DATASETS
@DATASETS.register_module()
class MyDataset(CustomDataset):
def load_annotations(self, ann_file):
# 加载标注文件,返回数据列表
pass
def get_ann_info(self, idx):
# 返回第 idx 个样本的标注信息
pass
```
## 六、模型构建
### 6.1 模型的模块化分解
MMDetection 将一个完整的检测模型拆分为三个主要部分:
- **Backbone(主干网络)** :负责提取图像特征,如 ResNet、VGG、EfficientNet 等
- **Neck(颈部网络)** :负责特征融合和增强,如 FPN、PAFPN、NASFPN 等
- **Head(头部网络)** :负责最终的目标检测预测
其中 Head 又分为两类:
- **DenseHead**:用于单阶段检测器(如 YOLO、RetinaNet),位于 `mmdet/models/dense_heads/`
- **RoIHead**:用于两阶段检测器(如 Faster R-CNN、Mask R-CNN),位于 `mmdet/models/roi_heads/`
### 6.2 自定义模型组件
添加新的模型组件需要三个步骤:
**Step 1:实现组件类并注册**
```python
# mmdet/models/backbones/my_backbone.py
from mmdet.models import BACKBONES
from mmengine.model import BaseModule
@BACKBONES.register_module()
class MyBackbone(BaseModule):
def __init__(self, depth, *args, **kwargs):
super().__init__(*args, **kwargs)
# 初始化网络层
def forward(self, x):
# 前向传播
return x
```
**Step 2:导入模块**
在 `mmdet/models/backbones/__init__.py` 中添加:
```python
from .my_backbone import MyBackbone
```
**Step 3:在配置文件中使用**
```python
model = dict(
backbone=dict(
type='MyBackbone',
depth=50
),
# ...
)
```
### 6.3 跨库调用模块
MMEngine 的注册器支持跨软件包的模块构建。例如,在 MMDetection 中使用 MMClassification 的 Backbone:
```python
# 在配置中添加 custom_imports
custom_imports = dict(imports=['mmcls.models'], allow_failed_imports=False)
model = dict(
backbone=dict(
type='mmcls.ConvNeXt', # 使用 mmcls 中的 ConvNeXt
# ...
)
)
```
## 七、训练与测试
### 7.1 训练模型
完成数据准备和配置文件后,使用训练脚本启动训练:
```bash
# 单 GPU 训练
python tools/train.py configs/my_config.py
# 多 GPU 训练
bash tools/dist_train.sh configs/my_config.py 8
```
### 7.2 测试与评估
```bash
# 单 GPU 测试
python tools/test.py configs/my_config.py work_dirs/epoch_12.pth --eval bbox
# 多 GPU 测试
bash tools/dist_test.sh configs/my_config.py work_dirs/epoch_12.pth 8 --eval bbox
```
### 7.3 推理
MMDetection 提供了高层 API 用于图像推理:
```python
from mmdet.apis import init_detector, inference_detector
import mmcv
# 初始化模型
config_file = 'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = 'checkpoints/faster_rcnn_r50_fpn_1x_coco.pth'
model = init_detector(config_file, checkpoint_file, device='cuda:0')
# 推理
img = mmcv.imread('demo/demo.jpg')
result = inference_detector(model, img)
# 可视化
from mmdet.apis import show_result_pyplot
show_result_pyplot(model, img, result)
```
MMDetection 3.0 还提供了更简洁的 `DetInferencer` 接口:
```python
from mmdet.apis import DetInferencer
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco')
result = inferencer('demo/demo.jpg', show=True)
```
## 八、自定义扩展
### 8.1 自定义损失函数
```python
from mmdet.models import LOSSES
import torch.nn as nn
@LOSSES.register_module()
class MyLoss(nn.Module):
def __init__(self, reduction='mean'):
super().__init__()
self.reduction = reduction
def forward(self, pred, target):
# 计算损失
loss = ...
return loss
```
### 8.2 自定义数据预处理流程
数据预处理通过 Pipeline 的方式组织:
```python
from mmcv.transforms import BaseTransform
from mmdet.datasets import TRANSFORMS
@TRANSFORMS.register_module()
class MyTransform(BaseTransform):
def __init__(self, param):
self.param = param
def transform(self, results):
# 处理数据
return results
```
### 8.3 自定义 Hook
```python
from mmengine.hooks import Hook
class MyCustomHook(Hook):
def __init__(self, interval=100):
self.interval = interval
def after_train_iter(self, runner, batch_idx, data_batch=None, outputs=None):
if batch_idx % self.interval == 0:
# 执行自定义操作
pass
```
在配置文件中使用:
```python
custom_hooks = [
dict(type='MyCustomHook', interval=50)
]
```
## 九、常见问题与实用技巧
### 9.1 模块未注册问题
如果遇到 `KeyError: 'xxx is not in the registry'` 错误,通常是因为模块文件没有被导入。需要在 `__init__.py` 中导入该模块,或在配置中添加 `custom_imports`。
### 9.2 查看完整配置
```bash
python tools/misc/print_config.py configs/my_config.py
```
### 9.3 冻结主干网络
在训练时冻结 Backbone 的参数:
```python
model = dict(
backbone=dict(
frozen_stages=4 # 冻结前4个stage
)
)
```
### 9.4 使用预训练权重
```python
# 在配置中指定预训练权重
load_from = 'path/to/pretrained.pth'
```
### 9.5 多尺度训练
```python
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', scale=[(1333, 640), (1333, 800)], keep_ratio=True),
# ...
]
```
## 十、总结
本文系统地介绍了 MMDetection 框架的各个方面:
1. **框架概述**:了解了 MMDetection 的定位、核心优势和整体架构
2. **环境搭建**:掌握了从零搭建 MMDetection 开发环境的完整流程
3. **核心机制**:深入理解了注册器(Registry)和 Hook 两大核心机制的工作原理
4. **配置文件**:学会了配置文件的继承、修改和动态调整
5. **数据集**:掌握了使用标准数据集和自定义数据集的方法
6. **模型构建**:理解了模型的模块化分解和自定义组件的开发流程
7. **训练与推理**:学会了训练、测试和推理的完整操作
8. **自定义扩展**:了解了损失函数、数据预处理和 Hook 的自定义方法
MMDetection 通过**模块化设计**和**配置驱动**的理念,极大地降低了目标检测算法的开发门槛,提高了代码复用率。无论是工业应用中的快速部署,还是学术研究中的算法创新,MMDetection 都是一个强大且实用的工具。