Commit ff793569 authored by dengjb's avatar dengjb
Browse files

update code

parent fdfe3c4f
Pipeline #639 failed with stages
in 0 seconds
# 自定义训练配置
## 自定义优化相关的配置
优化相关的配置现在已全部集成到 `optim_wrapper` 中,通常包含三个域:`optimizer`, `paramwise_cfg``clip_grad`,具体细节见 [OptimWrapper](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.md)。下面这个例子中,使用了 `AdamW` 作为优化器,主干部分的学习率缩小到原来的十分之一,以及添加了梯度裁剪。
```python
optim_wrapper = dict(
type='OptimWrapper',
# 优化器
optimizer=dict(
type='AdamW',
lr=0.0001,
weight_decay=0.05,
eps=1e-8,
betas=(0.9, 0.999)),
# 参数层面的学习率和正则化设置
paramwise_cfg=dict(
custom_keys={
'backbone': dict(lr_mult=0.1, decay_mult=1.0),
},
norm_decay_mult=0.0),
# 梯度裁剪
clip_grad=dict(max_norm=0.01, norm_type=2))
```
### 自定义 Pytorch 中优化器设置
我们已经支持了 Pytorch 中实现的所有优化器,要使用这些优化器唯一要做就是修改配置文件中的 `optimi_wrapper` 中的 `optimzer` 域。比如,如果想要使用 `ADAM` 作为优化器(可能会导致性能下降),所需要做的修改如下。
```python
optim_wrapper = dict(
type='OptimWrapper',
optimizer=dict(type='Adam', lr=0.0003, weight_decay=0.0001))
```
要修改模型的学习率,用户只需要修改 `optimizer` 中的 `lr` 域。用户可以直接参考 PyToch 的 [API doc](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim) 来进行参数的设置。
### 自定义优化器
#### 1. 定义一个新优化器
自定义优化器可以定义的方式如下:
假设你想要添加一个名为 `MyOptimizer` 的优化器,它包含三个参数 `a``b``c`。你需要新建一个名为
`mmdet/engine/optimizers` 的文件夹。然后在文件(比如,`mmdet/engine/optimizers/my_optimizer.py`)实现一个新的优化器。
```python
from mmdet.registry import OPTIMIZERS
from torch.optim import Optimizer
@OPTIMIZERS.register_module()
class MyOptimizer(Optimizer):
def __init__(self, a, b, c)
```
#### 2. 导入自定义的优化器
为了能找到上面的所定义的模块,这个模块必须要先导入到主命名空间中。有两种方式可以实现这一点。
- 修改 `mmdet/engine/optimizers/__init__.py` 来导入模块。
新定义的模块必须导入到 `mmdet/engine/optimizers/__init__.py`,这样注册器才能找到该模块并添加它。
```python
from .my_optimizer import MyOptimizer
```
- 在配置文件使用 `custom_imports` 来手动导入模块。
```python
custom_imports = dict(imports=['mmdet.engine.optimizers.my_optimizer'], allow_failed_imports=False)
```
`mmdet.engine.optimizers.my_optimizer` 模块将在程序开始时导入,之后 `MyOptimizer` 类会被自动注册。注意:应该导入 `MyOptimizer` 所在的文件,即 `mmdet.engine.optimizers.my_optimizer`,而不是 `mmdet.engine.optimizers.my_optimizer.MyOptimizer`
实际上,用户也可以在别的目录结构下来进行导入模块,只要改模块可以在 `PYTHONPATH` 中找到。
#### 3. 在配置文件中指定优化器
接下来,你可以在配置文件中的 `optim_wrapper` 域中的中 `optimizer` 域中设置你实现的优化器 `MyOptimizer`。在配置文件中,优化器在 `optimizer` 域中的配置方式如下:
```python
optim_wrapper = dict(
type='OptimWrapper',
optimizer=dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001))
```
为了使用你的优化器,可以进行如下修改
```python
optim_wrapper = dict(
type='OptimWrapper',
optimizer=dict(type='MyOptimizer', a=a_value, b=b_value, c=c_value))
```
### 自定义优化器包装构造类
一些模型可能存在一些特定参数的优化设置,比如,BN 层的权重衰减。用户可以通过自定义优化器包装构造类来实现这些精细化的参数调整。
```python
from mmengine.optim import DefaultOptiWrapperConstructor
from mmdet.registry import OPTIM_WRAPPER_CONSTRUCTORS
from .my_optimizer import MyOptimizer
@OPTIM_WRAPPER_CONSTRUCTORS.register_module()
class MyOptimizerWrapperConstructor(DefaultOptimWrapperConstructor):
def __init__(self,
optim_wrapper_cfg: dict,
paramwise_cfg: Optional[dict] = None):
def __call__(self, model: nn.Module) -> OptimWrapper:
return optim_wrapper
```
优化器包装构造类的具体实现见[这里](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/optimizer/default_constructor.py#L18),用户以它为模板,来实现新的优化器包装构造类。
### 额外的设置
一些没有被优化器实现的技巧(比如,参数层面的学习率设置)应该通过优化器包装构造类来实现或者钩子。我们列出了一些常用的设置用于稳定训练或者加速训练。请随意创建 PR,发布更多设置。
- __使用梯度裁剪来稳定训练__:
一些模型需要进行梯度裁剪来稳定训练过程,例子如下:
```python
optim_wrapper = dict(
_delete_=True, clip_grad=dict(max_norm=35, norm_type=2))
```
如果你的配置已经集成了基础配置(包含了 `optim_wrapper` 的配置),那么你需要添加 `_delete_=True` 来覆盖掉不需要的设置。具体见[配置相关的文档](https://mmdetection.readthedocs.io/en/latest/tutorials/config.html)
- __使用动量调度加速模型收敛__:
我们支持动量调度器根据学习率修改模型的动量,这可以使模型以更快的方式收敛。动量调度器通常与学习率调度器一起使用,例如 [3D 检测](https://github.com/open-mmlab/mmdetection3d/blob/dev-1.x/configs/_base_/schedules/cyclic-20e.py) 中使用以下配置以加速收敛。
更多细节请参考 [CosineAnnealingLR](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/scheduler/lr_scheduler.py#L43)[CosineAnnealingMomentum](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/scheduler/momentum_scheduler.py#L71) 的具体实现。
```python
param_scheduler = [
# 学习率调度器
# 在前 8 个 epoch, 学习率从 0 增大到 lr * 10
# 在接下来 12 个 epoch, 学习率从 lr * 10 减小到 lr * 1e-4
dict(
type='CosineAnnealingLR',
T_max=8,
eta_min=lr * 10,
begin=0,
end=8,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingLR',
T_max=12,
eta_min=lr * 1e-4,
begin=8,
end=20,
by_epoch=True,
convert_to_iter_based=True),
# 动量调度器
# 在前 8 个 epoch, 动量从 0 增大到 0.85 / 0.95
# 在接下来 12 个 epoch, 学习率从 0.85 / 0.95 增大到 1
dict(
type='CosineAnnealingMomentum',
T_max=8,
eta_min=0.85 / 0.95,
begin=0,
end=8,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingMomentum',
T_max=12,
eta_min=1,
begin=8,
end=20,
by_epoch=True,
convert_to_iter_based=True)
]
```
## 自定义训练策略
默认情况下,我们使用 1x 的学习率调整策略,这会条用 MMEngine 中的 [MultiStepLR](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/scheduler/lr_scheduler.py#L139)
我们支持许多其他学习率调整策略,具体见[这里](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/scheduler/lr_scheduler.py),例如 `CosineAnnealingLR``PolyLR` 策略。下面有些例子
- 多项式学习率调整策略:
```python
param_scheduler = [
dict(
type='PolyLR',
power=0.9,
eta_min=1e-4,
begin=0,
end=8,
by_epoch=True)]
```
- 余弦退火学习率调整策略
```python
param_scheduler = [
dict(
type='CosineAnnealingLR',
T_max=8,
eta_min=lr * 1e-5,
begin=0,
end=8,
by_epoch=True)]
```
## 自定义训练循环
默认情况下,在 `train_cfg` 中使用 `EpochBasedTrainLoop`,并且在每个 epoch 训练之后进行验证,如下所示。
```python
train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_begin=1, val_interval=1)
```
实际上,[`IterBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L183%5D)\[`EpochBasedTrainLoop`\](https:// github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L18) 支持动态区间的方式进行验证,见下例。
```python
# 在第 365001 次迭代之前,我们每 5000 次迭代进行一次评估。
# 在第 365000 次迭代后,我们每 368750 次迭代进行一次评估,
# 这意味着我们在训练结束时进行评估。
interval = 5000
max_iters = 368750
dynamic_intervals = [(max_iters // interval * interval + 1, max_iters)]
train_cfg = dict(
type='IterBasedTrainLoop',
max_iters=max_iters,
val_interval=interval,
dynamic_intervals=dynamic_intervals)
```
## 自定义钩子
### 自定义自行实现的钩子
#### 1. 实现一个新的钩子
MMEngine 提供了许多有用的[钩子](https://mmdetection.readthedocs.io/en/latest/tutorials/hooks.html),但在某些情况下用户可能需要实现新的钩子。MMDetection 在 v3.0 中支持自定义钩子。因此,用户可以直接在 mmdet 或其基于 mmdet 的代码库中实现钩子,并通过仅在训练中修改配置来使用钩子。
这里我们给出一个在 mmdet 中创建一个新的钩子并在训练中使用它的例子。
```python
from mmengine.hooks import Hook
from mmdet.registry import HOOKS
@HOOKS.register_module()
class MyHook(Hook):
def __init__(self, a, b):
def before_run(self, runner) -> None:
def after_run(self, runner) -> None:
def before_train(self, runner) -> None:
def after_train(self, runner) -> None:
def before_train_epoch(self, runner) -> None:
def after_train_epoch(self, runner) -> None:
def before_train_iter(self,
runner,
batch_idx: int,
data_batch: DATA_BATCH = None) -> None:
def after_train_iter(self,
runner,
batch_idx: int,
data_batch: DATA_BATCH = None,
outputs: Optional[dict] = None) -> None:
```
根据钩子的功能,用户需要在 `before_run``after_run``before_train``after_train``before_train_epoch``after_train_epoch``before_train_iter``after_train_iter`。还有更多可以插入钩子的点,更多细节请参考 [base hook class](https://github.com/open-mmlab/mmengine/blob/main/mmengine/hooks/hook.py#L9)
#### 2. 注册新钩子
然后我们需要导入 `MyHook`。假设该文件位于 `mmdet/engine/hooks/my_hook.py` 中,有两种方法可以做到这一点:
- 修改 `mmdet/engine/hooks/__init__.py` 以导入它。
新定义的模块应该在 `mmdet/engine/hooks/__init__.py` 中导入,以便注册表找到新模块并添加它:
```python
from .my_hook import MyHook
```
- 在配置中使用 `custom_imports` 手动导入它
```python
custom_imports = dict(imports=['mmdet.engine.hooks.my_hook'], allow_failed_imports=False)
```
#### 3. 修改配置
```python
custom_hooks = [
dict(type='MyHook', a=a_value, b=b_value)
]
```
你还可以通过修改键 `priority` 的值为 `NORMAL``HIGHEST` 来设置挂钩的优先级,如下所示
```python
custom_hooks = [
dict(type='MyHook', a=a_value, b=b_value, priority='NORMAL')
]
```
默认情况下,钩子的优先级在注册期间设置为 `NORMAL`
### 使用 MMDetection 中实现的钩子
如果 MMDetection 中已经实现了该钩子,你可以直接修改配置以使用该钩子,如下所示
#### 例子: `NumClassCheckHook`
我们实现了一个名为 [NumClassCheckHook](https://github.com/open-mmlab/mmdetection/blob/main/mmdet/engine/hooks/num_class_check_hook.py) 的自定义钩子来检查 `num_classes` 是否在 head 中和 `dataset` 中的 `classes` 的长度相匹配。
我们在 [default_runtime.py](https://github.com/open-mmlab/mmdetection/blob/main/configs/_base_/default_runtime.py) 中设置它。
```python
custom_hooks = [dict(type='NumClassCheckHook')]
```
### 修改默认运行时钩子
有一些常见的钩子是通过 `default_hooks` 注册的,它们是
- `IterTimerHook`:记录 “data_time” 用于加载数据和 “time” 用于模型训练步骤的钩子。
- `LoggerHook`:从`Runner`的不同组件收集日志并将它们写入终端、JSON文件、tensorboard和 wandb 等的钩子。
- `ParamSchedulerHook`:更新优化器中一些超参数的钩子,例如学习率和动量。
- `CheckpointHook`:定期保存检查点的钩子。
- `DistSamplerSeedHook`:为采样器和批处理采样器设置种子的钩子。
- `DetVisualizationHook`:用于可视化验证和测试过程预测结果的钩子。
`IterTimerHook``ParamSchedulerHook``DistSamplerSeedHook` 很简单,通常不需要修改,所以这里我们将展示如何使用 `LoggerHook``CheckpointHook``DetVisualizationHook`
#### CheckpointHook
除了定期保存检查点,[`CheckpointHook`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/hooks/checkpoint_hook.py#L19) 提供了其他选项,例如`max_keep_ckpts``save_optimizer ` 等。用户可以设置 `max_keep_ckpts` 只保存少量检查点或通过 `save_optimizer` 决定是否存储优化器的状态字典。参数的更多细节在[这里](https://github.com/open-mmlab/mmengine/blob/main/mmengine/hooks/checkpoint_hook.py#L19)可以找到。
```python
default_hooks = dict(
checkpoint=dict(
type='CheckpointHook',
interval=1,
max_keep_ckpts=3,
save_optimizer=True))
```
#### LoggerHook
`LoggerHook` 可以设置间隔。详细用法可以在 [docstring](https://github.com/open-mmlab/mmengine/blob/main/mmengine/hooks/logger_hook.py#L18) 中找到。
```python
default_hooks = dict(logger=dict(type='LoggerHook', interval=50))
```
#### DetVisualizationHook
`DetVisualizationHook` 使用 `DetLocalVisualizer` 来可视化预测结果,`DetLocalVisualizer` 支持不同的后端,例如 `TensorboardVisBackend``WandbVisBackend` (见 [docstring](https://github.com/open-mmlab/mmengine/blob/main/mmengine/visualization/vis_backend.py) 了解更多细节)。用户可以添加多个后端来进行可视化,如下所示。
```python
default_hooks = dict(
visualization=dict(type='DetVisualizationHook', draw=True))
vis_backends = [dict(type='LocalVisBackend'),
dict(type='TensorboardVisBackend')]
visualizer = dict(
type='DetLocalVisualizer', vis_backends=vis_backends, name='visualizer')
```
# 自定义数据预处理流程
1. 在任意文件里写一个新的流程,例如在 `my_pipeline.py`,它以一个字典作为输入并且输出一个字典:
```python
import random
from mmcv.transforms import BaseTransform
from mmdet.registry import TRANSFORMS
@TRANSFORMS.register_module()
class MyTransform(BaseTransform):
"""Add your transform
Args:
p (float): Probability of shifts. Default 0.5.
"""
def __init__(self, prob=0.5):
self.prob = prob
def transform(self, results):
if random.random() > self.prob:
results['dummy'] = True
return results
```
2. 在配置文件里调用并使用你写的数据处理流程,需要确保你的训练脚本能够正确导入新增模块:
```python
custom_imports = dict(imports=['path.to.my_pipeline'], allow_failed_imports=False)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True),
dict(type='Resize', scale=(1333, 800), keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(type='MyTransform', prob=0.2),
dict(type='PackDetInputs')
]
```
3. 可视化数据增强处理流程的结果
如果想要可视化数据增强处理流程的结果,可以使用 `tools/misc/browse_dataset.py` 直观
地浏览检测数据集(图像和标注信息),或将图像保存到指定目录。
使用方法请参考[可视化文档](../user_guides/visualization.md)
# 执行引擎(待更新)
# 精度评测(待更新)
本教程收集了任何如何使用 MMDetection 进行 xxx 的答案。 如果您遇到有关`如何做`的问题及答案,请随时更新此文档!
## 使用 MMPretrain 的骨干网络
MMDet、MMPretrain、MMSeg 中的模型注册表都继承自 MMEngine 中的根注册表,允许这些存储库直接使用彼此已经实现的模块。 因此用户可以在 MMDetection 中使用来自 MMPretrain 的骨干网络,而无需实现MMPretrain 中已经存在的网络。
### 使用在 MMPretrain 中实现的骨干网络
假设想将 `MobileNetV3-small` 作为 `RetinaNet` 的骨干网络,则配置文件如下。
```python
_base_ = [
'../_base_/models/retinanet_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
# please install mmpretrain
# import mmpretrain.models to trigger register_module in mmpretrain
custom_imports = dict(imports=['mmpretrain.models'], allow_failed_imports=False)
pretrained = 'https://download.openmmlab.com/mmclassification/v0/mobilenet_v3/convert/mobilenet_v3_small-8427ecf0.pth'
model = dict(
backbone=dict(
_delete_=True, # 将 _base_ 中关于 backbone 的字段删除
type='mmpretrain.MobileNetV3', # 使用 mmpretrain 中的 MobileNetV3
arch='small',
out_indices=(3, 8, 11), # 修改 out_indices
init_cfg=dict(
type='Pretrained',
checkpoint=pretrained,
prefix='backbone.')), # mmpretrain 中骨干网络的预训练权重含义 prefix='backbone.',为了正常加载权重,需要把这个 prefix 去掉。
# 修改 in_channels
neck=dict(in_channels=[24, 48, 96], start_level=0))
```
### 通过 MMPretrain 使用 TIMM 中实现的骨干网络
由于 MMPretrain 提供了 Py**T**orch **Im**age **M**odels (`timm`) 骨干网络的封装,用户也可以通过 MMPretrain 直接使用 `timm` 中的骨干网络。假设想将 [`EfficientNet-B1`](../../../configs/timm_example/retinanet_timm-efficientnet-b1_fpn_1x_coco.py) 作为 `RetinaNet` 的骨干网络,则配置文件如下。
```python
# https://github.com/open-mmlab/mmdetection/blob/main/configs/timm_example/retinanet_timm_efficientnet_b1_fpn_1x_coco.py
_base_ = [
'../_base_/models/retinanet_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
# please install mmpretrain
# import mmpretrain.models to trigger register_module in mmpretrain
custom_imports = dict(imports=['mmpretrain.models'], allow_failed_imports=False)
model = dict(
backbone=dict(
_delete_=True, # 将 _base_ 中关于 backbone 的字段删除
type='mmpretrain.TIMMBackbone', # 使用 mmpretrain 中 timm 骨干网络
model_name='efficientnet_b1',
features_only=True,
pretrained=True,
out_indices=(1, 2, 3, 4)), # 修改 out_indices
neck=dict(in_channels=[24, 40, 112, 320])) # 修改 in_channels
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)
```
`type='mmpretrain.TIMMBackbone'` 表示在 MMDetection 中使用 MMPretrain 中的 `TIMMBackbone` 类,并且使用的模型为` EfficientNet-B1`,其中 `mmpretrain` 表示 MMPretrain 库,而 `TIMMBackbone ` 表示 MMPretrain 中实现的 TIMMBackbone 包装器。
关于层次注册器的具体原理可以参考 [MMEngine 文档](https://mmengine.readthedocs.io/zh_cn/latest/tutorials/config.md#跨项目继承配置文件),关于如何使用 MMPretrain 中的其他 backbone,可以参考 [MMPretrain 文档](https://mmpretrain.readthedocs.io/en/latest/user_guides/config.html)
## 使用马赛克数据增强
如果你想在训练中使用 `Mosaic`,那么请确保你同时使用 `MultiImageMixDataset`。以 `Faster R-CNN` 算法为例,你可以通过如下做法实现:
```python
# 直接打开 configs/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py ,增添如下字段
data_root = 'data/coco/'
dataset_type = 'CocoDataset'
img_scale=(1333, 800)
train_pipeline = [
dict(type='Mosaic', img_scale=img_scale, pad_val=114.0),
dict(
type='RandomAffine',
scaling_ratio_range=(0.1, 2),
border=(-img_scale[0] // 2, -img_scale[1] // 2)), # 图像经过马赛克处理后会放大4倍,所以我们使用仿射变换来恢复图像的大小。
dict(type='RandomFlip', prob=0.5),
dict(type='PackDetInputs'))
]
train_dataset = dict(
_delete_ = True, # 删除不必要的设置
type='MultiImageMixDataset',
dataset=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_train2017.json',
img_prefix=data_root + 'train2017/',
pipeline=[
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True)
],
filter_empty_gt=False,
),
pipeline=train_pipeline
)
data = dict(
train=train_dataset
)
```
## 在配置文件中冻结骨干网络后在训练中解冻骨干网络
如果你在配置文件中已经冻结了骨干网络并希望在几个训练周期后解冻它,你可以通过 hook 来实现这个功能。以用 ResNet 为骨干网络的 Faster R-CNN 为例,你可以冻结一个骨干网络的一个层并在配置文件中添加如下 `custom_hooks`:
```python
_base_ = [
'../_base_/models/faster-rcnn_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
model = dict(
# freeze one stage of the backbone network.
backbone=dict(frozen_stages=1),
)
custom_hooks = [dict(type="UnfreezeBackboneEpochBasedHook", unfreeze_epoch=1)]
```
同时在 `mmdet/core/hook/unfreeze_backbone_epoch_based_hook.py` 当中书写 `UnfreezeBackboneEpochBasedHook`
```python
from mmengine.model import is_model_wrapper
from mmengine.hooks import Hook
from mmdet.registry import HOOKS
@HOOKS.register_module()
class UnfreezeBackboneEpochBasedHook(Hook):
"""Unfreeze backbone network Hook.
Args:
unfreeze_epoch (int): The epoch unfreezing the backbone network.
"""
def __init__(self, unfreeze_epoch=1):
self.unfreeze_epoch = unfreeze_epoch
def before_train_epoch(self, runner):
# Unfreeze the backbone network.
# Only valid for resnet.
if runner.epoch == self.unfreeze_epoch:
model = runner.model
if is_module_wrapper(model):
model = model.module
backbone = model.backbone
if backbone.frozen_stages >= 0:
if backbone.deep_stem:
backbone.stem.train()
for param in backbone.stem.parameters():
param.requires_grad = True
else:
backbone.norm1.train()
for m in [backbone.conv1, backbone.norm1]:
for param in m.parameters():
param.requires_grad = True
for i in range(1, backbone.frozen_stages + 1):
m = getattr(backbone, f'layer{i}')
m.train()
for param in m.parameters():
param.requires_grad = True
```
## 获得新的骨干网络的通道数
如果你想获得一个新骨干网络的通道数,你可以单独构建这个骨干网络并输入一个伪造的图片来获取每一个阶段的输出。
`ResNet` 为例:
```python
from mmdet.models import ResNet
import torch
self = ResNet(depth=18)
self.eval()
inputs = torch.rand(1, 3, 32, 32)
level_outputs = self.forward(inputs)
for level_out in level_outputs:
print(tuple(level_out.shape))
```
以上脚本的输出为:
```python
(1, 64, 8, 8)
(1, 128, 4, 4)
(1, 256, 2, 2)
(1, 512, 1, 1)
```
用户可以通过将脚本中的 `ResNet(depth=18)` 替换为自己的骨干网络配置来得到新的骨干网络的通道数。
# MMDetection 中训练 Detectron2 的模型
用户可以使用 `Detectron2Wrapper` 从而在 MMDetection 中使用 Detectron2 的模型。
我们提供了 [Faster R-CNN](../../../configs/misc/d2_faster-rcnn_r50-caffe_fpn_ms-90k_coco.py),
[Mask R-CNN](../../../configs/misc/d2_mask-rcnn_r50-caffe_fpn_ms-90k_coco.py)[RetinaNet](../../../configs/misc/d2_retinanet_r50-caffe_fpn_ms-90k_coco.py) 的示例来在 MMDetection 中训练/测试 Detectron2 的模型。
使用过程中需要注意配置文件中算法组件要和 Detectron2 中的相同。模型初始化时,我们首先初始化 [Detectron2](https://github.com/facebookresearch/detectron2/blob/main/detectron2/config/defaults.py) 的默认设置,然后配置文件中的设置将覆盖默认设置,模型将基于更新过的设置来建立。
输入数据首先转换成 Detectron2 的类型并输入进 Detectron2 的模型中。在推理阶段,Detectron2 的模型结果将会转换回 MMDetection 的类型。
## 使用 Detectron2 的预训练权重
`Detectron2Wrapper` 中的权重初始化将不使用 MMDetection 的逻辑。用户可以设置 `model.d2_detector.weights=xxx` 来加载预训练的权重。
例如,我们可以使用 `model.d2_detector.weights='detectron2://ImageNetPretrained/MSRA/R-50.pkl'` 来加载 ResNet-50 的预训练权重,或者使用
`model.d2_detector.weights='detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x/137260431/model_final_a54504.pkl'` 来加载 Detectron2 中提出的预训练的Mask R-CNN权重。
**注意:** 不能直接使用 `load_from` 来加载 Detectron2 的预训练模型,但可以通过 `tools/model_converters/detectron2_to_mmdet.py` 先对该预训练模型进行转换。
在测试时,用户应该首先使用 `tools/model_converters/detectron2_to_mmdet.py` 将 Detectron2 的预训练权重转换为 MMDetection 可读取的结构。
```shell
python tools/model_converters/detectron2_to_mmdet.py ${Detectron2 ckpt path} ${MMDetectron ckpt path}
```
基础概念
***************
.. toctree::
:maxdepth: 1
data_flow.md
structures.md
models.md
datasets.md
transforms.md
evaluation.md
engine.md
conventions.md
组件定制
************************
.. toctree::
:maxdepth: 1
customize_models.md
customize_losses.md
customize_dataset.md
customize_transforms.md
customize_runtime.md
How to
************************
.. toctree::
:maxdepth: 1
how_to.md
# 数据结构(待更新)
# 数据变换(待更新)
按照惯例,我们使用 `Dataset``DataLoader` 进行多进程的数据加载。`Dataset` 返回字典类型的数据,数据内容为模型 `forward` 方法的各个参数。由于在目标检测中,输入的图像数据具有不同的大小,我们在 `MMCV` 里引入一个新的 `DataContainer` 类去收集和分发不同大小的输入数据。更多细节请参考[这里](https://github.com/open-mmlab/mmcv/blob/master/mmcv/parallel/data_container.py)
数据的准备流程和数据集是解耦的。通常一个数据集定义了如何处理标注数据(annotations)信息,而一个数据流程定义了准备一个数据字典的所有步骤。一个流程包括一系列的操作,每个操作都把一个字典作为输入,然后再输出一个新的字典给下一个变换操作。
我们在下图展示了一个经典的数据处理流程。蓝色块是数据处理操作,随着数据流程的处理,每个操作都可以在结果字典中加入新的键(标记为绿色)或更新现有的键(标记为橙色)。
![pipeline figure](../../../resources/data_pipeline.png)
这些操作可以分为数据加载(data loading)、预处理(pre-processing)、格式变化(formatting)和测试时数据增强(test-time augmentation)。
下面的例子是 `Faster R-CNN` 的一个流程:
```python
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='LoadAnnotations', with_bbox=True),
dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1333, 800),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
```
mmdet.apis
--------------
.. automodule:: mmdet.apis
:members:
mmdet.datasets
--------------
datasets
^^^^^^^^^^
.. automodule:: mmdet.datasets
:members:
api_wrappers
^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.datasets.api_wrappers
:members:
samplers
^^^^^^^^^^
.. automodule:: mmdet.datasets.samplers
:members:
transforms
^^^^^^^^^^^^
.. automodule:: mmdet.datasets.transforms
:members:
mmdet.engine
--------------
hooks
^^^^^^^^^^
.. automodule:: mmdet.engine.hooks
:members:
optimizers
^^^^^^^^^^^^^^^
.. automodule:: mmdet.engine.optimizers
:members:
runner
^^^^^^^^^^
.. automodule:: mmdet.engine.runner
:members:
schedulers
^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.engine.schedulers
:members:
mmdet.evaluation
--------------------
functional
^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.evaluation.functional
:members:
metrics
^^^^^^^^^^
.. automodule:: mmdet.evaluation.metrics
:members:
mmdet.models
--------------
backbones
^^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.models.backbones
:members:
data_preprocessors
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.models.data_preprocessors
:members:
dense_heads
^^^^^^^^^^^^^^^
.. automodule:: mmdet.models.dense_heads
:members:
detectors
^^^^^^^^^^
.. automodule:: mmdet.models.detectors
:members:
layers
^^^^^^^^^^
.. automodule:: mmdet.models.layers
:members:
losses
^^^^^^^^^^
.. automodule:: mmdet.models.losses
:members:
necks
^^^^^^^^^^^^
.. automodule:: mmdet.models.necks
:members:
roi_heads
^^^^^^^^^^^^^
.. automodule:: mmdet.models.roi_heads
:members:
seg_heads
^^^^^^^^^^^^^
.. automodule:: mmdet.models.seg_heads
:members:
task_modules
^^^^^^^^^^^^^
.. automodule:: mmdet.models.task_modules
:members:
test_time_augs
^^^^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.models.test_time_augs
:members:
utils
^^^^^^^^^^
.. automodule:: mmdet.models.utils
:members:
mmdet.structures
--------------------
structures
^^^^^^^^^^^^^^^^^
.. automodule:: mmdet.structures
:members:
bbox
^^^^^^^^^^
.. automodule:: mmdet.structures.bbox
:members:
mask
^^^^^^^^^^
.. automodule:: mmdet.structures.mask
:members:
mmdet.testing
----------------
.. automodule:: mmdet.testing
:members:
mmdet.visualization
--------------------
.. automodule:: mmdet.visualization
:members:
mmdet.utils
--------------
.. automodule:: mmdet.utils
:members:
## 中文解读文案汇总(待更新)
### 1 官方解读文案(v2.x)
#### 1.1 框架解读
- **[轻松掌握 MMDetection 整体构建流程(一)](https://zhuanlan.zhihu.com/p/337375549)**
- **[轻松掌握 MMDetection 整体构建流程(二)](https://zhuanlan.zhihu.com/p/341954021)**
- **[轻松掌握 MMDetection 中 Head 流程](https://zhuanlan.zhihu.com/p/343433169)**
#### 1.2 算法解读
- **[轻松掌握 MMDetection 中常用算法(一):RetinaNet 及配置详解](https://zhuanlan.zhihu.com/p/346198300)**
- **[轻松掌握 MMDetection 中常用算法(二):Faster R-CNN|Mask R-CNN](https://zhuanlan.zhihu.com/p/349807581)**
- [轻松掌握 MMDetection 中常用算法(三):FCOS](https://zhuanlan.zhihu.com/p/358056615)
- [轻松掌握 MMDetection 中常用算法(四):ATSS](https://zhuanlan.zhihu.com/p/358125611)
- [轻松掌握 MMDetection 中常用算法(五):Cascade R-CNN](https://zhuanlan.zhihu.com/p/360952172)
- [轻松掌握 MMDetection 中常用算法(六):YOLOF](https://zhuanlan.zhihu.com/p/370758213)
- [轻松掌握 MMDetection 中常用算法(七):CenterNet](https://zhuanlan.zhihu.com/p/374891478)
- [轻松掌握 MMDetection 中常用算法(八):YOLACT](https://zhuanlan.zhihu.com/p/376347955)
- [轻松掌握 MMDetection 中常用算法(九):AutoAssign](https://zhuanlan.zhihu.com/p/378581552)
- [YOLOX 在 MMDetection 中复现全流程解析](https://zhuanlan.zhihu.com/p/398545304)
- [喂喂喂!你可以减重了!小模型 - MMDetection 新增SSDLite 、 MobileNetV2YOLOV3 两大经典算法](https://zhuanlan.zhihu.com/p/402781143)
#### 1.3 工具解读
- [OpenMMLab 中混合精度训练 AMP 的正确打开方式](https://zhuanlan.zhihu.com/p/375224982)
- [小白都能看懂!手把手教你使用混淆矩阵分析目标检测](https://zhuanlan.zhihu.com/p/443499860)
- [MMDetection 图像缩放 Resize 详细说明 OpenMMLab](https://zhuanlan.zhihu.com/p/381117525)
- [拿什么拯救我的 4G 显卡](https://zhuanlan.zhihu.com/p/430123077)
- [MMDet居然能用MMCls的Backbone?论配置文件的打开方式](https://zhuanlan.zhihu.com/p/436865195)
#### 1.4 知乎问答
- [COCO数据集上1x模式下为什么不采用多尺度训练?](https://www.zhihu.com/question/462170786/answer/1915119662)
- [MMDetection中SOTA论文源码中将训练过程中BN层的eval打开?](https://www.zhihu.com/question/471189603/answer/2195540892)
- [基于PyTorch的MMDetection中训练的随机性来自何处?](https://www.zhihu.com/question/453511684/answer/1839683634)
- [单阶段、双阶段、anchor-based、anchor-free 这四者之间有什么联系吗?](https://www.zhihu.com/question/428972054/answer/1619925296)
- [目标检测的深度学习方法,有推荐的书籍或资料吗?](https://www.zhihu.com/question/391577080/answer/1612593817)
- [大佬们,刚入学研究生,想入门目标检测,有什么学习路线可以入门的?](https://www.zhihu.com/question/343768934/answer/1612580715)
- [目标检测领域还有什么可以做的?](https://www.zhihu.com/question/280703314/answer/1627885518)
- [如何看待Transformer在CV上的应用前景,未来有可能替代CNN吗?](https://www.zhihu.com/question/437495132/answer/1686380553)
- [MMDetection如何学习源码?](https://www.zhihu.com/question/451585041/answer/1832498963)
- [如何具体上手实现目标检测呢?](https://www.zhihu.com/question/341401981/answer/1848561187)
#### 1.5 其他
- **[不得不知的 MMDetection 学习路线(个人经验版)](https://zhuanlan.zhihu.com/p/369826931)**
- [OpenMMLab 社区专访之 YOLOX 复现篇](https://zhuanlan.zhihu.com/p/405913343)
### 2 社区解读文案(v2.x)
- [手把手带你实现经典检测网络 Mask R-CNN 的推理](https://zhuanlan.zhihu.com/p/414082071)
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import subprocess
import sys
import pytorch_sphinx_theme
sys.path.insert(0, os.path.abspath('../../'))
# -- Project information -----------------------------------------------------
project = 'MMDetection'
copyright = '2018-2021, OpenMMLab'
author = 'MMDetection Authors'
version_file = '../../mmdet/version.py'
def get_version():
with open(version_file, 'r') as f:
exec(compile(f.read(), version_file, 'exec'))
return locals()['__version__']
# The full version, including alpha/beta/rc tags
release = get_version()
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode',
'myst_parser',
'sphinx_markdown_tables',
'sphinx_copybutton',
]
myst_enable_extensions = ['colon_fence']
myst_heading_anchors = 3
autodoc_mock_imports = [
'matplotlib', 'pycocotools', 'terminaltables', 'mmdet.version', 'mmcv.ops'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
# The main toctree document.
master_doc = 'index'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
# html_theme = 'sphinx_rtd_theme'
html_theme = 'pytorch_sphinx_theme'
html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()]
html_theme_options = {
'menu': [
{
'name': 'GitHub',
'url': 'https://github.com/open-mmlab/mmdetection'
},
],
# Specify the language of shared menu
'menu_lang':
'cn',
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = ['css/readthedocs.css']
language = 'zh_CN'
# -- Extension configuration -------------------------------------------------
# Ignore >>> when copying code
copybutton_prompt_text = r'>>> |\.\.\. '
copybutton_prompt_is_regexp = True
def builder_inited_handler(app):
subprocess.run(['./stat.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)
# 开始你的第一步
## 依赖
本节中,我们将演示如何用 PyTorch 准备一个环境。
MMDetection 支持在 Linux,Windows 和 macOS 上运行。它需要 Python 3.7 以上,CUDA 9.2 以上和 PyTorch 1.8 及其以上。
```{note}
如果你对 PyTorch 有经验并且已经安装了它,你可以直接跳转到[下一小节](#安装流程)。否则,你可以按照下述步骤进行准备。
```
**步骤 0.**[官方网站](https://docs.conda.io/en/latest/miniconda.html)下载并安装 Miniconda。
**步骤 1.** 创建并激活一个 conda 环境。
```shell
conda create --name openmmlab python=3.8 -y
conda activate openmmlab
```
**步骤 2.** 基于 [PyTorch 官方说明](https://pytorch.org/get-started/locally/)安装 PyTorch。
在 GPU 平台上:
```shell
conda install pytorch torchvision -c pytorch
```
在 CPU 平台上:
```shell
conda install pytorch torchvision cpuonly -c pytorch
```
## 安装流程
我们推荐用户参照我们的最佳实践安装 MMDetection。不过,整个过程也是可定制化的,更多信息请参考[自定义安装](#自定义安装)章节。
### 最佳实践
**步骤 0.** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMEngine](https://github.com/open-mmlab/mmengine)[MMCV](https://github.com/open-mmlab/mmcv)
```shell
pip install -U openmim
mim install mmengine
mim install "mmcv>=2.0.0"
```
**注意:** 在 MMCV-v2.x 中,`mmcv-full` 改名为 `mmcv`,如果你想安装不包含 CUDA 算子精简版,可以通过 `mim install "mmcv-lite>=2.0.0rc1"` 来安装。
**步骤 1.** 安装 MMDetection。
方案 a:如果你开发并直接运行 mmdet,从源码安装它:
```shell
git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -v -e .
# "-v" 指详细说明,或更多的输出
# "-e" 表示在可编辑模式下安装项目,因此对代码所做的任何本地修改都会生效,从而无需重新安装。
```
方案 b:如果你将 mmdet 作为依赖或第三方 Python 包,使用 MIM 安装:
```shell
mim install mmdet
```
## 验证安装
为了验证 MMDetection 是否安装正确,我们提供了一些示例代码来执行模型推理。
**步骤 1.** 我们需要下载配置文件和模型权重文件。
```shell
mim download mmdet --config rtmdet_tiny_8xb32-300e_coco --dest .
```
下载将需要几秒钟或更长时间,这取决于你的网络环境。完成后,你会在当前文件夹中发现两个文件 `rtmdet_tiny_8xb32-300e_coco.py``rtmdet_tiny_8xb32-300e_coco_20220902_112414-78e30dcc.pth`
**步骤 2.** 推理验证。
方案 a:如果你通过源码安装的 MMDetection,那么直接运行以下命令进行验证:
```shell
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
```
你会在当前文件夹中的 `outputs/vis` 文件夹中看到一个新的图像 `demo.jpg`,图像中包含有网络预测的检测框。
方案 b:如果你通过 MIM 安装的 MMDetection,那么可以打开你的 Python 解析器,复制并粘贴以下代码:
```python
from mmdet.apis import init_detector, inference_detector
config_file = 'rtmdet_tiny_8xb32-300e_coco.py'
checkpoint_file = 'rtmdet_tiny_8xb32-300e_coco_20220902_112414-78e30dcc.pth'
model = init_detector(config_file, checkpoint_file, device='cpu') # or device='cuda:0'
inference_detector(model, 'demo/demo.jpg')
```
你将会看到一个包含 `DetDataSample` 的列表,预测结果在 `pred_instance` 里,包含有检测框,类别和得分。
### 自定义安装
#### CUDA 版本
在安装 PyTorch 时,你需要指定 CUDA 的版本。如果你不清楚应该选择哪一个,请遵循我们的建议:
- 对于 Ampere 架构的 NVIDIA GPU,例如 GeForce 30 系列以及 NVIDIA A100,CUDA 11 是必需的。
- 对于更早的 NVIDIA GPU,CUDA 11 是向后兼容 (backward compatible) 的,但 CUDA 10.2 能够提供更好的兼容性,也更加轻量。
请确保你的 GPU 驱动版本满足最低的版本需求,参阅 NVIDIA 官方的 [CUDA 工具箱和相应的驱动版本关系表](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-major-component-versions__table-cuda-toolkit-driver-versions)
```{note}
如果按照我们的最佳实践,安装 CUDA 运行时库就足够了,这是因为不需要在本地编译 CUDA 代码。但如果你希望从源码编译 MMCV,或是开发其他 CUDA 算子,那么就必须安装完整的 CUDA 工具链,参见 [NVIDIA 官网](https://developer.nvidia.com/cuda-downloads),另外还需要确保该 CUDA 工具链的版本与 PyTorch 安装时的配置相匹配(如用 `conda install` 安装 PyTorch 时指定的 cudatoolkit 版本)。
```
#### 不使用 MIM 安装 MMEngine
要使用 pip 而不是 MIM 来安装 MMEngine,请遵照 [MMEngine 安装指南](https://mmengine.readthedocs.io/zh_CN/latest/get_started/installation.html)
例如,你可以通过以下命令安装 MMEngine。
```shell
pip install mmengine
```
#### 不使用 MIM 安装 MMCV
MMCV 包含 C++ 和 CUDA 扩展,因此其对 PyTorch 的依赖比较复杂。MIM 会自动解析这些依赖,选择合适的 MMCV 预编译包,使安装更简单,但它并不是必需的。
要使用 pip 而不是 MIM 来安装 MMCV,请遵照 [MMCV 安装指南](https://mmcv.readthedocs.io/zh_CN/2.x/get_started/installation.html)。它需要您用指定 url 的形式手动指定对应的 PyTorch 和 CUDA 版本。
例如,下述命令将会安装基于 PyTorch 1.12.x 和 CUDA 11.6 编译的 MMCV。
```shell
pip install "mmcv>=2.0.0" -f https://download.openmmlab.com/mmcv/dist/cu116/torch1.12.0/index.html
```
#### 在 CPU 环境中安装
MMDetection 可以在 CPU 环境中构建。在 CPU 模式下,可以进行模型训练(需要 MMCV 版本 >= 2.0.0rc1)、测试或者推理。
但是,以下功能在该模式下不能使用:
- Deformable Convolution
- Modulated Deformable Convolution
- ROI pooling
- Deformable ROI pooling
- CARAFE
- SyncBatchNorm
- CrissCrossAttention
- MaskedConv2d
- Temporal Interlace Shift
- nms_cuda
- sigmoid_focal_loss_cuda
- bbox_overlaps
因此,如果尝试训练/测试/推理包含上述算子的模型,将会报错。下表列出了将会受影响的相关算法。
| 操作 | 模型 |
| :-----------------------------------------------------: | :--------------------------------------------------------------------------------------: |
| Deformable Convolution/Modulated Deformable Convolution | DCN、Guided Anchoring、RepPoints、CentripetalNet、VFNet、CascadeRPN、NAS-FCOS、DetectoRS |
| MaskedConv2d | Guided Anchoring |
| CARAFE | CARAFE |
| SyncBatchNorm | ResNeSt |
#### 在 Google Colab 中安装
[Google Colab](https://colab.research.google.com/) 通常已经包含了 PyTorch 环境,因此我们只需要安装 MMEngine,MMCV 和 MMDetection 即可,命令如下:
**步骤 1.** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMEngine](https://github.com/open-mmlab/mmengine)[MMCV](https://github.com/open-mmlab/mmcv)
```shell
!pip3 install openmim
!mim install mmengine
!mim install "mmcv>=2.0.0,<2.1.0"
```
**步骤 2.** 使用源码安装 MMDetection。
```shell
!git clone https://github.com/open-mmlab/mmdetection.git
%cd mmdetection
!pip install -e .
```
**步骤 3.** 验证安装是否成功。
```python
import mmdet
print(mmdet.__version__)
# 预期输出:3.0.0 或其他版本号
```
```{note}
在 Jupyter Notebook 中,感叹号 `!` 用于执行外部命令,而 `%cd` 是一个[魔术命令](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-cd),用于切换 Python 的工作路径。
```
#### 通过 Docker 使用 MMDetection
我们提供了一个 [Dockerfile](../../docker/Dockerfile) 来构建一个镜像。请确保你的 [docker 版本](https://docs.docker.com/engine/install/) >=19.03。
```shell
# 基于 PyTorch 1.9,CUDA 11.1 构建镜像
# 如果你想要其他版本,只需要修改 Dockerfile
docker build -t mmdetection docker/
```
用以下命令运行 Docker 镜像:
```shell
docker run --gpus all --shm-size=8g -it -v {DATA_DIR}:/mmdetection/data mmdetection
```
### 排除故障
如果你在安装过程中遇到一些问题,请先查看 [FAQ](notes/faq.md) 页面。如果没有找到解决方案,你也可以在 GitHub 上[提出一个问题](https://github.com/open-mmlab/mmdetection/issues/new/choose)
### 使用多个 MMDetection 版本进行开发
训练和测试的脚本已经在 `PYTHONPATH` 中进行了修改,以确保脚本使用当前目录中的 MMDetection。
要使环境中安装默认版本的 MMDetection 而不是当前正在使用的,可以删除出现在相关脚本中的代码:
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
Welcome to MMDetection's documentation!
=======================================
.. toctree::
:maxdepth: 1
:caption: 开始你的第一步
overview.md
get_started.md
.. toctree::
:maxdepth: 2
:caption: 使用指南
user_guides/index.rst
.. toctree::
:maxdepth: 2
:caption: 进阶教程
advanced_guides/index.rst
.. toctree::
:maxdepth: 1
:caption: 迁移版本
migration/migration.md
.. toctree::
:maxdepth: 1
:caption: 接口文档(英文)
api.rst
.. toctree::
:maxdepth: 1
:caption: 模型仓库
model_zoo.md
.. toctree::
:maxdepth: 1
:caption: 说明
notes/contribution_guide.md
notes/projects.md
notes/faq.md
notes/compatibility.md
.. toctree::
:maxdepth: 1
:caption: 文章
article.md
.. toctree::
:caption: 语言切换
switch_language.md
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
# 将 API 和注册器从 MMDetection 2.x 迁移至 3.x
# 将配置文件从 MMDetection 2.x 迁移至 3.x
MMDetection 3.x 的配置文件与 2.x 相比有较大变化,这篇文档将介绍如何将 2.x 的配置文件迁移到 3.x。
在前面的[配置文件教程](../user_guides/config.md)中,我们以 Mask R-CNN 为例介绍了 MMDetection 3.x 的配置文件结构,这里我们将按同样的结构介绍如何将 2.x 的配置文件迁移至 3.x。
## 模型配置
模型的配置与 2.x 相比并没有太大变化,对于模型的 backbone,neck,head,以及 train_cfg 和 test_cfg,它们的参数与 2.x 版本的参数保持一致。
不同的是,我们在 3.x 版本的模型中新增了 `DataPreprocessor` 模块。
`DataPreprocessor` 模块的配置位于 `model.data_preprocessor` 中,它用于对输入数据进行预处理,例如对输入图像进行归一化,将不同大小的图片进行 padding 从而组成 batch,将图像从内存中读取到显存中等。这部分配置取代了原本存在于 train_pipeline 和 test_pipeline 中的 `Normalize``Pad`
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
# 图像归一化参数
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
to_rgb=True)
pipeline=[
...,
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32), # 图像 padding 到 32 的倍数
...
]
```
</td>
<tr>
<td>新配置</td>
<td>
```python
model = dict(
data_preprocessor=dict(
type='DetDataPreprocessor',
# 图像归一化参数
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
bgr_to_rgb=True,
# 图像 padding 参数
pad_mask=True, # 在实例分割中,需要将 mask 也进行 padding
pad_size_divisor=32) # 图像 padding 到 32 的倍数
)
```
</td>
</tr>
</table>
## 数据集和评测器配置
数据集和评测部分的配置相比 2.x 版本有较大的变化。我们将从 Dataloader 和 Dataset,Data transform pipeline,以及评测器配置三个方面介绍如何将 2.x 版本的配置迁移到 3.x 版本。
### Dataloader 和 Dataset 配置
在新版本中,我们将数据加载的设置与 PyTorch 官方的 DataLoader 保持一致,这样可以使用户更容易理解和上手。
我们将训练、验证和测试的数据加载设置分别放在 `train_dataloader``val_dataloader``test_dataloader` 中,用户可以分别对这些 dataloader 设置不同的参数,其输入参数与 [PyTorch 的 Dataloader](https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader) 所需要的参数基本一致。
通过这种方式,我们将 2.x 版本中不可配置的 `sampler``batch_sampler``persistent_workers` 等参数都放到了配置文件中,使得用户可以更加灵活地设置数据加载的参数。
用户可以通过 `train_dataloader.dataset``val_dataloader.dataset``test_dataloader.dataset` 来设置数据集的配置,它们分别对应 2.x 版本中的 `data.train``data.val``data.test`
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
data = dict(
samples_per_gpu=2,
workers_per_gpu=2,
train=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_train2017.json',
img_prefix=data_root + 'train2017/',
pipeline=train_pipeline),
val=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_val2017.json',
img_prefix=data_root + 'val2017/',
pipeline=test_pipeline),
test=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_val2017.json',
img_prefix=data_root + 'val2017/',
pipeline=test_pipeline))
```
</td>
<tr>
<td>新配置</td>
<td>
```python
train_dataloader = dict(
batch_size=2,
num_workers=2,
persistent_workers=True, # 避免每次迭代后 dataloader 重新创建子进程
sampler=dict(type='DefaultSampler', shuffle=True), # 默认的 sampler,同时支持分布式训练和非分布式训练
batch_sampler=dict(type='AspectRatioBatchSampler'), # 默认的 batch_sampler,用于保证 batch 中的图片具有相似的长宽比,从而可以更好地利用显存
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=True, min_size=32),
pipeline=train_pipeline))
# 在 3.x 版本中可以独立配置验证和测试的 dataloader
val_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='annotations/instances_val2017.json',
data_prefix=dict(img='val2017/'),
test_mode=True,
pipeline=test_pipeline))
test_dataloader = val_dataloader # 测试 dataloader 的配置与验证 dataloader 的配置相同,这里省略
```
</td>
</tr>
</table>
### Data transform pipeline 配置
上文中提到,我们将图像 normalize 和 padding 的配置从 `train_pipeline``test_pipeline` 中独立出来,放到了 `model.data_preprocessor` 中,因此在 3.x 版本的 pipeline 中,我们不再需要 `Normalize``Pad` 这两个 transform。
同时,我们也对负责数据格式打包的 transform 进行了重构,将 `Collect``DefaultFormatBundle` 这两个 transform 合并为了 `PackDetInputs`,它负责将 data pipeline 中的数据打包成模型的输入格式,关于输入格式的转换,详见[数据流文档](../advanced_guides/data_flow.md)
下面以 Mask R-CNN 1x 的 train_pipeline 为例,介绍如何将 2.x 版本的配置迁移到 3.x 版本:
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
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='LoadAnnotations', with_bbox=True),
dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
]
```
</td>
<tr>
<td>新配置</td>
<td>
```python
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True),
dict(type='Resize', scale=(1333, 800), keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(type='PackDetInputs')
]
```
</td>
</tr>
</table>
对于 test_pipeline,除了将 `Normalize``Pad` 这两个 transform 去掉之外,我们也将测试时的数据增强(TTA)与普通的测试流程分开,移除了 `MultiScaleFlipAug`。关于新版的 TTA 如何使用,详见[TTA 文档](../advanced_guides/tta.md)
下面同样以 Mask R-CNN 1x 的 test_pipeline 为例,介绍如何将 2.x 版本的配置迁移到 3.x 版本:
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1333, 800),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
```
</td>
<tr>
<td>新配置</td>
<td>
```python
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', scale=(1333, 800), keep_ratio=True),
dict(
type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor'))
]
```
</td>
</tr>
</table>
除此之外,我们还对一些数据增强进行了重构,下表列出了 2.x 版本中的 transform 与 3.x 版本中的 transform 的对应关系:
<table class="docutils">
<thead>
<tr>
<th>名称</th>
<th>原配置</th>
<th>新配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>Resize</td>
<td>
```python
dict(type='Resize',
img_scale=(1333, 800),
keep_ratio=True)
```
</td>
<td>
```python
dict(type='Resize',
scale=(1333, 800),
keep_ratio=True)
```
</td>
</tr>
<tr>
<td>RandomResize</td>
<td>
```python
dict(
type='Resize',
img_scale=[
(1333, 640), (1333, 800)],
multiscale_mode='range',
keep_ratio=True)
```
</td>
<td>
```python
dict(
type='RandomResize',
scale=[
(1333, 640), (1333, 800)],
keep_ratio=True)
```
</td>
</tr>
<tr>
<td>RandomChoiceResize</td>
<td>
```python
dict(
type='Resize',
img_scale=[
(1333, 640), (1333, 672),
(1333, 704), (1333, 736),
(1333, 768), (1333, 800)],
multiscale_mode='value',
keep_ratio=True)
```
</td>
<td>
```python
dict(
type='RandomChoiceResize',
scales=[
(1333, 640), (1333, 672),
(1333, 704), (1333, 736),
(1333, 768), (1333, 800)],
keep_ratio=True)
```
</td>
</tr>
<tr>
<td>RandomFlip</td>
<td>
```python
dict(type='RandomFlip',
flip_ratio=0.5)
```
</td>
<td>
```python
dict(type='RandomFlip',
prob=0.5)
```
</td>
</tr>
</tbody>
</table>
### 评测器配置
在 3.x 版本中,模型精度评测不再与数据集绑定,而是通过评测器(Evaluator)来完成。
评测器配置分为 val_evaluator 和 test_evaluator 两部分,其中 val_evaluator 用于验证集评测,test_evaluator 用于测试集评测,对应 2.x 版本中的 evaluation 字段。
下表列出了 2.x 版本与 3.x 版本中的评测器的对应关系:
<table class="docutils">
<thead>
<tr>
<th>评测指标名称</th>
<th>原配置</th>
<th>新配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>COCO</td>
<td>
```python
data = dict(
val=dict(
type='CocoDataset',
ann_file=data_root + 'annotations/instances_val2017.json'))
evaluation = dict(metric=['bbox', 'segm'])
```
</td>
<td>
```python
val_evaluator = dict(
type='CocoMetric',
ann_file=data_root + 'annotations/instances_val2017.json',
metric=['bbox', 'segm'],
format_only=False)
```
</td>
</tr>
<tr>
<td>Pascal VOC</td>
<td>
```python
data = dict(
val=dict(
type=dataset_type,
ann_file=data_root + 'VOC2007/ImageSets/Main/test.txt'))
evaluation = dict(metric='mAP')
```
</td>
<td>
```python
val_evaluator = dict(
type='VOCMetric',
metric='mAP',
eval_mode='11points')
```
</td>
</tr>
<tr>
<td>OpenImages</td>
<td>
```python
data = dict(
val=dict(
type='OpenImagesDataset',
ann_file=data_root + 'annotations/validation-annotations-bbox.csv',
img_prefix=data_root + 'OpenImages/validation/',
label_file=data_root + 'annotations/class-descriptions-boxable.csv',
hierarchy_file=data_root +
'annotations/bbox_labels_600_hierarchy.json',
meta_file=data_root + 'annotations/validation-image-metas.pkl',
image_level_ann_file=data_root +
'annotations/validation-annotations-human-imagelabels-boxable.csv'))
evaluation = dict(interval=1, metric='mAP')
```
</td>
<td>
```python
val_evaluator = dict(
type='OpenImagesMetric',
iou_thrs=0.5,
ioa_thrs=0.5,
use_group_of=True,
get_supercategory=True)
```
</td>
</tr>
<tr>
<td>CityScapes</td>
<td>
```python
data = dict(
val=dict(
type='CityScapesDataset',
ann_file=data_root +
'annotations/instancesonly_filtered_gtFine_val.json',
img_prefix=data_root + 'leftImg8bit/val/',
pipeline=test_pipeline))
evaluation = dict(metric=['bbox', 'segm'])
```
</td>
<td>
```python
val_evaluator = [
dict(
type='CocoMetric',
ann_file=data_root +
'annotations/instancesonly_filtered_gtFine_val.json',
metric=['bbox', 'segm']),
dict(
type='CityScapesMetric',
ann_file=data_root +
'annotations/instancesonly_filtered_gtFine_val.json',
seg_prefix=data_root + '/gtFine/val',
outfile_prefix='./work_dirs/cityscapes_metric/instance')
]
```
</td>
</tr>
</tbody>
</table>
## 训练和测试的配置
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
runner = dict(
type='EpochBasedRunner', # 训练循环的类型
max_epochs=12) # 最大训练轮次
evaluation = dict(interval=2) # 验证间隔。每 2 个 epoch 验证一次
```
</td>
<tr>
<td>新配置</td>
<td>
```python
train_cfg = dict(
type='EpochBasedTrainLoop', # 训练循环的类型,请参考 https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py
max_epochs=12, # 最大训练轮次
val_interval=2) # 验证间隔。每 2 个 epoch 验证一次
val_cfg = dict(type='ValLoop') # 验证循环的类型
test_cfg = dict(type='TestLoop') # 测试循环的类型
```
</td>
</tr>
</table>
## 优化相关配置
优化器以及梯度裁剪的配置都移至 optim_wrapper 字段中。下表列出了 2.x 版本与 3.x 版本中的优化器配置的对应关系:
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
optimizer = dict(
type='SGD', # 随机梯度下降优化器
lr=0.02, # 基础学习率
momentum=0.9, # 带动量的随机梯度下降
weight_decay=0.0001) # 权重衰减
optimizer_config = dict(grad_clip=None) # 梯度裁剪的配置,设置为 None 关闭梯度裁剪
```
</td>
<tr>
<td>新配置</td>
<td>
```python
optim_wrapper = dict( # 优化器封装的配置
type='OptimWrapper', # 优化器封装的类型。可以切换至 AmpOptimWrapper 来启用混合精度训练
optimizer=dict( # 优化器配置。支持 PyTorch 的各种优化器。请参考 https://pytorch.org/docs/stable/optim.html#algorithms
type='SGD', # 随机梯度下降优化器
lr=0.02, # 基础学习率
momentum=0.9, # 带动量的随机梯度下降
weight_decay=0.0001), # 权重衰减
clip_grad=None, # 梯度裁剪的配置,设置为 None 关闭梯度裁剪。使用方法请见 https://mmengine.readthedocs.io/en/latest/tutorials/optimizer.html
)
```
</td>
</tr>
</table>
学习率的配置也从 lr_config 字段中移至 param_scheduler 字段中。param_scheduler 的配置更贴近 PyTorch 的学习率调整策略,更加灵活。下表列出了 2.x 版本与 3.x 版本中的学习率配置的对应关系:
<table class="docutils">
<tr>
<td>原配置</td>
<td>
```python
lr_config = dict(
policy='step', # 在训练过程中使用 multi step 学习率策略
warmup='linear', # 使用线性学习率预热
warmup_iters=500, # 到第 500 个 iteration 结束预热
warmup_ratio=0.001, # 学习率预热的系数
step=[8, 11], # 在哪几个 epoch 进行学习率衰减
gamma=0.1) # 学习率衰减系数
```
</td>
<tr>
<td>新配置</td>
<td>
```python
param_scheduler = [
dict(
type='LinearLR', # 使用线性学习率预热
start_factor=0.001, # 学习率预热的系数
by_epoch=False, # 按 iteration 更新预热学习率
begin=0, # 从第一个 iteration 开始
end=500), # 到第 500 个 iteration 结束
dict(
type='MultiStepLR', # 在训练过程中使用 multi step 学习率策略
by_epoch=True, # 按 epoch 更新学习率
begin=0, # 从第一个 epoch 开始
end=12, # 到第 12 个 epoch 结束
milestones=[8, 11], # 在哪几个 epoch 进行学习率衰减
gamma=0.1) # 学习率衰减系数
]
```
</td>
</tr>
</table>
关于其他的学习率调整策略的迁移,请参考 MMEngine 的[学习率迁移文档](https://mmengine.readthedocs.io/zh_CN/latest/migration/param_scheduler.html)
## 其他配置的迁移
### 保存 checkpoint 的配置
<table class="docutils">
<thead>
<tr>
<th>功能</th>
<th>原配置</th>
<th>新配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>设置保存间隔</td>
<td>
```python
checkpoint_config = dict(
interval=1)
```
</td>
<td>
```python
default_hooks = dict(
checkpoint=dict(
type='CheckpointHook',
interval=1))
```
</td>
</tr>
<tr>
<td>保存最佳模型</td>
<td>
```python
evaluation = dict(
save_best='auto')
```
</td>
<td>
```python
default_hooks = dict(
checkpoint=dict(
type='CheckpointHook',
save_best='auto'))
```
</td>
</tr>
<tr>
<td>只保留最新的几个模型</td>
<td>
```python
checkpoint_config = dict(
max_keep_ckpts=3)
```
</td>
<td>
```python
default_hooks = dict(
checkpoint=dict(
type='CheckpointHook',
max_keep_ckpts=3))
```
</td>
</tr>
</tbody>
</table>
### 日志的配置
3.x 版本中,日志的打印和可视化由 MMEngine 中的 logger 和 visualizer 分别完成。下表列出了 2.x 版本与 3.x 版本中的日志配置的对应关系:
<table class="docutils">
<thead>
<tr>
<th>功能</th>
<th>原配置</th>
<th>新配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>设置日志打印间隔</td>
<td>
```python
log_config = dict(
interval=50)
```
</td>
<td>
```python
default_hooks = dict(
logger=dict(
type='LoggerHook',
interval=50))
# 可选: 配置日志打印数值的平滑窗口大小
log_processor = dict(
type='LogProcessor',
window_size=50)
```
</td>
</tr>
<tr>
<td>使用 TensorBoard 或 WandB 可视化日志</td>
<td>
```python
log_config = dict(
interval=50,
hooks=[
dict(type='TextLoggerHook'),
dict(type='TensorboardLoggerHook'),
dict(type='MMDetWandbHook',
init_kwargs={
'project': 'mmdetection',
'group': 'maskrcnn-r50-fpn-1x-coco'
},
interval=50,
log_checkpoint=True,
log_checkpoint_metadata=True,
num_eval_images=100)
])
```
</td>
<td>
```python
vis_backends = [
dict(type='LocalVisBackend'),
dict(type='TensorboardVisBackend'),
dict(type='WandbVisBackend',
init_kwargs={
'project': 'mmdetection',
'group': 'maskrcnn-r50-fpn-1x-coco'
})
]
visualizer = dict(
type='DetLocalVisualizer', vis_backends=vis_backends, name='visualizer')
```
</td>
</tr>
</tbody>
</table>
关于可视化相关的教程,请参考 MMDetection 的[可视化教程](../user_guides/visualization.md)
### Runtime 的配置
3.x 版本中 runtime 的配置字段有所调整,具体的对应关系如下:
<table class="docutils">
<thead>
<tr>
<th>原配置</th>
<th>新配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>
```python
cudnn_benchmark = False
opencv_num_threads = 0
mp_start_method = 'fork'
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
```
</td>
<td>
```python
env_cfg = dict(
cudnn_benchmark=False,
mp_cfg=dict(mp_start_method='fork',
opencv_num_threads=0),
dist_cfg=dict(backend='nccl'))
log_level = 'INFO'
load_from = None
resume = False
```
</td>
</tr>
</tbody>
</table>
# 将数据集从 MMDetection 2.x 迁移至 3.x
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment