Commit baf20b93 authored by dlyrm's avatar dlyrm
Browse files

update yolox

parent ec3f5448
Pipeline #679 canceled with stages
#!/usr/bin/env python
import functools as func
import glob
import os.path as osp
import re
import numpy as np
url_prefix = 'https://github.com/open-mmlab/mmdetection/blob/main/'
files = sorted(glob.glob('../configs/*/README.md'))
stats = []
titles = []
num_ckpts = 0
for f in files:
url = osp.dirname(f.replace('../', url_prefix))
with open(f, 'r') as content_file:
content = content_file.read()
title = content.split('\n')[0].replace('# ', '').strip()
ckpts = set(x.lower().strip()
for x in re.findall(r'\[model\]\((https?.*)\)', content))
if len(ckpts) == 0:
continue
_papertype = [x for x in re.findall(r'\[([A-Z]+)\]', content)]
assert len(_papertype) > 0
papertype = _papertype[0]
paper = set([(papertype, title)])
titles.append(title)
num_ckpts += len(ckpts)
statsmsg = f"""
\t* [{papertype}] [{title}]({url}) ({len(ckpts)} ckpts)
"""
stats.append((paper, ckpts, statsmsg))
allpapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _ in stats])
msglist = '\n'.join(x for _, _, x in stats)
papertypes, papercounts = np.unique([t for t, _ in allpapers],
return_counts=True)
countstr = '\n'.join(
[f' - {t}: {c}' for t, c in zip(papertypes, papercounts)])
modelzoo = f"""
# Model Zoo Statistics
* Number of papers: {len(set(titles))}
{countstr}
* Number of checkpoints: {num_ckpts}
{msglist}
"""
with open('modelzoo_statistics.md', 'w') as f:
f.write(modelzoo)
## <a href='https://mmdetection.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmdetection.readthedocs.io/zh_CN/latest/'>简体中文</a>
# 学习配置文件
MMDetection 和其他 OpenMMLab 仓库使用 [MMEngine 的配置文件系统](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)。 配置文件使用了模块化和继承设计,以便于进行各类实验。
## 配置文件的内容
MMDetection 采用模块化设计,所有功能的模块都可以通过配置文件进行配置。 以 Mask R-CNN 为例,我们将根据不同的功能模块介绍配置文件中的各个字段:
### 模型配置
在 mmdetection 的配置中,我们使用 `model` 字段来配置检测算法的组件。 除了 `backbone``neck` 等神经网络组件外,还需要 `data_preprocessor``train_cfg``test_cfg``data_preprocessor` 负责对 dataloader 输出的每一批数据进行预处理。 模型配置中的 `train_cfg``test_cfg` 用于设置训练和测试组件的超参数。
```python
model = dict(
type='MaskRCNN', # 检测器名
data_preprocessor=dict( # 数据预处理器的配置,通常包括图像归一化和 padding
type='DetDataPreprocessor', # 数据预处理器的类型,参考 https://mmdetection.readthedocs.io/en/latest/api.html#mmdet.models.data_preprocessors.DetDataPreprocessor
mean=[123.675, 116.28, 103.53], # 用于预训练骨干网络的图像归一化通道均值,按 R、G、B 排序
std=[58.395, 57.12, 57.375], # 用于预训练骨干网络的图像归一化通道标准差,按 R、G、B 排序
bgr_to_rgb=True, # 是否将图片通道从 BGR 转为 RGB
pad_mask=True, # 是否填充实例分割掩码
pad_size_divisor=32), # padding 后的图像的大小应该可以被 ``pad_size_divisor`` 整除
backbone=dict( # 主干网络的配置文件
type='ResNet', # 主干网络的类别,可用选项请参考 https://mmdetection.readthedocs.io/en/latest/api.html#mmdet.models.backbones.ResNet
depth=50, # 主干网络的深度,对于 ResNet 和 ResNext 通常设置为 50 或 101
num_stages=4, # 主干网络状态(stages)的数目,这些状态产生的特征图作为后续的 head 的输入
out_indices=(0, 1, 2, 3), # 每个状态产生的特征图输出的索引
frozen_stages=1, # 第一个状态的权重被冻结
norm_cfg=dict( # 归一化层(norm layer)的配置项
type='BN', # 归一化层的类别,通常是 BN 或 GN
requires_grad=True), # 是否训练归一化里的 gamma 和 beta
norm_eval=True, # 是否冻结 BN 里的统计项
style='pytorch', # 主干网络的风格,'pytorch' 意思是步长为2的层为 3x3 卷积, 'caffe' 意思是步长为2的层为 1x1 卷积
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), # 加载通过 ImageNet 预训练的模型
neck=dict(
type='FPN', # 检测器的 neck 是 FPN,我们同样支持 'NASFPN', 'PAFPN' 等,更多细节可以参考 https://mmdetection.readthedocs.io/en/latest/api.html#mmdet.models.necks.FPN
in_channels=[256, 512, 1024, 2048], # 输入通道数,这与主干网络的输出通道一致
out_channels=256, # 金字塔特征图每一层的输出通道
num_outs=5), # 输出的范围(scales)
rpn_head=dict(
type='RPNHead', # rpn_head 的类型是 'RPNHead', 我们也支持 'GARPNHead' 等,更多细节可以参考 https://mmdetection.readthedocs.io/en/latest/api.html#mmdet.models.dense_heads.RPNHead
in_channels=256, # 每个输入特征图的输入通道,这与 neck 的输出通道一致
feat_channels=256, # head 卷积层的特征通道
anchor_generator=dict( # 锚点(Anchor)生成器的配置
type='AnchorGenerator', # 大多数方法使用 AnchorGenerator 作为锚点生成器, SSD 检测器使用 `SSDAnchorGenerator`。更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/prior_generators/anchor_generator.py#L18
scales=[8], # 锚点的基本比例,特征图某一位置的锚点面积为 scale * base_sizes
ratios=[0.5, 1.0, 2.0], # 高度和宽度之间的比率
strides=[4, 8, 16, 32, 64]), # 锚生成器的步幅。这与 FPN 特征步幅一致。 如果未设置 base_sizes,则当前步幅值将被视为 base_sizes
bbox_coder=dict( # 在训练和测试期间对框进行编码和解码
type='DeltaXYWHBBoxCoder', # 框编码器的类别,'DeltaXYWHBBoxCoder' 是最常用的,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/coders/delta_xywh_bbox_coder.py#L13
target_means=[0.0, 0.0, 0.0, 0.0], # 用于编码和解码框的目标均值
target_stds=[1.0, 1.0, 1.0, 1.0]), # 用于编码和解码框的标准差
loss_cls=dict( # 分类分支的损失函数配置
type='CrossEntropyLoss', # 分类分支的损失类型,我们也支持 FocalLoss 等,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/losses/cross_entropy_loss.py#L201
use_sigmoid=True, # RPN 通常进行二分类,所以通常使用 sigmoid 函数
los_weight=1.0), # 分类分支的损失权重
loss_bbox=dict( # 回归分支的损失函数配置
type='L1Loss', # 损失类型,我们还支持许多 IoU Losses 和 Smooth L1-loss 等,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/losses/smooth_l1_loss.py#L56
loss_weight=1.0)), # 回归分支的损失权重
roi_head=dict( # RoIHead 封装了两步(two-stage)/级联(cascade)检测器的第二步
type='StandardRoIHead', # RoI head 的类型,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/roi_heads/standard_roi_head.py#L17
bbox_roi_extractor=dict( # 用于 bbox 回归的 RoI 特征提取器
type='SingleRoIExtractor', # RoI 特征提取器的类型,大多数方法使用 SingleRoIExtractor,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/roi_heads/roi_extractors/single_level_roi_extractor.py#L13
roi_layer=dict( # RoI 层的配置
type='RoIAlign', # RoI 层的类别, 也支持 DeformRoIPoolingPack 和 ModulatedDeformRoIPoolingPack,更多细节请参考 https://mmcv.readthedocs.io/en/latest/api.html#mmcv.ops.RoIAlign
output_size=7, # 特征图的输出大小
sampling_ratio=0), # 提取 RoI 特征时的采样率。0 表示自适应比率
out_channels=256, # 提取特征的输出通道
featmap_strides=[4, 8, 16, 32]), # 多尺度特征图的步幅,应该与主干的架构保持一致
bbox_head=dict( # RoIHead 中 box head 的配置
type='Shared2FCBBoxHead', # bbox head 的类别,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/roi_heads/bbox_heads/convfc_bbox_head.py#L220
in_channels=256, # bbox head 的输入通道。 这与 roi_extractor 中的 out_channels 一致
fc_out_channels=1024, # FC 层的输出特征通道
roi_feat_size=7, # 候选区域(Region of Interest)特征的大小
num_classes=80, # 分类的类别数量
bbox_coder=dict( # 第二阶段使用的框编码器
type='DeltaXYWHBBoxCoder', # 框编码器的类别,大多数情况使用 'DeltaXYWHBBoxCoder'
target_means=[0.0, 0.0, 0.0, 0.0], # 用于编码和解码框的均值
target_stds=[0.1, 0.1, 0.2, 0.2]), # 编码和解码的标准差。因为框更准确,所以值更小,常规设置时 [0.1, 0.1, 0.2, 0.2]。
reg_class_agnostic=False, # 回归是否与类别无关
loss_cls=dict( # 分类分支的损失函数配
type='CrossEntropyLoss', # 分类分支的损失类型,我们也支持 FocalLoss 等
use_sigmoid=False, # 是否使用 sigmoid
loss_weight=1.0), # 分类分支的损失权重
loss_bbox=dict( # 回归分支的损失函数配置
type='L1Loss', # 损失类型,我们还支持许多 IoU Losses 和 Smooth L1-loss 等
loss_weight=1.0)), # 回归分支的损失权重
mask_roi_extractor=dict( # 用于 mask 生成的 RoI 特征提取器
type='SingleRoIExtractor', # RoI 特征提取器的类型,大多数方法使用 SingleRoIExtractor
roi_layer=dict( # 提取实例分割特征的 RoI 层配置
type='RoIAlign', # RoI 层的类型,也支持 DeformRoIPoolingPack 和 ModulatedDeformRoIPoolingPack
output_size=14, # 特征图的输出大小
sampling_ratio=0), # 提取 RoI 特征时的采样率
out_channels=256, # 提取特征的输出通道
featmap_strides=[4, 8, 16, 32]), # 多尺度特征图的步幅
mask_head=dict( # mask 预测 head 模型
type='FCNMaskHead', # mask head 的类型,更多细节请参考 https://mmdetection.readthedocs.io/en/latest/api.html#mmdet.models.roi_heads.FCNMaskHead
num_convs=4, # mask head 中的卷积层数
in_channels=256, # 输入通道,应与 mask roi extractor 的输出通道一致
conv_out_channels=256, # 卷积层的输出通道
num_classes=80, # 要分割的类别数
loss_mask=dict( # mask 分支的损失函数配置
type='CrossEntropyLoss', # 用于分割的损失类型
use_mask=True, # 是否只在正确的类中训练 mask
loss_weight=1.0))), # mask 分支的损失权重
train_cfg = dict( # rpn 和 rcnn 训练超参数的配置
rpn=dict( # rpn 的训练配置
assigner=dict( # 分配器(assigner)的配置
type='MaxIoUAssigner', # 分配器的类型,MaxIoUAssigner 用于许多常见的检测器,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/assigners/max_iou_assigner.py#L14
pos_iou_thr=0.7, # IoU >= 0.7(阈值) 被视为正样本
neg_iou_thr=0.3, # IoU < 0.3(阈值) 被视为负样本
min_pos_iou=0.3, # 将框作为正样本的最小 IoU 阈值
match_low_quality=True, # 是否匹配低质量的框(更多细节见 API 文档)
ignore_iof_thr=-1), # 忽略 bbox 的 IoF 阈值
sampler=dict( # 正/负采样器(sampler)的配置
type='RandomSampler', # 采样器类型,还支持 PseudoSampler 和其他采样器,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/samplers/random_sampler.py#L14
num=256, # 样本数量。
pos_fraction=0.5, # 正样本占总样本的比例
neg_pos_ub=-1, # 基于正样本数量的负样本上限
add_gt_as_proposals=False), # 采样后是否添加 GT 作为 proposal
allowed_border=-1, # 填充有效锚点后允许的边框
pos_weight=-1, # 训练期间正样本的权重
debug=False), # 是否设置调试(debug)模式
rpn_proposal=dict( # 在训练期间生成 proposals 的配置
nms_across_levels=False, # 是否对跨层的 box 做 NMS。仅适用于 `GARPNHead` ,naive rpn 不支持 nms cross levels
nms_pre=2000, # NMS 前的 box 数
nms_post=1000, # NMS 要保留的 box 的数量,只在 GARPNHHead 中起作用
max_per_img=1000, # NMS 后要保留的 box 数量
nms=dict( # NMS 的配置
type='nms', # NMS 的类别
iou_threshold=0.7 # NMS 的阈值
),
min_bbox_size=0), # 允许的最小 box 尺寸
rcnn=dict( # roi head 的配置。
assigner=dict( # 第二阶段分配器的配置,这与 rpn 中的不同
type='MaxIoUAssigner', # 分配器的类型,MaxIoUAssigner 目前用于所有 roi_heads。更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/assigners/max_iou_assigner.py#L14
pos_iou_thr=0.5, # IoU >= 0.5(阈值)被认为是正样本
neg_iou_thr=0.5, # IoU < 0.5(阈值)被认为是负样本
min_pos_iou=0.5, # 将 box 作为正样本的最小 IoU 阈值
match_low_quality=False, # 是否匹配低质量下的 box(有关更多详细信息,请参阅 API 文档)
ignore_iof_thr=-1), # 忽略 bbox 的 IoF 阈值
sampler=dict(
type='RandomSampler', # 采样器的类型,还支持 PseudoSampler 和其他采样器,更多细节请参考 https://github.com/open-mmlab/mmdetection/blob/main/mmdet/models/task_modules/samplers/random_sampler.py#L14
num=512, # 样本数量
pos_fraction=0.25, # 正样本占总样本的比例
neg_pos_ub=-1, # 基于正样本数量的负样本上限
add_gt_as_proposals=True
), # 采样后是否添加 GT 作为 proposal
mask_size=28, # mask 的大小
pos_weight=-1, # 训练期间正样本的权重
debug=False)), # 是否设置调试模式
test_cfg = dict( # 用于测试 rpn 和 rcnn 超参数的配置
rpn=dict( # 测试阶段生成 proposals 的配置
nms_across_levels=False, # 是否对跨层的 box 做 NMS。仅适用于 `GARPNHead`,naive rpn 不支持做 NMS cross levels
nms_pre=1000, # NMS 前的 box 数
nms_post=1000, # NMS 要保留的 box 的数量,只在 `GARPNHHead` 中起作用
max_per_img=1000, # NMS 后要保留的 box 数量
nms=dict( # NMS 的配置
type='nms', # NMS 的类型
iou_threshold=0.7 # NMS 阈值
),
min_bbox_size=0), # box 允许的最小尺寸
rcnn=dict( # roi heads 的配置
score_thr=0.05, # bbox 的分数阈值
nms=dict( # 第二步的 NMS 配置
type='nms', # NMS 的类型
iou_thr=0.5), # NMS 的阈值
max_per_img=100, # 每张图像的最大检测次数
mask_thr_binary=0.5))) # mask 预处的阈值
```
### 数据集和评测器配置
在使用[执行器](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/runner.html) 进行训练、测试、验证时,我们需要配置 [Dataloader](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/dataset.html)。构建数据 dataloader 需要设置数据集(dataset)和数据处理流程(data pipeline)。 由于这部分的配置较为复杂,我们使用中间变量来简化 dataloader 配置的编写。
```python
dataset_type = 'CocoDataset' # 数据集类型,这将被用来定义数据集。
data_root = 'data/coco/' # 数据的根路径。
train_pipeline = [ # 训练数据处理流程
dict(type='LoadImageFromFile'), # 第 1 个流程,从文件路径里加载图像。
dict(
type='LoadAnnotations', # 第 2 个流程,对于当前图像,加载它的注释信息。
with_bbox=True, # 是否使用标注框(bounding box), 目标检测需要设置为 True。
with_mask=True, # 是否使用 instance mask,实例分割需要设置为 True。
poly2mask=False), # 是否将 polygon mask 转化为 instance mask, 设置为 False 以加速和节省内存。
dict(
type='Resize', # 变化图像和其标注大小的流程。
scale=(1333, 800), # 图像的最大尺寸
keep_ratio=True # 是否保持图像的长宽比。
),
dict(
type='RandomFlip', # 翻转图像和其标注的数据增广流程。
prob=0.5), # 翻转图像的概率。
dict(type='PackDetInputs') # 将数据转换为检测器输入格式的流程
]
test_pipeline = [ # 测试数据处理流程
dict(type='LoadImageFromFile'), # 第 1 个流程,从文件路径里加载图像。
dict(type='Resize', scale=(1333, 800), keep_ratio=True), # 变化图像大小的流程。
dict(
type='PackDetInputs', # 将数据转换为检测器输入格式的流程
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor'))
]
train_dataloader = dict( # 训练 dataloader 配置
batch_size=2, # 单个 GPU 的 batch size
num_workers=2, # 单个 GPU 分配的数据加载线程数
persistent_workers=True, # 如果设置为 True,dataloader 在迭代完一轮之后不会关闭数据读取的子进程,可以加速训练
sampler=dict( # 训练数据的采样器
type='DefaultSampler', # 默认的采样器,同时支持分布式和非分布式训练。请参考 https://mmengine.readthedocs.io/zh_CN/latest/api/generated/mmengine.dataset.DefaultSampler.html#mmengine.dataset.DefaultSampler
shuffle=True), # 随机打乱每个轮次训练数据的顺序
batch_sampler=dict(type='AspectRatioBatchSampler'), # 批数据采样器,用于确保每一批次内的数据拥有相似的长宽比,可用于节省显存
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)) # 这是由之前创建的 train_pipeline 定义的数据处理流程。
val_dataloader = dict( # 验证 dataloader 配置
batch_size=1, # 单个 GPU 的 Batch size。如果 batch-szie > 1,组成 batch 时的额外填充会影响模型推理精度
num_workers=2, # 单个 GPU 分配的数据加载线程数
persistent_workers=True, # 如果设置为 True,dataloader 在迭代完一轮之后不会关闭数据读取的子进程,可以加速训练
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 配置
```
[评测器](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/evaluation.html) 用于计算训练模型在验证和测试数据集上的指标。评测器的配置由一个或一组评价指标(Metric)配置组成:
```python
val_evaluator = dict( # 验证过程使用的评测器
type='CocoMetric', # 用于评估检测和实例分割的 AR、AP 和 mAP 的 coco 评价指标
ann_file=data_root + 'annotations/instances_val2017.json', # 标注文件路径
metric=['bbox', 'segm'], # 需要计算的评价指标,`bbox` 用于检测,`segm` 用于实例分割
format_only=False)
test_evaluator = val_evaluator # 测试过程使用的评测器
```
由于测试数据集没有标注文件,因此 MMDetection 中的 test_dataloader 和 test_evaluator 配置通常等于val。 如果要保存在测试数据集上的检测结果,则可以像这样编写配置:
```python
# 在测试集上推理,
# 并将检测结果转换格式以用于提交结果
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='CocoMetric',
ann_file=data_root + 'annotations/image_info_test-dev2017.json',
metric=['bbox', 'segm'],
format_only=True, # 只将模型输出转换为 coco 的 JSON 格式并保存
outfile_prefix='./work_dirs/coco_detection/test') # 要保存的 JSON 文件的前缀
```
### 训练和测试的配置
MMEngine 的 Runner 使用 Loop 来控制训练,验证和测试过程。
用户可以使用这些字段设置最大训练轮次和验证间隔。
```python
train_cfg = dict(
type='EpochBasedTrainLoop', # 训练循环的类型,请参考 https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py
max_epochs=12, # 最大训练轮次
val_interval=1) # 验证间隔。每个 epoch 验证一次
val_cfg = dict(type='ValLoop') # 验证循环的类型
test_cfg = dict(type='TestLoop') # 测试循环的类型
```
### 优化相关配置
`optim_wrapper` 是配置优化相关设置的字段。优化器封装(OptimWrapper)不仅提供了优化器的功能,还支持梯度裁剪、混合精度训练等功能。更多内容请看[优化器封装教程](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/optim_wrapper.html)
```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
)
```
`param_scheduler` 字段用于配置参数调度器(Parameter Scheduler)来调整优化器的超参数(例如学习率和动量)。 用户可以组合多个调度器来创建所需的参数调整策略。 在 [参数调度器教程](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/param_scheduler.html)[参数调度器 API 文档](https://mmengine.readthedocs.io/zh_CN/latest/api/generated/mmengine.optim._ParamScheduler.html#mmengine.optim._ParamScheduler) 中查找更多信息。
```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) # 学习率衰减系数
]
```
### 钩子配置
用户可以在训练、验证和测试循环上添加钩子,以便在运行期间插入一些操作。配置中有两种不同的钩子字段,一种是 `default_hooks`,另一种是 `custom_hooks`
`default_hooks` 是一个字典,用于配置运行时必须使用的钩子。这些钩子具有默认优先级,如果未设置,runner 将使用默认值。如果要禁用默认钩子,用户可以将其配置设置为 `None`。更多内容请看 [钩子教程](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/hook.html)
```python
default_hooks = dict(
timer=dict(type='IterTimerHook'),
logger=dict(type='LoggerHook', interval=50),
param_scheduler=dict(type='ParamSchedulerHook'),
checkpoint=dict(type='CheckpointHook', interval=1),
sampler_seed=dict(type='DistSamplerSeedHook'),
visualization=dict(type='DetVisualizationHook'))
```
`custom_hooks` 是一个列表。用户可以在这个字段中加入自定义的钩子。
```python
custom_hooks = []
```
### 运行相关配置
```python
default_scope = 'mmdet' # 默认的注册器域名,默认从此注册器域中寻找模块。请参考 https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/registry.html
env_cfg = dict(
cudnn_benchmark=False, # 是否启用 cudnn benchmark
mp_cfg=dict( # 多进程设置
mp_start_method='fork', # 使用 fork 来启动多进程。'fork' 通常比 'spawn' 更快,但可能存在隐患。请参考 https://github.com/pytorch/pytorch/issues/1355
opencv_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='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` 中的最新检查点。
```
## Iter-based 配置
MMEngine 的 Runner 除了基于轮次的训练循环(epoch)外,还提供了基于迭代(iteration)的训练循环。
要使用基于迭代的训练,用户应该修改 `train_cfg``param_scheduler``train_dataloader``default_hooks``log_processor`
以下是将基于 epoch 的 RetinaNet 配置更改为基于 iteration 的示例:configs/retinanet/retinanet_r50_fpn_90k_coco.py
```python
# iter-based 训练配置
train_cfg = dict(
_delete_=True, # 忽略继承的配置文件中的值(可选)
type='IterBasedTrainLoop', # iter-based 训练循环
max_iters=90000, # 最大迭代次数
val_interval=10000) # 每隔多少次进行一次验证
# 将参数调度器修改为 iter-based
param_scheduler = [
dict(
type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500),
dict(
type='MultiStepLR',
begin=0,
end=90000,
by_epoch=False,
milestones=[60000, 80000],
gamma=0.1)
]
# 切换至 InfiniteSampler 来避免 dataloader 重启
train_dataloader = dict(sampler=dict(type='InfiniteSampler'))
# 将模型检查点保存间隔设置为按 iter 保存
default_hooks = dict(checkpoint=dict(by_epoch=False, interval=10000))
# 将日志格式修改为 iter-based
log_processor = dict(by_epoch=False)
```
## 配置文件继承
`config/_base_` 文件夹下有 4 个基本组件类型,分别是:数据集(dataset),模型(model),训练策略(schedule)和运行时的默认设置(default runtime)。许多方法,例如 Faster R-CNN、Mask R-CNN、Cascade R-CNN、RPN、SSD 能够很容易地构建出来。由 `_base_` 下的组件组成的配置,被我们称为 _原始配置(primitive)_。
对于同一文件夹下的所有配置,推荐**只有一个**对应的**原始配置**文件。所有其他的配置文件都应该继承自这个**原始配置**文件。这样就能保证配置文件的最大继承深度为 3。
为了便于理解,我们建议贡献者继承现有方法。例如,如果在 Faster R-CNN 的基础上做了一些修改,用户首先可以通过指定 `_base_ = ../faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py` 来继承基础的 Faster R-CNN 结构,然后修改配置文件中的必要参数以完成继承。
如果你在构建一个与任何现有方法不共享结构的全新方法,那么可以在 `configs` 文件夹下创建一个新的例如 `xxx_rcnn` 文件夹。
更多细节请参考 [MMEngine 配置文件教程](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)
通过设置 `_base_` 字段,我们可以设置当前配置文件继承自哪些文件。
`_base_` 为文件路径字符串时,表示继承一个配置文件的内容。
```python
_base_ = './mask-rcnn_r50_fpn_1x_coco.py'
```
`_base_` 是多个文件路径的列表时,表示继承多个文件。
```python
_base_ = [
'../_base_/models/mask-rcnn_r50_fpn.py',
'../_base_/datasets/coco_instance.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
```
如果需要检查配置文件,可以通过运行 `python tools/misc/print_config.py /PATH/TO/CONFIG` 来查看完整的配置。
### 忽略基础配置文件里的部分内容
有时,您也许会设置 `_delete_=True` 去忽略基础配置文件里的一些域内容。 您也许可以参照 [MMEngine 配置文件教程](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html) 来获得一些简单的指导。
在 MMDetection 里,例如为了改变 Mask R-CNN 的主干网络的某些内容:
```python
model = dict(
type='MaskRCNN',
backbone=dict(
type='ResNet',
depth=50,
num_stages=4,
out_indices=(0, 1, 2, 3),
frozen_stages=1,
norm_cfg=dict(type='BN', requires_grad=True),
norm_eval=True,
style='pytorch',
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),
neck=dict(...),
rpn_head=dict(...),
roi_head=dict(...))
```
基础配置的 `Mask R-CNN` 使用 `ResNet-50`,在需要将主干网络改成 `HRNet` 的时候,因为 `HRNet``ResNet` 中有不同的字段,需要使用 `_delete_=True` 将新的键去替换 `backbone` 域内所有老的键。
```python
_base_ = '../mask_rcnn/mask-rcnn_r50_fpn_1x_coco.py'
model = dict(
backbone=dict(
_delete_=True,
type='HRNet',
extra=dict(
stage1=dict(
num_modules=1,
num_branches=1,
block='BOTTLENECK',
num_blocks=(4, ),
num_channels=(64, )),
stage2=dict(
num_modules=1,
num_branches=2,
block='BASIC',
num_blocks=(4, 4),
num_channels=(32, 64)),
stage3=dict(
num_modules=4,
num_branches=3,
block='BASIC',
num_blocks=(4, 4, 4),
num_channels=(32, 64, 128)),
stage4=dict(
num_modules=3,
num_branches=4,
block='BASIC',
num_blocks=(4, 4, 4, 4),
num_channels=(32, 64, 128, 256))),
init_cfg=dict(type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')),
neck=dict(...))
```
### 使用配置文件里的中间变量
配置文件里会使用一些中间变量,例如数据集里的 `train_pipeline`/`test_pipeline`。我们在定义新的 `train_pipeline`/`test_pipeline` 之后,需要将它们传递到 `data` 里。例如,我们想在训练或测试时,改变 Mask R-CNN 的多尺度策略 (multi scale strategy),`train_pipeline`/`test_pipeline` 是我们想要修改的中间变量。
```python
_base_ = './mask-rcnn_r50_fpn_1x_coco.py'
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True, with_mask=True),
dict(
type='RandomResize', scale=[(1333, 640), (1333, 800)],
keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(type='PackDetInputs')
]
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'))
]
train_dataloader = dict(dataset=dict(pipeline=train_pipeline))
val_dataloader = dict(dataset=dict(pipeline=test_pipeline))
test_dataloader = dict(dataset=dict(pipeline=test_pipeline))
```
我们首先定义新的 `train_pipeline`/`test_pipeline` 然后传递到 `data` 里。
同样的,如果我们想从 `SyncBN` 切换到 `BN` 或者 `MMSyncBN`,我们需要修改配置文件里的每一个 `norm_cfg`
```python
_base_ = './mask-rcnn_r50_fpn_1x_coco.py'
norm_cfg = dict(type='BN', requires_grad=True)
model = dict(
backbone=dict(norm_cfg=norm_cfg),
neck=dict(norm_cfg=norm_cfg),
...)
```
### 复用 \_base\_ 文件中的变量
如果用户希望在当前配置中复用 base 文件中的变量,则可以通过使用 `{{_base_.xxx}}` 的方式来获取对应变量的拷贝。例如:
```python
_base_ = './mask-rcnn_r50_fpn_1x_coco.py'
a = {{_base_.model}} # 变量 a 等于 _base_ 中定义的 model
```
## 通过脚本参数修改配置
当运行 `tools/train.py``tools/test.py` 时,可以通过 `--cfg-options` 来修改配置文件。
- 更新字典链中的配置
可以按照原始配置文件中的 dict 键顺序地指定配置预选项。例如,使用 `--cfg-options model.backbone.norm_eval=False` 将模型主干网络中的所有 BN 模块都改为 `train` 模式。
- 更新配置列表中的键
在配置文件里,一些字典型的配置被包含在列表中。例如,数据训练流程 `data.train.pipeline` 通常是一个列表,比如 `[dict(type='LoadImageFromFile'), ...]`。如果需要将 `'LoadImageFromFile'` 改成 `'LoadImageFromWebcam'`,需要写成下述形式: `--cfg-options data.train.pipeline.0.type=LoadImageFromNDArray`.
- 更新列表或元组的值
如果要更新的值是列表或元组。例如,配置文件通常设置 `model.data_preprocessor.mean=[123.675, 116.28, 103.53]`. 如果需要改变这个键,可以通过 `--cfg-options model.data_preprocessor.mean="[127,127,127]"` 来重新设置。需要注意,引号 " 是支持列表或元组数据类型所必需的,并且在指定值的引号内**不允许**有空格。
## 配置文件名称风格
我们遵循以下样式来命名配置文件。建议贡献者遵循相同的风格。
```
{algorithm name}_{model component names [component1]_[component2]_[...]}_{training settings}_{training dataset information}_{testing dataset information}.py
```
文件名分为五个部分。 每个部分用`_`连接,每个部分内的单词应该用`-`连接。
- `{algorithm name}`: 算法的名称。 它可以是检测器名称,例如 `faster-rcnn``mask-rcnn` 等。也可以是半监督或知识蒸馏算法,例如 `soft-teacher``lad` 等等
- `{component names}`: 算法中使用的组件名称,如 backbone、neck 等。例如 `r50-caffe_fpn_gn-head` 表示在算法中使用 caffe 版本的 ResNet50、FPN 和 使用了 Group Norm 的检测头。
- `{training settings}`: 训练设置的信息,例如 batch 大小、数据增强、损失、参数调度方式和训练最大轮次/迭代。 例如:`4xb4-mixup-giou-coslr-100e` 表示使用 8 个 gpu 每个 gpu 4 张图、mixup 数据增强、GIoU loss、余弦退火学习率,并训练 100 个 epoch。
缩写介绍:
- `{gpu x batch_per_gpu}`: GPU 数和每个 GPU 的样本数。`bN` 表示每个 GPU 上的 batch 大小为 N。例如 `4x4b` 是 4 个 GPU 每个 GPU 4 张图的缩写。如果没有注明,默认为 8 卡每卡 2 张图。
- `{schedule}`: 训练方案,选项是 `1x``2x``20e` 等。`1x``2x` 分别代表 12 epoch 和 24 epoch,`20e` 在级联模型中使用,表示 20 epoch。对于 `1x`/`2x`,初始学习率在第 8/16 和第 11/22 epoch 衰减 10 倍;对于 `20e` ,初始学习率在第 16 和第 19 epoch 衰减 10 倍。
- `{training dataset information}`: 训练数据集,例如 `coco`, `coco-panoptic`, `cityscapes`, `voc-0712`, `wider-face`
- `{testing dataset information}` (可选): 测试数据集,用于训练和测试在不同数据集上的模型配置。 如果没有注明,则表示训练和测试的数据集类型相同。
## 数据集准备
### 基础检测数据集准备
MMDetection 支持多个公共数据集,包括 [COCO](https://cocodataset.org/)[Pascal VOC](http://host.robots.ox.ac.uk/pascal/VOC)[Cityscapes](https://www.cityscapes-dataset.com/)[其他更多数据集](https://github.com/open-mmlab/mmdetection/tree/main/configs/_base_/datasets)
一些公共数据集,比如 Pascal VOC 及其镜像数据集,或者 COCO 等数据集都可以从官方网站或者镜像网站获取。注意:在检测任务中,Pascal VOC 2012 是 Pascal VOC 2007 的无交集扩展,我们通常将两者一起使用。 我们建议将数据集下载,然后解压到项目外部的某个文件夹内,然后通过符号链接的方式,将数据集根目录链接到 `$MMDETECTION/data` 文件夹下, 如果你的文件夹结构和下方不同的话,你需要在配置文件中改变对应的路径。
我们提供了下载 COCO 等数据集的脚本,你可以运行 `python tools/misc/download_dataset.py --dataset-name coco2017` 下载 COCO 数据集。 对于中国境内的用户,我们也推荐通过开源数据平台 [OpenDataLab](https://opendatalab.com/?source=OpenMMLab%20GitHub) 来下载数据,以获得更好的下载体验。
更多用法请参考[数据集下载](./useful_tools.md#dataset-download)
```text
mmdetection
├── mmdet
├── tools
├── configs
├── data
│ ├── coco
│ │ ├── annotations
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ ├── cityscapes
│ │ ├── annotations
│ │ ├── leftImg8bit
│ │ │ ├── train
│ │ │ ├── val
│ │ ├── gtFine
│ │ │ ├── train
│ │ │ ├── val
│ ├── VOCdevkit
│ │ ├── VOC2007
│ │ ├── VOC2012
```
有些模型需要额外的 [COCO-stuff](http://calvin.inf.ed.ac.uk/wp-content/uploads/data/cocostuffdataset/stuffthingmaps_trainval2017.zip) 数据集,比如 HTC,DetectoRS 和 SCNet,你可以下载并解压它们到 `coco` 文件夹下。文件夹会是如下结构:
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ │ ├── stuffthingmaps
```
PanopticFPN 等全景分割模型需要额外的 [COCO Panoptic](http://images.cocodataset.org/annotations/panoptic_annotations_trainval2017.zip) 数据集,你可以下载并解压它们到 `coco/annotations` 文件夹下。文件夹会是如下结构:
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── panoptic_train2017.json
│ │ │ ├── panoptic_train2017
│ │ │ ├── panoptic_val2017.json
│ │ │ ├── panoptic_val2017
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
```
Cityscape 数据集的标注格式需要转换,以与 COCO 数据集标注格式保持一致,使用 `tools/dataset_converters/cityscapes.py` 来完成转换:
```shell
pip install cityscapesscripts
python tools/dataset_converters/cityscapes.py \
./data/cityscapes \
--nproc 8 \
--out-dir ./data/cityscapes/annotations
```
### COCO Caption 数据集准备
COCO Caption 采用的是 COCO2014 数据集作为图片,并且使用了 karpathy 的标注,
首先你需要下载 COCO2014 数据集
```shell
python tools/misc/download_dataset.py --dataset-name coco2014 --unzip
```
数据集会下载到当前路径的 `data/coco` 下。然后下载 karpathy 的标注
```shell
cd data/coco/annotations
wget https://storage.googleapis.com/sfr-vision-language-research/datasets/coco_karpathy_train.json
wget https://storage.googleapis.com/sfr-vision-language-research/datasets/coco_karpathy_val.json
wget https://storage.googleapis.com/sfr-vision-language-research/datasets/coco_karpathy_test.json
wget https://storage.googleapis.com/sfr-vision-language-research/datasets/coco_karpathy_val_gt.json
wget https://storage.googleapis.com/sfr-vision-language-research/datasets/coco_karpathy_test_gt.json
```
最终直接可用于训练和测试的数据集文件夹结构如下:
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── coco_karpathy_train.json
│ │ │ ├── coco_karpathy_test.json
│ │ │ ├── coco_karpathy_val.json
│ │ │ ├── coco_karpathy_val_gt.json
│ │ │ ├── coco_karpathy_test_gt.json
│ │ ├── train2014
│ │ ├── val2014
│ │ ├── test2014
```
### COCO semantic 数据集准备
COCO 语义分割有两种类型标注,主要差别在于类别名定义不一样,因此处理方式也有两种,第一种是直接使用 stuffthingmaps 数据集,第二种是使用 panoptic 数据集。
**(1) 使用 stuffthingmaps 数据集**
该数据集的下载地址为 [stuffthingmaps_trainval2017](http://calvin.inf.ed.ac.uk/wp-content/uploads/data/cocostuffdataset/stuffthingmaps_trainval2017.zip),请下载后解压到 `data/coco` 文件夹下。
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ │ ├── stuffthingmaps
```
该数据集不同于标准的 COCO 类别标注,其包括 172 个类: 80 thing 类、91 stuff 类和 1 个 'unlabeled',其每个类别的说明见 https://github.com/nightrome/cocostuff/blob/master/labels.md
虽然只标注了 172 个类别,但是 `stuffthingmaps` 中最大标签 id 是 182,中间有些类别是没有标注的,并且第 0 类的 `unlabeled` 类别被移除。因此最终的 `stuffthingmaps` 图片中每个位置的值对应的类别关系见 https://github.com/kazuto1011/deeplab-pytorch/blob/master/data/datasets/cocostuff/labels.txt
考虑到训练高效和方便用户,在开启训练或者评估前,我们需要将没有标注的 12 个类移除,这 12 个类的名字为: `street sign、hat、shoe、eye glasses、plate、mirror、window、desk、door、blender、hair brush`,最终可用于训练和评估的类别信息见 `mmdet/datasets/coco_semantic.py`
你可以使用 `tools/dataset_converters/coco_stuff164k.py` 来完成将下载的 `stuffthingmaps` 转换为直接可以训练和评估的数据集,转换后的数据集文件夹结构如下:
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ │ ├── stuffthingmaps
│ │ ├── stuffthingmaps_semseg
```
`stuffthingmaps_semseg` 即为新生成的可以直接训练和测试的 COCO 语义分割数据集。
**(2) 使用 panoptic 数据集**
通过 panoptic 标注生成的语义分割数据集类别数相比使用 `stuffthingmaps` 数据集生成的会少一些。首先你需要准备全景分割标注,然后使用如下脚本完成转换
```shell
python tools/dataset_converters/prepare_coco_semantic_annos_from_panoptic_annos.py data/coco
```
转换后的数据集文件夹结构如下:
```text
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── panoptic_train2017.json
│ │ │ ├── panoptic_train2017
│ │ │ ├── panoptic_val2017.json
│ │ │ ├── panoptic_val2017
│ │ │ ├── panoptic_semseg_train2017
│ │ │ ├── panoptic_semseg_val2017
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
```
`panoptic_semseg_train2017``panoptic_semseg_val2017` 即为新生成的可以直接训练和测试的 COCO 语义分割数据集。注意其类别信息就是 COCO 全景分割的类别信息,包括 thing 和 stuff。
### RefCOCO 数据集准备
[RefCOCO](https://github.com/lichengunc/refer)系列数据集的图像和注释可以通过运行 `tools/misc/download_dataset.py` 下载:
```shell
python tools/misc/download_dataset.py --dataset-name refcoco --save-dir data/coco --unzip
```
然后,目录应该是这样的:
```text
data
├── coco
│ ├── refcoco
│   │   ├── instances.json
│   │   ├── refs(google).p
│   │   └── refs(unc).p
│   ├── refcoco+
│   │   ├── instances.json
│   │   └── refs(unc).p
│   ├── refcocog
│   │   ├── instances.json
│   │   ├── refs(google).p
│   │   └── refs(umd).p
| |── train2014
```
### ADE20K 数据集准备
[ADE20K](http://groups.csail.mit.edu/vision/datasets/ADE20K/)数据集的图像和注释可以通过运行 `tools/misc/download_dataset.py` 下载:
```shell
python tools/misc/download_dataset.py --dataset-name ade20k_2016 --save-dir data --unzip
```
然后将注释移至`data/ADEChallengeData2016`目录,并运行预处理脚本以产生coco格式注释:
```shell
mv data/annotations_instance data/ADEChallengeData2016/
mv data/categoryMapping.txt data/ADEChallengeData2016/
mv data/imgCatIds.json data/ADEChallengeData2016/
python tools/dataset_converters/ade20k2coco.py data/ADEChallengeData2016 --task panoptic
python tools/dataset_converters/ade20k2coco.py data/ADEChallengeData2016 --task instance
```
然后,目录应该是这样的:
```text
data
├── ADEChallengeData2016
│   ├── ade20k_instance_train.json
│   ├── ade20k_instance_val.json
│   ├── ade20k_panoptic_train
| | ├── ADE_train_00000001.png
| | ├── ADE_train_00000002.png
| | ├── ...
│   ├── ade20k_panoptic_train.json
│   ├── ade20k_panoptic_val
| | ├── ADE_val_00000001.png
| | ├── ADE_val_00000002.png
| | ├── ...
│   ├── ade20k_panoptic_val.json
│   ├── annotations
| | ├── training
| | | ├── ADE_train_00000001.png
| | | ├── ADE_train_00000002.png
| | | ├── ...
| | ├── validation
| | | ├── ADE_val_00000001.png
| | | ├── ADE_val_00000002.png
| | | ├── ...
│   ├── annotations_instance
| | ├── training
| | | ├── ADE_train_00000001.png
| | | ├── ADE_train_00000002.png
| | | ├── ...
| | ├── validation
| | | ├── ADE_val_00000001.png
| | | ├── ADE_val_00000002.png
| | | ├── ...
│   ├── categoryMapping.txt
│   ├── images
│   | ├── training
| | | ├── ADE_train_00000001.jpg
| | | ├── ADE_train_00000002.jpg
| | | ├── ...
| | ├── validation
| | | ├── ADE_val_00000001.jpg
| | | ├── ADE_val_00000002.jpg
| | | ├── ...
│   ├── imgCatIds.json
│   ├── objectInfo150.txt
| |── sceneCategories.txt
```
上述文件夹包括ADE20K的语义分割、实例分割和泛在分割的所有数据。
### 从 OpenDataLab 中下载
[OpenDataLab](https://opendatalab.com/) 为人工智能研究者提供免费开源的数据集,通过 OpenDataLab,研究者可以获得格式统一的各领域经典数据集。通过平台的搜索功能,研究者可以迅速便捷地找到自己所需数据集;通过平台的统一格式,研究者可以便捷地对跨数据集任务进行开发。
目前,MIM 支持使用一条命令行从 OpenDataLab 中下载 VOC 和 COCO 数据集,后续将支持更多数据集。你也可以直接访问 OpenDataLab 平台下载你所需的数据集,然后将其转化为 MMDetection 所要求的格式。
如果使用 MIM 下载,请确保版本大于 v0.3.8,你可以使用如下命令更新:
```Bash
pip install -U openmim
```
```Bash
# install OpenXLab CLI tools
pip install -U openxlab
# log in OpenXLab, registry
openxlab login
# download voc2007 and preprocess by MIM
mim download mmdet --dataset voc2007
# download voc2012 and preprocess by MIM
mim download mmdet --dataset voc2012
# download coco2017 and preprocess by MIM
mim download mmdet --dataset coco2017
```
# 模型部署
[MMDeploy](https://github.com/open-mmlab/mmdeploy) 是 OpenMMLab 的部署仓库,负责包括 MMPretrain、MMDetection 等在内的各算法库的部署工作。
你可以从[这里](https://mmdeploy.readthedocs.io/zh_CN/1.x/04-supported-codebases/mmdet.html)获取 MMDeploy 对 MMDetection 部署支持的最新文档。
本文的结构如下:
- [安装](#安装)
- [模型转换](#模型转换)
- [模型规范](#模型规范)
- [模型推理](#模型推理)
- [后端模型推理](#后端模型推理)
- [SDK 模型推理](#sdk-模型推理)
- [模型支持列表](#模型支持列表)
-
## 安装
请参考[此处](https://mmdetection.readthedocs.io/en/latest/get_started.html)安装 mmdet。然后,按照[说明](https://mmdeploy.readthedocs.io/zh_CN/1.x/get_started.html#mmdeploy)安装 mmdeploy。
```{note}
如果安装的是 mmdeploy 预编译包,那么也请通过 'git clone https://github.com/open-mmlab/mmdeploy.git --depth=1' 下载 mmdeploy 源码。因为它包含了部署时要用到的配置文件
```
## 模型转换
假设在安装步骤中,mmdetection 和 mmdeploy 代码库在同级目录下,并且当前的工作目录为 mmdetection 的根目录,那么以 [Faster R-CNN](https://github.com/open-mmlab/mmdetection/blob/main/configs/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py) 模型为例,你可以从[此处](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth)下载对应的 checkpoint,并使用以下代码将之转换为 onnx 模型:
```python
from mmdeploy.apis import torch2onnx
from mmdeploy.backend.sdk.export_info import export2SDK
img = 'demo/demo.jpg'
work_dir = 'mmdeploy_models/mmdet/onnx'
save_file = 'end2end.onnx'
deploy_cfg = '../mmdeploy/configs/mmdet/detection/detection_onnxruntime_dynamic.py'
model_cfg = 'configs/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py'
model_checkpoint = 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
device = 'cpu'
# 1. convert model to onnx
torch2onnx(img, work_dir, save_file, deploy_cfg, model_cfg,
model_checkpoint, device)
# 2. extract pipeline info for inference by MMDeploy SDK
export2SDK(deploy_cfg, model_cfg, work_dir, pth=model_checkpoint,
device=device)
```
转换的关键之一是使用正确的配置文件。项目中已内置了各后端部署[配置文件](https://github.com/open-mmlab/mmdeploy/tree/1.x/configs/mmdet)
文件的命名模式是:
```
{task}/{task}_{backend}-{precision}_{static | dynamic}_{shape}.py
```
其中:
- **{task}:** mmdet 中的任务
mmdet 任务有2种:物体检测(detection)、实例分割(instance-seg)。例如,`RetinaNet``Faster R-CNN``DETR`等属于前者。`Mask R-CNN``SOLO`等属于后者。更多`模型-任务`的划分,请参考章节[模型支持列表](#模型支持列表)
**请务必**使用 `detection/detection_*.py` 转换检测模型,使用 `instance-seg/instance-seg_*.py` 转换实例分割模型。
- **{backend}:** 推理后端名称。比如,onnxruntime、tensorrt、pplnn、ncnn、openvino、coreml 等等
- **{precision}:** 推理精度。比如,fp16、int8。不填表示 fp32
- **{static | dynamic}:** 动态、静态 shape
- **{shape}:** 模型输入的 shape 或者 shape 范围
在上例中,你也可以把 `Faster R-CNN` 转为其他后端模型。比如使用`detection_tensorrt-fp16_dynamic-320x320-1344x1344.py`,把模型转为 tensorrt-fp16 模型。
```{tip}
当转 tensorrt 模型时, --device 需要被设置为 "cuda"
```
## 模型规范
在使用转换后的模型进行推理之前,有必要了解转换结果的结构。 它存放在 `--work-dir` 指定的路路径下。
上例中的`mmdeploy_models/mmdet/onnx`,结构如下:
```
mmdeploy_models/mmdet/onnx
├── deploy.json
├── detail.json
├── end2end.onnx
└── pipeline.json
```
重要的是:
- **end2end.onnx**: 推理引擎文件。可用 ONNX Runtime 推理
- ***xxx*.json**: mmdeploy SDK 推理所需的 meta 信息
整个文件夹被定义为**mmdeploy SDK model**。换言之,**mmdeploy SDK model**既包括推理引擎,也包括推理 meta 信息。
## 模型推理
## 后端模型推理
以上述模型转换后的 `end2end.onnx` 为例,你可以使用如下代码进行推理:
```python
from mmdeploy.apis.utils import build_task_processor
from mmdeploy.utils import get_input_shape, load_config
import torch
deploy_cfg = '../mmdeploy/configs/mmdet/detection/detection_onnxruntime_dynamic.py'
model_cfg = 'configs/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py'
device = 'cpu'
backend_model = ['mmdeploy_models/mmdet/onnx/end2end.onnx']
image = 'demo/demo.jpg'
# read deploy_cfg and model_cfg
deploy_cfg, model_cfg = load_config(deploy_cfg, model_cfg)
# build task and backend model
task_processor = build_task_processor(model_cfg, deploy_cfg, device)
model = task_processor.build_backend_model(backend_model)
# process input image
input_shape = get_input_shape(deploy_cfg)
model_inputs, _ = task_processor.create_input(image, input_shape)
# do model inference
with torch.no_grad():
result = model.test_step(model_inputs)
# visualize results
task_processor.visualize(
image=image,
model=model,
result=result[0],
window_name='visualize',
output_file='output_detection.png')
```
## SDK 模型推理
你也可以参考如下代码,对 SDK model 进行推理:
```python
from mmdeploy_python import Detector
import cv2
img = cv2.imread('demo/demo.jpg')
# create a detector
detector = Detector(model_path='mmdeploy_models/mmdet/onnx',
device_name='cpu', device_id=0)
# perform inference
bboxes, labels, masks = detector(img)
# visualize inference result
indices = [i for i in range(len(bboxes))]
for index, bbox, label_id in zip(indices, bboxes, labels):
[left, top, right, bottom], score = bbox[0:4].astype(int), bbox[4]
if score < 0.3:
continue
cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0))
cv2.imwrite('output_detection.png', img)
```
除了python API,mmdeploy SDK 还提供了诸如 C、C++、C#、Java等多语言接口。
你可以参考[样例](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo)学习其他语言接口的使用方法。
## 模型支持列表
请参考[这里](https://mmdeploy.readthedocs.io/zh_CN/1.x/04-supported-codebases/mmdet.html#id6)
# 模型微调
在 COCO 数据集上预训练的检测器可以作为其他数据集(例如 CityScapes 和 KITTI 数据集)优质的预训练模型。
本教程将指导用户如何把 [ModelZoo](../model_zoo.md) 中提供的模型用于其他数据集中并使得当前所训练的模型获得更好性能。
以下是在新数据集中微调模型需要的两个步骤。
-[教程2:自定义数据集](../advanced_guides/customize_dataset.md) 中的方法对新数据集添加支持中的方法对新数据集添加支持
- 按照本教程中所讨论方法,修改配置信息
接下来将会以 Cityscapes Dataset 上的微调过程作为例子,具体讲述用户需要在配置中修改的五个部分。
## 继承基础配置
为了减轻编写整个配置的负担并减少漏洞的数量, MMDetection V3.0 支持从多个现有配置中继承配置信息。微调 MaskRCNN 模型的时候,新的配置信息需要使用从 `_base_/models/mask_rcnn_r50_fpn.py` 中继承的配置信息来构建模型的基本结构。当使用 Cityscapes 数据集时,新的配置信息可以简便地从`_base_/datasets/cityscapes_instance.py` 中继承。对于训练过程的运行设置部分,例如 `logger settings`,配置文件可以从 `_base_/default_runtime.py` 中继承。对于训练计划的配置则可以从`_base_/schedules/schedule_1x.py` 中继承。这些配置文件存放于 `configs` 目录下,用户可以选择全部内容的重新编写而不是使用继承方法。
```python
_base_ = [
'../_base_/models/mask_rcnn_r50_fpn.py',
'../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py',
'../_base_/schedules/schedule_1x.py'
]
```
## Head 的修改
接下来新的配置还需要根据新数据集的类别数量对 Head 进行修改。只需要对 roi_head 中的 `num_classes`进行修改。修改后除了最后的预测模型的 Head 之外,预训练模型的权重的大部分都会被重新使用。
```python
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))))
```
## 数据集的修改
用户可能还需要准备数据集并编写有关数据集的配置,可在 [Customize Datasets](../advanced_guides/customize_dataset.md) 中获取更多信息。目前 MMDetection V3.0 的配置文件已经支持 VOC、WIDERFACE、COCO、LIVS、OpenImages、DeepFashion、Objects365 和 Cityscapes Dataset 的数据集信息。
## 训练策略的修改
微调超参数与默认的训练策略不同。它通常需要更小的学习率和更少的训练回合。
```python
# 优化器
# 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)),
```
## 使用预训练模型
如果要使用预训练模型,可以在 `load_from` 中查阅新的配置信息,用户需要在训练开始之前下载好需要的模型权重,从而避免在训练过程中浪费了宝贵时间。
```python
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
```
训练 & 测试
**************
MMDetection 在 `Model Zoo <https://mmdetection.readthedocs.io/en/latest/model_zoo.html>`_ 中提供了数百个预训练的检测模型,
并支持多种标准数据集格式,包括 Pascal VOC、COCO、CityScapes、LVIS 等。本文档将展示如何使用这些模型和数据集来执行常见的训练和测试任务:
.. toctree::
:maxdepth: 1
config.md
inference.md
dataset_prepare.md
test.md
train.md
new_model.md
finetune.md
test_results_submission.md
init_cfg.md
single_stage_as_rpn.md
semi_det.md
实用工具
************
.. toctree::
:maxdepth: 1
useful_tools.md
useful_hooks.md
visualization.md
robustness_benchmarking.md
deploy.md
label_studio.md
# 使用已有模型在标准数据集上进行推理
MMDetection 提供了许多预训练好的检测模型,可以在 [Model Zoo](https://mmdetection.readthedocs.io/zh_CN/latest/model_zoo.html) 查看具体有哪些模型。
推理具体指使用训练好的模型来检测图像上的目标,本文将会展示具体步骤。
在 MMDetection 中,一个模型被定义为一个[配置文件](https://mmdetection.readthedocs.io/zh_CN/latest/user_guides/config.html) 和对应被存储在 checkpoint 文件内的模型参数的集合。
首先,我们建议从 [RTMDet](https://github.com/open-mmlab/mmdetection/tree/main/configs/rtmdet) 开始,其 [配置](https://github.com/open-mmlab/mmdetection/blob/main/configs/rtmdet/rtmdet_l_8xb32-300e_coco.py) 文件和 [checkpoint](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/rtmdet_l_8xb32-300e_coco/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth) 文件在此。
我们建议将 checkpoint 文件下载到 `checkpoints` 文件夹内。
## 推理的高层编程接口——推理器
在 OpenMMLab 中,所有的推理操作都被统一到了推理器 `Inferencer` 中。推理器被设计成为一个简洁易用的 API,它在不同的 OpenMMLab 库中都有着非常相似的接口。
下面介绍的演示样例都放在 [demo/inference_demo.ipynb](https://github.com/open-mmlab/mmdetection/blob/main/demo/inference_demo.ipynb) 中方便大家尝试。
### 基础用法
使用 `DetInferencer`,您只需 3 行代码就可以获得推理结果。
```python
from mmdet.apis import DetInferencer
# 初始化模型
inferencer = DetInferencer('rtmdet_tiny_8xb32-300e_coco')
# 推理示例图片
inferencer('demo/demo.jpg', show=True)
```
可视化结果将被显示在一个新窗口中:
<div align="center">
<img src='https://github.com/open-mmlab/mmdetection/assets/27466624/311df42d-640a-4a5b-9ad9-9ba7f3ec3a2f' />
</div>
```{note}
如果你在没有 GUI 的服务器上,或者通过禁用 X11 转发的 SSH 隧道运行以上命令,`show` 选项将不起作用。然而,你仍然可以通过设置 `out_dir` 参数将可视化数据保存到文件。阅读 [储存结果](#储存结果) 了解详情。
```
### 初始化
每个推理器必须使用一个模型进行初始化。初始化时,可以手动选择推理设备。
#### 模型初始化
- 要用 MMDetection 的预训练模型进行推理,只需要把它的名字传给参数 `model`,权重将自动从 OpenMMLab 的模型库中下载和加载。
```python
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco')
```
在 MMDetection 中有一个非常容易的方法,可以列出所有模型名称。
```python
# models 是一个模型名称列表,它们将自动打印
models = DetInferencer.list_models('mmdet')
```
你可以通过将权重的路径或 URL 传递给 `weights` 来让推理器加载自定义的权重。
```python
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', weights='path/to/rtmdet.pth')
```
- 要加载自定义的配置和权重,你可以把配置文件的路径传给 `model`,把权重的路径传给 `weights`
```python
inferencer = DetInferencer(model='path/to/rtmdet_config.py', weights='path/to/rtmdet.pth')
```
- 默认情况下,[MMEngine](https://github.com/open-mmlab/mmengine/) 会在训练模型时自动将配置文件转储到权重文件中。如果你有一个在 MMEngine 上训练的权重,你也可以将权重文件的路径传递给 `weights`,而不需要指定 `model`
```python
# 如果无法在权重中找到配置文件,则会引发错误。目前 MMDetection 模型库中只有 ddq-detr-4scale_r50 的权重可以这样加载。
inferencer = DetInferencer(weights='https://download.openmmlab.com/mmdetection/v3.0/ddq/ddq-detr-4scale_r50_8xb2-12e_coco/ddq-detr-4scale_r50_8xb2-12e_coco_20230809_170711-42528127.pth')
```
- 传递配置文件到 `model` 而不指定 `weights` 则会产生一个随机初始化的模型。
#### 推理设备
每个推理器实例都会跟一个设备绑定。默认情况下,最佳设备是由 [MMEngine](https://github.com/open-mmlab/mmengine/) 自动决定的。你也可以通过指定 `device` 参数来改变设备。例如,你可以使用以下代码在 GPU 1 上创建一个推理器。
```python
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', device='cuda:1')
```
如要在 CPU 上创建一个推理器:
```python
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', device='cpu')
```
请参考 [torch.device](https://pytorch.org/docs/stable/tensor_attributes.html#torch.device) 了解 `device` 参数支持的所有形式。
### 推理
当推理器初始化后,你可以直接传入要推理的原始数据,从返回值中获取推理结果。
#### 输入
输入可以是以下任意一种格式:
- str: 图像的路径/URL。
```python
inferencer('demo/demo.jpg')
```
- array: 图像的 numpy 数组。它应该是 BGR 格式。
```python
import mmcv
array = mmcv.imread('demo/demo.jpg')
inferencer(array)
```
- list: 基本类型的列表。列表中的每个元素都将单独处理。
```python
inferencer(['img_1.jpg', 'img_2.jpg])
# 列表内混合类型也是允许的
inferencer(['img_1.jpg', array])
```
- str: 目录的路径。目录中的所有图像都将被处理。
```python
inferencer('path/to/your_imgs/')
```
#### 输出
默认情况下,每个推理器都以字典格式返回预测结果。
- `visualization` 包含可视化的预测结果。但默认情况下,它是一个空列表,除非 `return_vis=True`
- `predictions` 包含以 json-可序列化格式返回的预测结果。
```python
{
'predictions' : [
# 每个实例都对应于一个输入图像
{
'labels': [...], # 整数列表,长度为 (N, )
'scores': [...], # 浮点列表,长度为 (N, )
'bboxes': [...], # 2d 列表,形状为 (N, 4),格式为 [min_x, min_y, max_x, max_y]
},
...
],
'visualization' : [
array(..., dtype=uint8),
]
}
```
如果你想要从模型中获取原始输出,可以将 `return_datasamples` 设置为 `True` 来获取原始的 [DataSample](advanced_guides/structures.md),它将存储在 `predictions` 中。
#### 储存结果
除了从返回值中获取预测结果,你还可以通过设置 `out_dir``no_save_pred`/`no_save_vis` 参数将预测结果和可视化结果导出到文件中。
```python
inferencer('demo/demo.jpg', out_dir='outputs/', no_save_pred=False)
```
结果目录结构如下:
```text
outputs
├── preds
│ └── demo.json
└── vis
└── demo.jpg
```
#### 批量推理
你可以通过设置 `batch_size` 来自定义批量推理的批大小。默认批大小为 1。
### API
这里列出了推理器详尽的参数列表。
- **DetInferencer.\_\_init\_\_():**
| 参数 | 类型 | 默认值 | 描述 |
| --------------- | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model` | str , 可选 | None | 配置文件的路径或 metafile 中定义的模型名称。例如,可以是 'rtmdet-s' 或 'rtmdet_s_8xb32-300e_coco' 或 'configs/rtmdet/rtmdet_s_8xb32-300e_coco.py'。如果未指定模型,用户必须提供 MMEngine 保存的包含配置字符串的 "weights"。 |
| `weights` | str, 可选 | None | 模型权重文件的路径。如果未指定且 `model` 是 metafile 中的模型名称,权重将从 metafile 中加载。 |
| `device` | str, 可选 | None | 推理使用的设备,接受 `torch.device` 允许的所有字符串。例如,'cuda:0' 或 'cpu'。如果为 None,将自动使用可用设备。 默认为 None。 |
| `scope` | str, 可选 | 'mmdet' | 模型的”域名“。 |
| `palette` | str | 'none' | 用于可视化的配色。优先顺序为 palette -> config -> checkpoint。 |
| `show_progress` | bool | True | 控制是否在推理过程中显示进度条。 |
- **DetInferencer.\_\_call\_\_()**
| 参数 | 类型 | 默认值 | 描述 |
| -------------------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inputs` | str/list/tuple/np.array | **必需** | 它可以是一个图片/文件夹的路径,一个 numpy 数组,或者是一个包含图片路径或 numpy 数组的列表/元组 |
| `batch_size` | int | 1 | 推理的批大小。 |
| `return_vis` | bool | False | 是否返回可视化结果。 |
| `show` | bool | False | 是否在弹出窗口中显示可视化结果。 |
| `wait_time` | float | 0 | 弹窗展示可视化结果的时间间隔。 |
| `no_save_vis` | bool | False | 是否将可视化结果保存到 `out_dir`。默认为保存。 |
| `draw_pred` | bool | True | 是否绘制预测的边界框。 |
| `pred_score_thr` | float | 0.3 | 显示预测框的最低置信度。 |
| `return_datasamples` | bool | False | 是否将结果作为 `DetDataSample` 返回。 如果为 False,则结果将被打包到一个 dict 中。 |
| `print_result` | bool | False | 是否将推理结果打印到控制台。 |
| `no_save_pred` | bool | True | 是否将推理结果保存到 `out_dir`。默认为不保存。 |
| `out_dir` | str | '' | 结果的输出目录。 |
| `texts` | str/list\[str\],可选 | None | 文本提示词。 |
| `stuff_texts` | str/list\[str\],可选 | None | 物体文本提示词。 |
| `custom_entities` | bool | False | 是否使用自定义实体。只用于 GLIP 算法。 |
| \*\*kwargs | | | 传递给 :meth:`preprocess`、:meth:`forward`、:meth:`visualize` 和 :meth:`postprocess` 的其他关键字参数。kwargs 中的每个关键字都应在相应的 `preprocess_kwargs``forward_kwargs``visualize_kwargs``postprocess_kwargs` 中。 |
## 演示脚本样例
我们还提供了四个演示脚本,它们是使用高层编程接口实现的。[源码在此](https://github.com/open-mmlab/mmdetection/blob/main/demo)
### 图片样例
这是在单张图片上进行推理的脚本。
```shell
python demo/image_demo.py \
${IMAGE_FILE} \
${CONFIG_FILE} \
[--weights ${WEIGHTS}] \
[--device ${GPU_ID}] \
[--pred-score-thr ${SCORE_THR}]
```
运行样例:
```shell
python demo/image_demo.py demo/demo.jpg \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
--weights checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth \
--device cpu
```
### 摄像头样例
这是使用摄像头实时图片的推理脚本。
```shell
python demo/webcam_demo.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--device ${GPU_ID}] \
[--camera-id ${CAMERA-ID}] \
[--score-thr ${SCORE_THR}]
```
运行样例:
```shell
python demo/webcam_demo.py \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth
```
### 视频样例
这是在视频样例上进行推理的脚本。
```shell
python demo/video_demo.py \
${VIDEO_FILE} \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--device ${GPU_ID}] \
[--score-thr ${SCORE_THR}] \
[--out ${OUT_FILE}] \
[--show] \
[--wait-time ${WAIT_TIME}]
```
运行样例:
```shell
python demo/video_demo.py demo/demo.mp4 \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth \
--out result.mp4
```
#### 视频样例,显卡加速版本
这是在视频样例上进行推理的脚本,使用显卡加速。
```shell
python demo/video_gpuaccel_demo.py \
${VIDEO_FILE} \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--device ${GPU_ID}] \
[--score-thr ${SCORE_THR}] \
[--nvdecode] \
[--out ${OUT_FILE}] \
[--show] \
[--wait-time ${WAIT_TIME}]
```
运行样例:
```shell
python demo/video_gpuaccel_demo.py demo/demo.mp4 \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth \
--nvdecode --out result.mp4
```
### 大图推理样例
这是在大图上进行切片推理的脚本。
```shell
python demo/large_image_demo.py \
${IMG_PATH} \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
--device ${GPU_ID} \
--show \
--tta \
--score-thr ${SCORE_THR} \
--patch-size ${PATCH_SIZE} \
--patch-overlap-ratio ${PATCH_OVERLAP_RATIO} \
--merge-iou-thr ${MERGE_IOU_THR} \
--merge-nms-type ${MERGE_NMS_TYPE} \
--batch-size ${BATCH_SIZE} \
--debug \
--save-patch
```
运行样例:
```shell
# inferecnce without tta
wget -P checkpoint https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth
python demo/large_image_demo.py \
demo/large_image.jpg \
configs/faster_rcnn/faster-rcnn_r101_fpn_2x_coco.py \
checkpoint/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth
# inference with tta
wget -P checkpoint https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth
python demo/large_image_demo.py \
demo/large_image.jpg \
configs/retinanet/retinanet_r50_fpn_1x_coco.py \
checkpoint/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth --tta
```
## 多模态算法的推理和验证
随着多模态视觉算法的不断发展,MMDetection 也完成了对这类算法的支持。这一小节我们通过 GLIP 算法和模型来演示如何使用对应多模态算法的 demo 和 eval 脚本。同时 MMDetection 也在 projects 下完成了 [gradio_demo 项目](../../../projects/gradio_demo/),用户可以参照[文档](../../../projects/gradio_demo/README.md)在本地快速体验 MMDetection 中支持的各类图片输入的任务。
### 模型准备
首先需要安装多模态依赖:
```shell
# if source
pip install -r requirements/multimodal.txt
# if wheel
mim install mmdet[multimodal]
```
MMDetection 已经集成了 glip 算法和模型,可以直接使用链接下载使用:
```shell
cd mmdetection
wget https://download.openmmlab.com/mmdetection/v3.0/glip/glip_tiny_a_mmdet-b3654169.pth
```
### 推理演示
下载完成后我们就可以利用 `demo` 下的多模态推理脚本完成推理:
```shell
python demo/image_demo.py demo/demo.jpg glip_tiny_a_mmdet-b3654169.pth --texts bench
```
demo 效果如下图所示:
<div align=center>
<img src="https://user-images.githubusercontent.com/17425982/234547841-266476c8-f987-4832-8642-34357be621c6.png" height="300"/>
</div>
如果想进行多种类型的识别,需要使用 `xx. xx` 的格式在 `--texts` 字段后声明目标类型:
```shell
python demo/image_demo.py demo/demo.jpg glip_tiny_a_mmdet-b3654169.pth --texts 'bench. car'
```
结果如下图所示:
<div align=center>
<img src="https://user-images.githubusercontent.com/17425982/234548156-ef9bbc2e-7605-4867-abe6-048b8578893d.png" height="300"/>
</div>
推理脚本还支持输入一个句子作为 `--texts` 字段的输入:
```shell
python demo/image_demo.py demo/demo.jpg glip_tiny_a_mmdet-b3654169.pth --texts 'There are a lot of cars here.'
```
结果可以参考下图:
<div align=center>
<img src="https://user-images.githubusercontent.com/17425982/234548490-d2e0a16d-1aad-4708-aea0-c829634fabbd.png" height="300"/>
</div>
### 验证演示
MMDetection 支持后的 GLIP 算法对比官方版本没有精度上的损失, benchmark 如下所示:
| Model | official mAP | mmdet mAP |
| ----------------------- | :----------: | :-------: |
| glip_A_Swin_T_O365.yaml | 42.9 | 43.0 |
| glip_Swin_T_O365.yaml | 44.9 | 44.9 |
| glip_Swin_L.yaml | 51.4 | 51.3 |
用户可以使用 `test.py` 脚本对模型精度进行验证,使用如下所示:
```shell
# 1 gpu
python tools/test.py configs/glip/glip_atss_swin-t_fpn_dyhead_pretrain_obj365.py glip_tiny_a_mmdet-b3654169.pth
# 8 GPU
./tools/dist_test.sh configs/glip/glip_atss_swin-t_fpn_dyhead_pretrain_obj365.py glip_tiny_a_mmdet-b3654169.pth 8
```
# 权重初始化
在训练过程中,适当的初始化策略有利于加快训练速度或获得更⾼的性能。 [MMCV](https://github.com/open-mmlab/mmcv/blob/master/mmcv/cnn/utils/weight_init.py) 提供了一些常⽤的初始化模块的⽅法,如 `nn.Conv2d`。 MMdetection 中的模型初始化主要使⽤ `init_cfg`。⽤⼾可以通过以下两个步骤来初始化模型:
1.`model_cfg` 中为模型或其组件定义 `init_cfg`,但⼦组件的 `init_cfg` 优先级更⾼,会覆盖⽗模块的 `init_cfg`
2. 像往常一样构建模型,然后显式调⽤ `model.init_weights()` ⽅法,此时模型参数将会被按照配置文件写法进行初始化。
MMdetection 初始化工作流的高层 API 调用流程是:
model_cfg(init_cfg) -> build_from_cfg -> model -> init_weight() -> initialize(self, self.init_cfg) -> children's init_weight()
### 描述
它的数据类型是 dict 或者 list\[dict\],包含了下列键值:
- `type` (str),包含 `INTIALIZERS` 中的初始化器名称,后面跟着初始化器的参数。
- `layer`(str 或 list\[str\]),包含 Pytorch 或 MMCV 中基本层的名称,以及将被初始化的可学习参数,例如 `'Conv2d'``'DeformConv2d'`
- `override` (dict 或 list\[dict\]),包含不继承⾃ `BaseModule` 且其初始化配置与 `layer` 键中的其他层不同的⼦模块。 `type` 中定义的初始化器将适⽤于 `layer` 中定义的所有层,因此如果⼦模块不是 `BaseModule` 的派⽣类但可以与 `layer` 中的层相同的⽅式初始化,则不需要使⽤ `override``override` 包含了:
- `type` 后跟初始化器的参数;
- `name` 用以指⽰将被初始化的⼦模块。
### 初始化参数
`mmcv.runner.BaseModule``mmdet.models` 继承一个新模型。这里我们用 FooModel 来举个例子。
```python
import torch.nn as nn
from mmcv.runner import BaseModule
class FooModel(BaseModule)
def __init__(self,
arg1,
arg2,
init_cfg=None):
super(FooModel, self).__init__(init_cfg)
...
```
- 直接在代码中使⽤ `init_cfg` 初始化模型
```python
import torch.nn as nn
from mmcv.runner import BaseModule
# or directly inherit mmdet models
class FooModel(BaseModule)
def __init__(self,
arg1,
arg2,
init_cfg=XXX):
super(FooModel, self).__init__(init_cfg)
...
```
-`mmcv.Sequential``mmcv.ModuleList` 代码中直接使⽤ `init_cfg` 初始化模型
```python
from mmcv.runner import BaseModule, ModuleList
class FooModel(BaseModule)
def __init__(self,
arg1,
arg2,
init_cfg=None):
super(FooModel, self).__init__(init_cfg)
...
self.conv1 = ModuleList(init_cfg=XXX)
```
- 使⽤配置⽂件中的 `init_cfg` 初始化模型
```python
model = dict(
...
model = dict(
type='FooModel',
arg1=XXX,
arg2=XXX,
init_cfg=XXX),
...
```
### init_cfg 的使用
1.`layer` 键初始化模型
如果我们只定义了 `layer`, 它只会在 `layer` 键中初始化网络层。
注意: `layer` 键对应的值是 Pytorch 的带有 weights 和 bias 属性的类名(因此不⽀持 `MultiheadAttention` 层)。
- 定义⽤于初始化具有相同配置的模块的 `layer` 键。
```python
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d', 'Linear'], val=1)
# ⽤相同的配置初始化整个模块
```
- 定义⽤于初始化具有不同配置的层的 `layer` 键。
```python
init_cfg = [dict(type='Constant', layer='Conv1d', val=1),
dict(type='Constant', layer='Conv2d', val=2),
dict(type='Constant', layer='Linear', val=3)]
# nn.Conv1d 将被初始化为 dict(type='Constant', val=1)
# nn.Conv2d 将被初始化为 dict(type='Constant', val=2)
# nn.Linear 将被初始化为 dict(type='Constant', val=3)
```
2. 使⽤ `override` 键初始化模型
- 当使⽤属性名初始化某些特定部分时,我们可以使⽤ `override` 键, `override` 中的值将忽略 init_cfg 中的值。
```python
# layers:
# self.feat = nn.Conv1d(3, 1, 3)
# self.reg = nn.Conv2d(3, 3, 3)
# self.cls = nn.Linear(1,2)
init_cfg = dict(type='Constant',
layer=['Conv1d','Conv2d'], val=1, bias=2,
override=dict(type='Constant', name='reg', val=3, bias=4))
# self.feat and self.cls 将被初始化为 dict(type='Constant', val=1, bias=2)
# 叫 'reg' 的模块将被初始化为 dict(type='Constant', val=3, bias=4)
```
- 如果 init_cfg 中的 `layer` 为 None,则只会初始化 override 中有 name 的⼦模块,⽽ override 中的 type 和其他参数可以省略。
```python
# layers:
# self.feat = nn.Conv1d(3, 1, 3)
# self.reg = nn.Conv2d(3, 3, 3)
# self.cls = nn.Linear(1,2)
init_cfg = dict(type='Constant', val=1, bias=2, override=dict(name='reg'))
# self.feat and self.cls 将被 Pytorch 初始化
# 叫 'reg' 的模块将被 dict(type='Constant', val=1, bias=2) 初始化
```
- 如果我们不定义 `layer``override` 键,它不会初始化任何东西。
- 无效的使用
```python
# override 没有 name 键的话是无效的
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2,
override=dict(type='Constant', val=3, bias=4))
# override 有 name 键和其他参数但是没有 type 键也是无效的
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2,
override=dict(name='reg', val=3, bias=4))
```
3. 使⽤预训练模型初始化模型
```python
init_cfg = dict(type='Pretrained',
checkpoint='torchvision://resnet50')
```
更多细节可以参考 [MMEngine](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/initialize.html) 的文档
# 使用 MMDetection 和 Label-Studio 进行半自动化目标检测标注
标注数据是一个费时费力的任务,本文介绍了如何使用 MMDetection 中的 RTMDet 算法联合 Label-Studio 软件进行半自动化标注。具体来说,使用 RTMDet 预测图片生成标注,然后使用 Label-Studio 进行微调标注,社区用户可以参考此流程和方法,将其应用到其他领域。
- RTMDet:RTMDet 是 OpenMMLab 自研的高精度单阶段的目标检测算法,开源于 MMDetection 目标检测工具箱中,其开源协议为 Apache 2.0,工业界的用户可以不受限的免费使用。
- [Label Studio](https://github.com/heartexlabs/label-studio) 是一款优秀的标注软件,覆盖图像分类、目标检测、分割等领域数据集标注的功能。
本文将使用[喵喵数据集](https://download.openmmlab.com/mmyolo/data/cat_dataset.zip)的图片,进行半自动化标注。
## 环境配置
首先需要创建一个虚拟环境,然后安装 PyTorch 和 MMCV。在本文中,我们将指定 PyTorch 和 MMCV 的版本。接下来安装 MMDetection、Label-Studio 和 label-studio-ml-backend,具体步骤如下:
创建虚拟环境:
```shell
conda create -n rtmdet python=3.9 -y
conda activate rtmdet
```
安装 PyTorch
```shell
# Linux and Windows CPU only
pip install torch==1.10.1+cpu torchvision==0.11.2+cpu torchaudio==0.10.1 -f https://download.pytorch.org/whl/cpu/torch_stable.html
# Linux and Windows CUDA 11.3
pip install torch==1.10.1+cu113 torchvision==0.11.2+cu113 torchaudio==0.10.1 -f https://download.pytorch.org/whl/cu113/torch_stable.html
# OSX
pip install torch==1.10.1 torchvision==0.11.2 torchaudio==0.10.1
```
安装 MMCV
```shell
pip install -U openmim
mim install "mmcv>=2.0.0"
# 安装 mmcv 的过程中会自动安装 mmengine
```
安装 MMDetection
```shell
git clone https://github.com/open-mmlab/mmdetection
cd mmdetection
pip install -v -e .
```
安装 Label-Studio 和 label-studio-ml-backend
```shell
# 安装 label-studio 需要一段时间,如果找不到版本请使用官方源
pip install label-studio==1.7.2
pip install label-studio-ml==1.0.9
```
下载rtmdet权重
```shell
cd path/to/mmetection
mkdir work_dirs
cd work_dirs
wget https://download.openmmlab.com/mmdetection/v3.0/rtmdet/rtmdet_m_8xb32-300e_coco/rtmdet_m_8xb32-300e_coco_20220719_112220-229f527c.pth
```
## 启动服务
启动 RTMDet 后端推理服务:
```shell
cd path/to/mmetection
label-studio-ml start projects/LabelStudio/backend_template --with \
config_file=configs/rtmdet/rtmdet_m_8xb32-300e_coco.py \
checkpoint_file=./work_dirs/rtmdet_m_8xb32-300e_coco_20220719_112220-229f527c.pth \
device=cpu \
--port 8003
# device=cpu 为使用 CPU 推理,如果使用 GPU 推理,将 cpu 替换为 cuda:0
```
![](https://cdn.vansin.top/picgo20230330131601.png)
此时,RTMDet 后端推理服务已经启动,后续在 Label-Studio Web 系统中配置 http://localhost:8003 后端推理服务即可。
现在启动 Label-Studio 网页服务:
```shell
label-studio start
```
![](https://cdn.vansin.top/picgo20230330132913.png)
打开浏览器访问 [http://localhost:8080/](http://localhost:8080/) 即可看到 Label-Studio 的界面。
![](https://cdn.vansin.top/picgo20230330133118.png)
我们注册一个用户,然后创建一个 RTMDet-Semiautomatic-Label 项目。
![](https://cdn.vansin.top/picgo20230330133333.png)
我们通过下面的方式下载好示例的喵喵图片,点击 Data Import 导入需要标注的猫图片。
```shell
cd path/to/mmetection
mkdir data && cd data
wget https://download.openmmlab.com/mmyolo/data/cat_dataset.zip && unzip cat_dataset.zip
```
![](https://cdn.vansin.top/picgo20230330133628.png)
![](https://cdn.vansin.top/picgo20230330133715.png)
然后选择 Object Detection With Bounding Boxes 模板
![](https://cdn.vansin.top/picgo20230330133807.png)
```shell
airplane
apple
backpack
banana
baseball_bat
baseball_glove
bear
bed
bench
bicycle
bird
boat
book
bottle
bowl
broccoli
bus
cake
car
carrot
cat
cell_phone
chair
clock
couch
cow
cup
dining_table
dog
donut
elephant
fire_hydrant
fork
frisbee
giraffe
hair_drier
handbag
horse
hot_dog
keyboard
kite
knife
laptop
microwave
motorcycle
mouse
orange
oven
parking_meter
person
pizza
potted_plant
refrigerator
remote
sandwich
scissors
sheep
sink
skateboard
skis
snowboard
spoon
sports_ball
stop_sign
suitcase
surfboard
teddy_bear
tennis_racket
tie
toaster
toilet
toothbrush
traffic_light
train
truck
tv
umbrella
vase
wine_glass
zebra
```
然后将上述类别复制添加到 Label-Studio,然后点击 Save。
![](https://cdn.vansin.top/picgo20230330134027.png)
然后在设置中点击 Add Model 添加 RTMDet 后端推理服务。
![](https://cdn.vansin.top/picgo20230330134320.png)
点击 Validate and Save,然后点击 Start Labeling。
![](https://cdn.vansin.top/picgo20230330134424.png)
看到如下 Connected 就说明后端推理服务添加成功。
![](https://cdn.vansin.top/picgo20230330134554.png)
## 开始半自动化标注
点击 Label 开始标注
![](https://cdn.vansin.top/picgo20230330134804.png)
我们可以看到 RTMDet 后端推理服务已经成功返回了预测结果并显示在图片上,我们可以发现这个喵喵预测的框有点大。
![](https://cdn.vansin.top/picgo20230403104419.png)
我们手工拖动框,修正一下框的位置,得到以下修正过后的标注,然后点击 Submit,本张图片就标注完毕了。
![](https://cdn.vansin.top/picgo/20230403105923.png)
我们 submit 完毕所有图片后,点击 exprot 导出 COCO 格式的数据集,就能把标注好的数据集的压缩包导出来了。
![](https://cdn.vansin.top/picgo20230330135921.png)
用 vscode 打开解压后的文件夹,可以看到标注好的数据集,包含了图片和 json 格式的标注文件。
![](https://cdn.vansin.top/picgo20230330140321.png)
到此半自动化标注就完成了,我们可以用这个数据集在 MMDetection 训练精度更高的模型了,训练出更好的模型,然后再用这个模型继续半自动化标注新采集的图片,这样就可以不断迭代,扩充高质量数据集,提高模型的精度。
## 使用 MMYOLO 作为后端推理服务
如果想在 MMYOLO 中使用 Label-Studio,可以参考在启动后端推理服务时,将 config_file 和 checkpoint_file 替换为 MMYOLO 的配置文件和权重文件即可。
```shell
cd path/to/mmetection
label-studio-ml start projects/LabelStudio/backend_template --with \
config_file= path/to/mmyolo_config.py \
checkpoint_file= path/to/mmyolo_weights.pth \
device=cpu \
--port 8003
# device=cpu 为使用 CPU 推理,如果使用 GPU 推理,将 cpu 替换为 cuda:0
```
旋转目标检测和实例分割还在支持中,敬请期待。
# 在标准数据集上训练自定义模型(待更新)
在本文中,你将知道如何在标准数据集上训练、测试和推理自定义模型。我们将在 cityscapes 数据集上以自定义 Cascade Mask R-CNN R50 模型为例演示整个过程,为了方便说明,我们将 neck 模块中的 `FPN` 替换为 `AugFPN`,并且在训练中的自动增强类中增加 `Rotate``TranslateX`
基本步骤如下所示:
1. 准备标准数据集
2. 准备你的自定义模型
3. 准备配置文件
4. 在标准数据集上对模型进行训练、测试和推理
## 准备标准数据集
在本文中,我们使用 cityscapes 标准数据集为例进行说明。
推荐将数据集根路径采用符号链接方式链接到 `$MMDETECTION/data`
如果你的文件结构不同,你可能需要在配置文件中进行相应的路径更改。标准的文件组织格式如下所示:
```none
mmdetection
├── mmdet
├── tools
├── configs
├── data
│ ├── coco
│ │ ├── annotations
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ ├── cityscapes
│ │ ├── annotations
│ │ ├── leftImg8bit
│ │ │ ├── train
│ │ │ ├── val
│ │ ├── gtFine
│ │ │ ├── train
│ │ │ ├── val
│ ├── VOCdevkit
│ │ ├── VOC2007
│ │ ├── VOC2012
```
你也可以通过如下方式设定数据集根路径
```bash
export MMDET_DATASETS=$data_root
```
我们将会使用环境便变量 `$MMDET_DATASETS` 作为数据集的根目录,因此你无需再修改相应配置文件的路径信息。
你需要使用脚本 `tools/dataset_converters/cityscapes.py` 将 cityscapes 标注转化为 coco 标注格式。
```shell
pip install cityscapesscripts
python tools/dataset_converters/cityscapes.py ./data/cityscapes --nproc 8 --out-dir ./data/cityscapes/annotations
```
目前在 `cityscapes `文件夹中的配置文件所对应模型是采用 COCO 预训练权重进行初始化的。
如果你的网络不可用或者比较慢,建议你先手动下载对应的预训练权重,否则可能在训练开始时候出现错误。
## 准备你的自定义模型
第二步是准备你的自定义模型或者训练相关配置。假设你想在已有的 Cascade Mask R-CNN R50 检测模型基础上,新增一个新的 neck 模块 `AugFPN` 去代替默认的 `FPN`,以下是具体实现:
### 1 定义新的 neck (例如 AugFPN)
首先创建新文件 `mmdet/models/necks/augfpn.py`.
```python
import torch.nn as nn
from mmdet.registry import MODELS
@MODELS.register_module()
class AugFPN(nn.Module):
def __init__(self,
in_channels,
out_channels,
num_outs,
start_level=0,
end_level=-1,
add_extra_convs=False):
pass
def forward(self, inputs):
# implementation is ignored
pass
```
### 2 导入模块
你可以采用两种方式导入模块,第一种是在 `mmdet/models/necks/__init__.py` 中添加如下内容
```python
from .augfpn import AugFPN
```
第二种是增加如下代码到对应配置中,这种方式的好处是不需要改动代码
```python
custom_imports = dict(
imports=['mmdet.models.necks.augfpn'],
allow_failed_imports=False)
```
### 3 修改配置
```python
neck=dict(
type='AugFPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
num_outs=5)
```
关于自定义模型其余相关细节例如实现新的骨架网络,头部网络、损失函数,以及运行时训练配置例如定义新的优化器、使用梯度裁剪、定制训练调度策略和钩子等,请参考文档 [自定义模型](tutorials/customize_models.md)[自定义运行时训练配置](tutorials/customize_runtime.md)
## 准备配置文件
第三步是准备训练配置所需要的配置文件。假设你打算基于 cityscapes 数据集,在 Cascade Mask R-CNN R50 中新增 `AugFPN` 模块,同时增加 `Rotate` 或者 `Translate` 数据增强策略,假设你的配置文件位于 `configs/cityscapes/` 目录下,并且取名为 `cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes.py`,则配置信息如下:
```python
# 继承 base 配置,然后进行针对性修改
_base_ = [
'../_base_/models/cascade-mask-rcnn_r50_fpn.py',
'../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py'
]
model = dict(
# 设置 `init_cfg` 为 None,表示不加载 ImageNet 预训练权重,
# 后续可以设置 `load_from` 参数用来加载 COCO 预训练权重
backbone=dict(init_cfg=None),
# 使用新增的 `AugFPN` 模块代替默认的 `FPN`
neck=dict(
type='AugFPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
num_outs=5),
# 我们也需要将 num_classes 从 80 修改为 8 来匹配 cityscapes 数据集标注
# 这个修改包括 `bbox_head` 和 `mask_head`.
roi_head=dict(
bbox_head=[
dict(
type='Shared2FCBBoxHead',
in_channels=256,
fc_out_channels=1024,
roi_feat_size=7,
# 将 COCO 类别修改为 cityscapes 类别
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=True,
loss_cls=dict(
type='CrossEntropyLoss',
use_sigmoid=False,
loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0,
loss_weight=1.0)),
dict(
type='Shared2FCBBoxHead',
in_channels=256,
fc_out_channels=1024,
roi_feat_size=7,
# 将 COCO 类别修改为 cityscapes 类别
num_classes=8,
bbox_coder=dict(
type='DeltaXYWHBBoxCoder',
target_means=[0., 0., 0., 0.],
target_stds=[0.05, 0.05, 0.1, 0.1]),
reg_class_agnostic=True,
loss_cls=dict(
type='CrossEntropyLoss',
use_sigmoid=False,
loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0,
loss_weight=1.0)),
dict(
type='Shared2FCBBoxHead',
in_channels=256,
fc_out_channels=1024,
roi_feat_size=7,
# 将 COCO 类别修改为 cityscapes 类别
num_classes=8,
bbox_coder=dict(
type='DeltaXYWHBBoxCoder',
target_means=[0., 0., 0., 0.],
target_stds=[0.033, 0.033, 0.067, 0.067]),
reg_class_agnostic=True,
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,
# 将 COCO 类别修改为 cityscapes 类别
num_classes=8,
loss_mask=dict(
type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))))
# 覆写 `train_pipeline`,然后新增 `AutoAugment` 训练配置
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True, with_mask=True),
dict(
type='AutoAugment',
policies=[
[dict(
type='Rotate',
level=5,
img_border_value=(124, 116, 104),
prob=0.5)
],
[dict(type='Rotate', level=7, img_border_value=(124, 116, 104)),
dict(
type='TranslateX',
level=5,
prob=0.5,
img_border_value=(124, 116, 104))
],
]),
dict(
type='RandomResize',
scale=[(2048, 800), (2048, 1024)],
keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(type='PackDetInputs'),
]
# 设置每张显卡的批处理大小,同时设置新的训练 pipeline
data = dict(
samples_per_gpu=1,
workers_per_gpu=3,
train=dict(dataset=dict(pipeline=train_pipeline)))
# 设置优化器
optim_wrapper = dict(
type='OptimWrapper',
optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001))
# 设置定制的学习率策略
param_scheduler = [
dict(
type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500),
dict(
type='MultiStepLR',
begin=0,
end=10,
by_epoch=True,
milestones=[8],
gamma=0.1)
]
# 训练,验证,测试配置
train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=10, val_interval=1)
val_cfg = dict(type='ValLoop')
test_cfg = dict(type='TestLoop')
# 我们采用 COCO 预训练过的 Cascade Mask R-CNN R50 模型权重作为初始化权重,可以得到更加稳定的性能
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco/cascade_mask_rcnn_r50_fpn_1x_coco_20200203-9d4dcb24.pth'
```
## 训练新模型
为了能够使用新增配置来训练模型,你可以运行如下命令:
```shell
python tools/train.py configs/cityscapes/cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes.py
```
如果想了解更多用法,可以参考 [例子1](1_exist_data_model.md)
## 测试和推理
为了能够测试训练好的模型,你可以运行如下命令:
```shell
python tools/test.py configs/cityscapes/cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes.py work_dirs/cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes/epoch_10.pth
```
如果想了解更多用法,可以参考 [例子1](1_exist_data_model.md)
# 检测器鲁棒性检查
## 介绍
我们提供了在 [Benchmarking Robustness in Object Detection: Autonomous Driving when Winter is Coming](https://arxiv.org/abs/1907.07484) 中定义的「图像损坏基准测试」上测试目标检测和实例分割模型的工具。
此页面提供了如何使用该基准测试的基本教程。
```latex
@article{michaelis2019winter,
title={Benchmarking Robustness in Object Detection:
Autonomous Driving when Winter is Coming},
author={Michaelis, Claudio and Mitzkus, Benjamin and
Geirhos, Robert and Rusak, Evgenia and
Bringmann, Oliver and Ecker, Alexander S. and
Bethge, Matthias and Brendel, Wieland},
journal={arXiv:1907.07484},
year={2019}
}
```
![image corruption example](../../../resources/corruptions_sev_3.png)
## 关于基准测试
要将结果提交到基准测试,请访问[基准测试主页](https://github.com/bethgelab/robust-detection-benchmark)
基准测试是仿照 [imagenet-c 基准测试](https://github.com/hendrycks/robustness),由 Dan Hendrycks 和 Thomas Dietterich 在[Benchmarking Neural Network Robustness to Common Corruptions and Perturbations](https://arxiv.org/abs/1903.12261)(ICLR 2019)中发表。
图像损坏变换功能包含在此库中,但可以使用以下方法单独安装:
```shell
pip install imagecorruptions
```
与 imagenet-c 相比,我们必须进行一些更改以处理任意大小的图像和灰度图像。
我们还修改了“运动模糊”和“雪”损坏,以解除对于 linux 特定库的依赖,
否则必须单独安装这些库。有关详细信息,请参阅 [imagecorruptions](https://github.com/bethgelab/imagecorruptions)
## 使用预训练模型进行推理
我们提供了一个测试脚本来评估模型在基准测试中提供的各种损坏变换组合下的性能。
### 在数据集上测试
- [x] 单张 GPU 测试
- [ ] 多张 GPU 测试
- [ ] 可视化检测结果
您可以使用以下命令在基准测试中使用 15 种损坏变换来测试模型性能。
```shell
# single-gpu testing
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}]
```
也可以选择其它不同类型的损坏变换。
```shell
# noise
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --corruptions noise
# blur
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --corruptions blur
# wetaher
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --corruptions weather
# digital
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --corruptions digital
```
或者使用一组自定义的损坏变换,例如:
```shell
# gaussian noise, zoom blur and snow
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --corruptions gaussian_noise zoom_blur snow
```
最后,我们也可以选择施加在图像上的损坏变换的严重程度。
严重程度从 1 到 5 逐级增强,0 表示不对图像施加损坏变换,即原始图像数据。
```shell
# severity 1
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --severities 1
# severities 0,2,4
python tools/analysis_tools/test_robustness.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] --severities 0 2 4
```
## 模型测试结果
下表是各模型在 COCO 2017val 上的测试结果。
| Model | Backbone | Style | Lr schd | box AP clean | box AP corr. | box % | mask AP clean | mask AP corr. | mask % |
| :-----------------: | :-----------------: | :-----: | :-----: | :----------: | :----------: | :---: | :-----------: | :-----------: | :----: |
| Faster R-CNN | R-50-FPN | pytorch | 1x | 36.3 | 18.2 | 50.2 | - | - | - |
| Faster R-CNN | R-101-FPN | pytorch | 1x | 38.5 | 20.9 | 54.2 | - | - | - |
| Faster R-CNN | X-101-32x4d-FPN | pytorch | 1x | 40.1 | 22.3 | 55.5 | - | - | - |
| Faster R-CNN | X-101-64x4d-FPN | pytorch | 1x | 41.3 | 23.4 | 56.6 | - | - | - |
| Faster R-CNN | R-50-FPN-DCN | pytorch | 1x | 40.0 | 22.4 | 56.1 | - | - | - |
| Faster R-CNN | X-101-32x4d-FPN-DCN | pytorch | 1x | 43.4 | 26.7 | 61.6 | - | - | - |
| Mask R-CNN | R-50-FPN | pytorch | 1x | 37.3 | 18.7 | 50.1 | 34.2 | 16.8 | 49.1 |
| Mask R-CNN | R-50-FPN-DCN | pytorch | 1x | 41.1 | 23.3 | 56.7 | 37.2 | 20.7 | 55.7 |
| Cascade R-CNN | R-50-FPN | pytorch | 1x | 40.4 | 20.1 | 49.7 | - | - | - |
| Cascade Mask R-CNN | R-50-FPN | pytorch | 1x | 41.2 | 20.7 | 50.2 | 35.7 | 17.6 | 49.3 |
| RetinaNet | R-50-FPN | pytorch | 1x | 35.6 | 17.8 | 50.1 | - | - | - |
| Hybrid Task Cascade | X-101-64x4d-FPN-DCN | pytorch | 1x | 50.6 | 32.7 | 64.7 | 43.8 | 28.1 | 64.0 |
由于对图像的损坏变换存在随机性,测试结果可能略有不同。
# 半监督目标检测
半监督目标检测同时利用标签数据和无标签数据进行训练,一方面可以减少模型对检测框数量的依赖,另一方面也可以利用大量的未标记数据进一步提高模型。
按照以下流程进行半监督目标检测:
- [半监督目标检测](#半监督目标检测)
- [准备和拆分数据集](#准备和拆分数据集)
- [配置多分支数据流程](#配置多分支数据流程)
- [配置半监督数据加载](#配置半监督数据加载)
- [配置半监督模型](#配置半监督模型)
- [配置MeanTeacherHook](#配置meanteacherhook)
- [配置TeacherStudentValLoop](#配置teacherstudentvalloop)
## 准备和拆分数据集
我们提供了数据集下载脚本,默认下载 coco2017 数据集,并且自动解压。
```shell
python tools/misc/download_dataset.py
```
解压后的数据集目录如下:
```plain
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── image_info_unlabeled2017.json
│ │ │ ├── instances_train2017.json
│ │ │ ├── instances_val2017.json
│ │ ├── test2017
│ │ ├── train2017
│ │ ├── unlabeled2017
│ │ ├── val2017
```
半监督目标检测在 coco 数据集上有两种比较通用的实验设置:
(1)将 `train2017` 按照固定百分比(1%,2%,5% 和 10%)划分出一部分数据作为标签数据集,剩余的训练集数据作为无标签数据集,同时考虑划分不同的训练集数据作为标签数据集对半监督训练的结果影响较大,所以采用五折交叉验证来评估算法性能。我们提供了数据集划分脚本:
```shell
python tools/misc/split_coco.py
```
该脚本默认会按照 1%,2%,5% 和 10% 的标签数据占比划分 `train2017`,每一种划分会随机重复 5 次,用于交叉验证。生成的半监督标注文件名称格式如下:
- 标签数据集标注名称格式:`instances_train2017.{fold}@{percent}.json`
- 无标签数据集名称标注:`instances_train2017.{fold}@{percent}-unlabeled.json`
其中,`fold` 用于交叉验证,`percent` 表示标签数据的占比。 划分后的数据集目录结构如下:
```plain
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── image_info_unlabeled2017.json
│ │ │ ├── instances_train2017.json
│ │ │ ├── instances_val2017.json
│ │ ├── semi_anns
│ │ │ ├── instances_train2017.1@1.json
│ │ │ ├── instances_train2017.1@1-unlabeled.json
│ │ │ ├── instances_train2017.1@2.json
│ │ │ ├── instances_train2017.1@2-unlabeled.json
│ │ │ ├── instances_train2017.1@5.json
│ │ │ ├── instances_train2017.1@5-unlabeled.json
│ │ │ ├── instances_train2017.1@10.json
│ │ │ ├── instances_train2017.1@10-unlabeled.json
│ │ │ ├── instances_train2017.2@1.json
│ │ │ ├── instances_train2017.2@1-unlabeled.json
│ │ ├── test2017
│ │ ├── train2017
│ │ ├── unlabeled2017
│ │ ├── val2017
```
(2)将 `train2017` 作为标签数据集,`unlabeled2017` 作为无标签数据集。由于 `image_info_unlabeled2017.json` 没有 `categories` 信息,无法初始化 `CocoDataset` ,所以需要将 `instances_train2017.json``categories` 写入 `image_info_unlabeled2017.json` ,另存为 `instances_unlabeled2017.json`,相关脚本如下:
```python
from mmengine.fileio import load, dump
anns_train = load('instances_train2017.json')
anns_unlabeled = load('image_info_unlabeled2017.json')
anns_unlabeled['categories'] = anns_train['categories']
dump(anns_unlabeled, 'instances_unlabeled2017.json')
```
处理后的数据集目录如下:
```plain
mmdetection
├── data
│ ├── coco
│ │ ├── annotations
│ │ │ ├── image_info_unlabeled2017.json
│ │ │ ├── instances_train2017.json
│ │ │ ├── instances_unlabeled2017.json
│ │ │ ├── instances_val2017.json
│ │ ├── test2017
│ │ ├── train2017
│ │ ├── unlabeled2017
│ │ ├── val2017
```
## 配置多分支数据流程
半监督学习有两个主要的方法,分别是
[一致性正则化](https://research.nvidia.com/sites/default/files/publications/laine2017iclr_paper.pdf)
[伪标签](https://www.researchgate.net/profile/Dong-Hyun-Lee/publication/280581078_Pseudo-Label_The_Simple_and_Efficient_Semi-Supervised_Learning_Method_for_Deep_Neural_Networks/links/55bc4ada08ae092e9660b776/Pseudo-Label-The-Simple-and-Efficient-Semi-Supervised-Learning-Method-for-Deep-Neural-Networks.pdf)
一致性正则化往往需要一些精心的设计,而伪标签的形式比较简单,更容易拓展到下游任务。我们主要采用了基于伪标签的教师学生联合训练的半监督目标检测框架,对于标签数据和无标签数据需要配置不同的数据流程:
(1)标签数据的数据流程:
```python
# pipeline used to augment labeled data,
# which will be sent to student model for supervised training.
sup_pipeline = [
dict(type='LoadImageFromFile',backend_args = backend_args),
dict(type='LoadAnnotations', with_bbox=True),
dict(type='RandomResize', scale=scale, keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(type='RandAugment', aug_space=color_space, aug_num=1),
dict(type='FilterAnnotations', min_gt_bbox_wh=(1e-2, 1e-2)),
dict(type='MultiBranch', sup=dict(type='PackDetInputs'))
]
```
(2)无标签的数据流程:
```python
# pipeline used to augment unlabeled data weakly,
# which will be sent to teacher model for predicting pseudo instances.
weak_pipeline = [
dict(type='RandomResize', scale=scale, keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(
type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor', 'flip', 'flip_direction',
'homography_matrix')),
]
# pipeline used to augment unlabeled data strongly,
# which will be sent to student model for unsupervised training.
strong_pipeline = [
dict(type='RandomResize', scale=scale, keep_ratio=True),
dict(type='RandomFlip', prob=0.5),
dict(
type='RandomOrder',
transforms=[
dict(type='RandAugment', aug_space=color_space, aug_num=1),
dict(type='RandAugment', aug_space=geometric, aug_num=1),
]),
dict(type='RandomErasing', n_patches=(1, 5), ratio=(0, 0.2)),
dict(type='FilterAnnotations', min_gt_bbox_wh=(1e-2, 1e-2)),
dict(
type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor', 'flip', 'flip_direction',
'homography_matrix')),
]
# pipeline used to augment unlabeled data into different views
unsup_pipeline = [
dict(type='LoadImageFromFile', backend_args = backend_args),
dict(type='LoadEmptyAnnotations'),
dict(
type='MultiBranch',
unsup_teacher=weak_pipeline,
unsup_student=strong_pipeline,
)
]
```
## 配置半监督数据加载
(1)构建半监督数据集。使用 `ConcatDataset` 拼接标签数据集和无标签数据集。
```python
labeled_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=sup_pipeline)
unlabeled_dataset = dict(
type=dataset_type,
data_root=data_root,
ann_file='annotations/instances_unlabeled2017.json',
data_prefix=dict(img='unlabeled2017/'),
filter_cfg=dict(filter_empty_gt=False),
pipeline=unsup_pipeline)
train_dataloader = dict(
batch_size=batch_size,
num_workers=num_workers,
persistent_workers=True,
sampler=dict(
type='GroupMultiSourceSampler',
batch_size=batch_size,
source_ratio=[1, 4]),
dataset=dict(
type='ConcatDataset', datasets=[labeled_dataset, unlabeled_dataset]))
```
(2)使用多源数据集采样器。 使用 `GroupMultiSourceSampler``labeled_dataset``labeled_dataset` 采样数据组成 batch , `source_ratio` 控制 batch 中标签数据和无标签数据的占比。`GroupMultiSourceSampler` 还保证了同一个 batch 中的图片具有相近的长宽比例,如果不需要保证batch内图片的长宽比例,可以使用 `MultiSourceSampler``GroupMultiSourceSampler` 采样示意图如下:
<div align=center>
<img src="https://user-images.githubusercontent.com/40661020/186149261-8cf28e92-de5c-4c8c-96e1-13558b2e27f7.jpg"/>
</div>
`sup=1000` 表示标签数据集的规模为 1000 ,`sup_h=200` 表示标签数据集中长宽比大于等于1的图片规模为 200,`sup_w=800` 表示标签数据集中长宽比小于1的图片规模为 800 ,`unsup=9000` 表示无标签数据集的规模为 9000 ,`unsup_h=1800` 表示无标签数据集中长宽比大于等于1的图片规模为 1800,`unsup_w=7200` 表示标签数据集中长宽比小于1的图片规模为 7200 ,`GroupMultiSourceSampler` 每次按照标签数据集和无标签数据集的图片的总体长宽比分布随机选择一组,然后按照 `source_ratio` 从两个数据集中采样组成 batch ,因此标签数据集和无标签数据集重复采样次数不同。
## 配置半监督模型
我们选择 `Faster R-CNN` 作为 `detector` 进行半监督训练,以半监督目标检测算法 `SoftTeacher` 为例,模型的配置可以继承 `_base_/models/faster-rcnn_r50_fpn.py`,将检测器的骨干网络替换成 `caffe` 风格。
注意,与监督训练的配置文件不同的是,`Faster R-CNN` 作为 `detector`,是作为 `model`的一个属性,而不是 `model` 。此外,还需要将`data_preprocessor`设置为`MultiBranchDataPreprocessor`,用于处理不同数据流程图片的填充和归一化。
最后,可以通过 `semi_train_cfg``semi_test_cfg` 配置半监督训练和测试需要的参数。
```python
_base_ = [
'../_base_/models/faster-rcnn_r50_fpn.py', '../_base_/default_runtime.py',
'../_base_/datasets/semi_coco_detection.py'
]
detector = _base_.model
detector.data_preprocessor = dict(
type='DetDataPreprocessor',
mean=[103.530, 116.280, 123.675],
std=[1.0, 1.0, 1.0],
bgr_to_rgb=False,
pad_size_divisor=32)
detector.backbone = dict(
type='ResNet',
depth=50,
num_stages=4,
out_indices=(0, 1, 2, 3),
frozen_stages=1,
norm_cfg=dict(type='BN', requires_grad=False),
norm_eval=True,
style='caffe',
init_cfg=dict(
type='Pretrained',
checkpoint='open-mmlab://detectron2/resnet50_caffe'))
model = dict(
_delete_=True,
type='SoftTeacher',
detector=detector,
data_preprocessor=dict(
type='MultiBranchDataPreprocessor',
data_preprocessor=detector.data_preprocessor),
semi_train_cfg=dict(
freeze_teacher=True,
sup_weight=1.0,
unsup_weight=4.0,
pseudo_label_initial_score_thr=0.5,
rpn_pseudo_thr=0.9,
cls_pseudo_thr=0.9,
reg_pseudo_thr=0.02,
jitter_times=10,
jitter_scale=0.06,
min_pseudo_bbox_wh=(1e-2, 1e-2)),
semi_test_cfg=dict(predict_on='teacher'))
```
此外,我们也支持其他检测模型进行半监督训练,比如,`RetinaNet``Cascade R-CNN`。由于 `SoftTeacher` 仅支持 `Faster R-CNN`,所以需要将其替换为 `SemiBaseDetector`,示例如下:
```python
_base_ = [
'../_base_/models/retinanet_r50_fpn.py', '../_base_/default_runtime.py',
'../_base_/datasets/semi_coco_detection.py'
]
detector = _base_.model
model = dict(
_delete_=True,
type='SemiBaseDetector',
detector=detector,
data_preprocessor=dict(
type='MultiBranchDataPreprocessor',
data_preprocessor=detector.data_preprocessor),
semi_train_cfg=dict(
freeze_teacher=True,
sup_weight=1.0,
unsup_weight=1.0,
cls_pseudo_thr=0.9,
min_pseudo_bbox_wh=(1e-2, 1e-2)),
semi_test_cfg=dict(predict_on='teacher'))
```
沿用 `SoftTeacher` 的半监督训练配置,将 `batch_size` 改为 2 ,`source_ratio` 改为 `[1, 1]``RetinaNet``Faster R-CNN``Cascade R-CNN` 以及 `SoftTeacher` 在 10% coco 训练集上的监督训练和半监督训练的实验结果如下:
| Model | Detector | BackBone | Style | sup-0.1-coco mAP | semi-0.1-coco mAP |
| :--------------: | :-----------: | :------: | :---: | :--------------: | :---------------: |
| SemiBaseDetector | RetinaNet | R-50-FPN | caffe | 23.5 | 27.7 |
| SemiBaseDetector | Faster R-CNN | R-50-FPN | caffe | 26.7 | 28.4 |
| SemiBaseDetector | Cascade R-CNN | R-50-FPN | caffe | 28.0 | 29.7 |
| SoftTeacher | Faster R-CNN | R-50-FPN | caffe | 26.7 | 31.1 |
## 配置MeanTeacherHook
通常,教师模型采用对学生模型指数滑动平均(EMA)的方式进行更新,进而教师模型随着学生模型的优化而优化,可以通过配置 `custom_hooks` 实现:
```python
custom_hooks = [dict(type='MeanTeacherHook')]
```
## 配置TeacherStudentValLoop
由于教师学生联合训练框架存在两个模型,我们可以用 `TeacherStudentValLoop` 替换 `ValLoop`,在训练的过程中同时检验两个模型的精度。
```python
val_cfg = dict(type='TeacherStudentValLoop')
```
# 将单阶段检测器作为 RPN
候选区域网络 (Region Proposal Network, RPN) 作为 [Faster R-CNN](https://arxiv.org/abs/1506.01497) 的一个子模块,将为 Faster R-CNN 的第二阶段产生候选区域。在 MMDetection 里大多数的二阶段检测器使用 [`RPNHead`](../../../mmdet/models/dense_heads/rpn_head.py)作为候选区域网络来产生候选区域。然而,任何的单阶段检测器都可以作为候选区域网络,是因为他们对边界框的预测可以被视为是一种候选区域,并且因此能够在 R-CNN 中得到改进。因此在 MMDetection v3.0 中会支持将单阶段检测器作为 RPN 使用。
接下来我们通过一个例子,即如何在 [Faster R-CNN](../../../configs/faster_rcnn/faster-rcnn_r50_fpn_fcos-rpn_1x_coco.py) 中使用一个无锚框的单阶段的检测器模型 [FCOS](../../../configs/fcos/fcos_r50-caffe_fpn_gn-head_1x_coco.py) 作为 RPN ,详细阐述具体的全部流程。
主要流程如下:
1. 在 Faster R-CNN 中使用 `FCOSHead` 作为 `RPNHead`
2. 评估候选区域
3. 用预先训练的 FCOS 训练定制的 Faster R-CNN
## 在 Faster R-CNN 中使用 `FCOSHead` 作为` RPNHead`
为了在 Faster R-CNN 中使用 `FCOSHead` 作为 `RPNHead` ,我们应该创建一个名为 `configs/faster_rcnn/faster-rcnn_r50_fpn_fcos-rpn_1x_coco.py` 的配置文件,并且在 `configs/faster_rcnn/faster-rcnn_r50_fpn_fcos-rpn_1x_coco.py` 中将 `rpn_head` 的设置替换为 `bbox_head` 的设置,此外我们仍然使用 FCOS 的瓶颈设置,步幅为`[8,16,32,64,128]`,并且更新 `bbox_roi_extractor``featmap_stride`` [8,16,32,64,128]`。为了避免损失变慢,我们在前1000次迭代而不是前500次迭代中应用预热,这意味着 lr 增长得更慢。相关配置如下:
```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(
# 从 configs/fcos/fcos_r50-caffe_fpn_gn-head_1x_coco.py 复制
neck=dict(
start_level=1,
add_extra_convs='on_output', # 使用 P5
relu_before_extra_convs=True),
rpn_head=dict(
_delete_=True, # 忽略未使用的旧设置
type='FCOSHead',
num_classes=1, # 对于 rpn, num_classes = 1,如果 num_classes > 1,它将在 TwoStageDetector 中自动设置为1
in_channels=256,
stacked_convs=4,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)),
roi_head=dict( # featmap_strides 的更新取决于于颈部的步伐
bbox_roi_extractor=dict(featmap_strides=[8, 16, 32, 64, 128])))
# 学习率
param_scheduler = [
dict(
type='LinearLR', start_factor=0.001, by_epoch=False, begin=0,
end=1000), # 慢慢增加 lr,否则损失变成 NAN
dict(
type='MultiStepLR',
begin=0,
end=12,
by_epoch=True,
milestones=[8, 11],
gamma=0.1)
]
```
然后,我们可以使用下面的命令来训练我们的定制模型。更多训练命令,请参考[这里](train.md)
```python
# 使用8个 GPU 进行训练
bash
tools/dist_train.sh
configs/faster_rcnn/faster-rcnn_r50_fpn_fcos-rpn_1x_coco.py
--work-dir /work_dirs/faster-rcnn_r50_fpn_fcos-rpn_1x_coco
```
## 评估候选区域
候选区域的质量对检测器的性能有重要影响,因此,我们也提供了一种评估候选区域的方法。和上面一样创建一个新的名为 `configs/rpn/fcos-rpn_r50_fpn_1x_coco.py` 的配置文件,并且在 `configs/rpn/fcos-rpn_r50_fpn_1x_coco.py` 中将 `rpn_head` 的设置替换为 `bbox_head` 的设置。
```python
_base_ = [
'../_base_/models/rpn_r50_fpn.py', '../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
val_evaluator = dict(metric='proposal_fast')
test_evaluator = val_evaluator
model = dict(
# 从 configs/fcos/fcos_r50-caffe_fpn_gn-head_1x_coco.py 复制
neck=dict(
start_level=1,
add_extra_convs='on_output', # 使用 P5
relu_before_extra_convs=True),
rpn_head=dict(
_delete_=True, # 忽略未使用的旧设置
type='FCOSHead',
num_classes=1, # 对于 rpn, num_classes = 1,如果 num_classes >为1,它将在 rpn 中自动设置为1
in_channels=256,
stacked_convs=4,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)))
```
假设我们在训练之后有检查点 `./work_dirs/faster-rcnn_r50_fpn_fcos-rpn_1x_coco/epoch_12.pth` ,然后,我们可以使用下面的命令来评估建议的质量。
```python
# 使用8个 GPU 进行测试
bash
tools/dist_test.sh
configs/rpn/fcos-rpn_r50_fpn_1x_coco.py
--work_dirs /faster-rcnn_r50_fpn_fcos-rpn_1x_coco/epoch_12.pth
```
## 用预先训练的 FCOS 训练定制的 Faster R-CNN
预训练不仅加快了训练的收敛速度,而且提高了检测器的性能。因此,我们在这里给出一个例子来说明如何使用预先训练的 FCOS 作为 RPN 来加速训练和提高精度。假设我们想在 Faster R-CNN 中使用 `FCOSHead` 作为 `rpn_head`,并加载预先训练权重来进行训练 [`fcos_r50-caffe_fpn_gn-head_1x_coco`](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco/fcos_r50_caffe_fpn_gn-head_1x_coco-821213aa.pth)。 配置文件 `configs/faster_rcnn/faster-rcnn_r50-caffe_fpn_fcos- rpn_1x_copy .py` 的内容如下所示。注意,`fcos_r50-caffe_fpn_gn-head_1x_coco` 使用 ResNet50 的 caffe 版本,因此需要更新 `data_preprocessor` 中的像素平均值和 std。
```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(
data_preprocessor=dict(
mean=[103.530, 116.280, 123.675],
std=[1.0, 1.0, 1.0],
bgr_to_rgb=False),
backbone=dict(
norm_cfg=dict(type='BN', requires_grad=False),
style='caffe',
init_cfg=None), # the checkpoint in ``load_from`` contains the weights of backbone
neck=dict(
start_level=1,
add_extra_convs='on_output', # 使用 P5
relu_before_extra_convs=True),
rpn_head=dict(
_delete_=True, # 忽略未使用的旧设置
type='FCOSHead',
num_classes=1, # 对于 rpn, num_classes = 1,如果 num_classes > 1,它将在 TwoStageDetector 中自动设置为1
in_channels=256,
stacked_convs=4,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)),
roi_head=dict( # update featmap_strides due to the strides in neck
bbox_roi_extractor=dict(featmap_strides=[8, 16, 32, 64, 128])))
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco/fcos_r50_caffe_fpn_gn-head_1x_coco-821213aa.pth'
```
训练命令如下。
```python
bash
tools/dist_train.sh
configs/faster_rcnn/faster-rcnn_r50-caffe_fpn_fcos-rpn_1x_coco.py \
--work-dir /work_dirs/faster-rcnn_r50-caffe_fpn_fcos-rpn_1x_coco
```
# 测试现有模型
我们提供了测试脚本,能够测试一个现有模型在所有数据集(COCO,Pascal VOC,Cityscapes 等)上的性能。我们支持在如下环境下测试:
- 单 GPU 测试
- CPU 测试
- 单节点多 GPU 测试
- 多节点测试
根据以上测试环境,选择合适的脚本来执行测试过程。
```shell
# 单 GPU 测试
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--out ${RESULT_FILE}] \
[--show]
# CPU 测试:禁用 GPU 并运行单 GPU 测试脚本
export CUDA_VISIBLE_DEVICES=-1
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--out ${RESULT_FILE}] \
[--show]
# 单节点多 GPU 测试
bash tools/dist_test.sh \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
${GPU_NUM} \
[--out ${RESULT_FILE}]
```
`tools/dist_test.sh` 也支持多节点测试,不过需要依赖 PyTorch 的 [启动工具](https://pytorch.org/docs/stable/distributed.html#launch-utility)
可选参数:
- `RESULT_FILE`: 结果文件名称,需以 .pkl 形式存储。如果没有声明,则不将结果存储到文件。
- `--show`: 如果开启,检测结果将被绘制在图像上,以一个新窗口的形式展示。它只适用于单 GPU 的测试,是用于调试和可视化的。请确保使用此功能时,你的 GUI 可以在环境中打开。否则,你可能会遇到这么一个错误 `cannot connect to X server`
- `--show-dir`: 如果指明,检测结果将会被绘制在图像上并保存到指定目录。它只适用于单 GPU 的测试,是用于调试和可视化的。即使你的环境中没有 GUI,这个选项也可使用。
- `--cfg-options`: 如果指明,这里的键值对将会被合并到配置文件中。
### 样例
假设你已经下载了 checkpoint 文件到 `checkpoints/` 文件下了。
1. 测试 RTMDet 并可视化其结果。按任意键继续下张图片的测试。配置文件和 checkpoint 文件 [在此](https://github.com/open-mmlab/mmdetection/tree/main/configs/rtmdet)
```shell
python tools/test.py \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth \
--show
```
2. 测试 RTMDet,并为了之后的可视化保存绘制的图像。配置文件和 checkpoint 文件 [在此](https://github.com/open-mmlab/mmdetection/tree/main/configs/rtmdet)
```shell
python tools/test.py \
configs/rtmdet/rtmdet_l_8xb32-300e_coco.py \
checkpoints/rtmdet_l_8xb32-300e_coco_20220719_112030-5a0be7c4.pth \
--show-dir rtmdet_l_8xb32-300e_coco_results
```
3. 在 Pascal VOC 数据集上测试 Faster R-CNN,不保存测试结果,测试 `mAP`。配置文件和 checkpoint 文件 [在此](../../../configs/pascal_voc)
```shell
python tools/test.py \
configs/pascal_voc/faster-rcnn_r50_fpn_1x_voc0712.py \
checkpoints/faster_rcnn_r50_fpn_1x_voc0712_20200624-c9895d40.pth
```
4. 使用 8 块 GPU 测试 Mask R-CNN,测试 `bbox``mAP` 。配置文件和 checkpoint 文件 [在此](../../../configs/mask_rcnn)
```shell
./tools/dist_test.sh \
configs/mask-rcnn_r50_fpn_1x_coco.py \
checkpoints/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth \
8 \
--out results.pkl
```
5. 使用 8 块 GPU 测试 Mask R-CNN,测试**每类**`bbox``mAP`。配置文件和 checkpoint 文件 [在此](../../../configs/mask_rcnn)
```shell
./tools/dist_test.sh \
configs/mask_rcnn/mask-rcnn_r50_fpn_1x_coco.py \
checkpoints/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth \
8
```
该命令生成两个JSON文件 `./work_dirs/coco_instance/test.bbox.json``./work_dirs/coco_instance/test.segm.json`
6. 在 COCO test-dev 数据集上,使用 8 块 GPU 测试 Mask R-CNN,并生成 JSON 文件提交到官方评测服务器,配置文件和 checkpoint 文件 [在此](../../../configs/mask_rcnnn) 。你可以在 [config](./././configs/_base_/datasets/coco_instance.py) 的注释中用 test_evaluator 和 test_dataloader 替换原来的 test_evaluator 和 test_dataloader,然后运行:
```shell
./tools/dist_test.sh \
configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py \
checkpoints/mask_rcnn_r50_fpn_1x_cityscapes_20200227-afe51d5a.pth \
8
```
这行命令生成两个 JSON 文件 `mask_rcnn_test-dev_results.bbox.json``mask_rcnn_test-dev_results.segm.json`
7. 在 Cityscapes 数据集上,使用 8 块 GPU 测试 Mask R-CNN,生成 txt 和 png 文件,并上传到官方评测服务器。配置文件和 checkpoint 文件 [在此](../../../configs/cityscapes) 。 你可以在 [config](./././configs/_base_/datasets/cityscapes_instance.py) 的注释中用 test_evaluator 和 test_dataloader 替换原来的 test_evaluator 和 test_dataloader,然后运行:
```shell
./tools/dist_test.sh \
configs/cityscapes/mask-rcnn_r50_fpn_1x_cityscapes.py \
checkpoints/mask_rcnn_r50_fpn_1x_cityscapes_20200227-afe51d5a.pth \
8
```
生成的 png 和 txt 文件在 `./work_dirs/cityscapes_metric` 文件夹下。
### 不使用 Ground Truth 标注进行测试
MMDetection 支持在不使用 ground-truth 标注的情况下对模型进行测试,这需要用到 `CocoDataset`。如果你的数据集格式不是 COCO 格式的,请将其转化成 COCO 格式。如果你的数据集格式是 VOC 或者 Cityscapes,你可以使用 [tools/dataset_converters](https://github.com/open-mmlab/mmdetection/tree/main/tools/dataset_converters) 内的脚本直接将其转化成 COCO 格式。如果是其他格式,可以使用 [images2coco 脚本](https://github.com/open-mmlab/mmdetection/tree/master/tools/dataset_converters/images2coco.py) 进行转换。
```shell
python tools/dataset_converters/images2coco.py \
${IMG_PATH} \
${CLASSES} \
${OUT} \
[--exclude-extensions]
```
参数:
- `IMG_PATH`: 图片根路径。
- `CLASSES`: 类列表文本文件名。文本中每一行存储一个类别。
- `OUT`: 输出 json 文件名。 默认保存目录和 `IMG_PATH` 在同一级。
- `exclude-extensions`: 待排除的文件后缀名。
在转换完成后,使用如下命令进行测试
```shell
# 单 GPU 测试
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--show]
# CPU 测试:禁用 GPU 并运行单 GPU 测试脚本
export CUDA_VISIBLE_DEVICES=-1
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--out ${RESULT_FILE}] \
[--show]
# 单节点多 GPU 测试
bash tools/dist_test.sh \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
${GPU_NUM} \
[--show]
```
假设 [model zoo](https://mmdetection.readthedocs.io/en/latest/modelzoo_statistics.html) 中的 checkpoint 文件被下载到了 `checkpoints/` 文件夹下,
我们可以使用以下命令,用 8 块 GPU 在 COCO test-dev 数据集上测试 Mask R-CNN,并且生成 JSON 文件。
```sh
./tools/dist_test.sh \
configs/mask_rcnn/mask-rcnn_r50_fpn_1x_coco.py \
checkpoints/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth \
8
```
这行命令生成两个 JSON 文件 `./work_dirs/coco_instance/test.bbox.json``./work_dirs/coco_instance/test.segm.json`
### 批量推理
MMDetection 在测试模式下,既支持单张图片的推理,也支持对图像进行批量推理。默认情况下,我们使用单张图片的测试,你可以通过修改测试数据配置文件中的 `samples_per_gpu` 来开启批量测试。
开启批量推理的配置文件修改方法为:
```shell
data = dict(train_dataloader=dict(...), val_dataloader=dict(...), test_dataloader=dict(batch_size=2, ...))
```
或者你可以通过将 `--cfg-options` 设置为 `--cfg-options test_dataloader.batch_size=` 来开启它。
## 测试时增强 (TTA)
测试时增强 (TTA) 是一种在测试阶段使用的数据增强策略。它对同一张图片应用不同的增强,例如翻转和缩放,用于模型推理,然后将每个增强后的图像的预测结果合并,以获得更准确的预测结果。为了让用户更容易使用 TTA,MMEngine 提供了 [BaseTTAModel](https://mmengine.readthedocs.io/en/latest/api/generated/mmengine.model.BaseTTAModel.html#mmengine.model.BaseTTAModel) 类,允许用户根据自己的需求通过简单地扩展 BaseTTAModel 类来实现不同的 TTA 策略。
在 MMDetection 中,我们提供了 [DetTTAModel](../../../mmdet/models/test_time_augs/det_tta.py) 类,它继承自 BaseTTAModel。
### 使用案例
使用 TTA 需要两个步骤。首先,你需要在配置文件中添加 `tta_model``tta_pipeline`
```shell
tta_model = dict(
type='DetTTAModel',
tta_cfg=dict(nms=dict(
type='nms',
iou_threshold=0.5),
max_per_img=100))
tta_pipeline = [
dict(type='LoadImageFromFile',
backend_args=None),
dict(
type='TestTimeAug',
transforms=[[
dict(type='Resize', scale=(1333, 800), keep_ratio=True)
], [ # It uses 2 flipping transformations (flipping and not flipping).
dict(type='RandomFlip', prob=1.),
dict(type='RandomFlip', prob=0.)
], [
dict(
type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape',
'img_shape', 'scale_factor', 'flip',
'flip_direction'))
]])]
```
第二步,运行测试脚本时,设置 `--tta` 参数,如下所示:
```shell
# 单 GPU 测试
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--tta]
# CPU 测试:禁用 GPU 并运行单 GPU 测试脚本
export CUDA_VISIBLE_DEVICES=-1
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
[--out ${RESULT_FILE}] \
[--tta]
# 多 GPU 测试
bash tools/dist_test.sh \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
${GPU_NUM} \
[--tta]
```
你也可以自己修改 TTA 配置,例如添加缩放增强:
```shell
tta_model = dict(
type='DetTTAModel',
tta_cfg=dict(nms=dict(
type='nms',
iou_threshold=0.5),
max_per_img=100))
img_scales = [(1333, 800), (666, 400), (2000, 1200)]
tta_pipeline = [
dict(type='LoadImageFromFile',
backend_args=None),
dict(
type='TestTimeAug',
transforms=[[
dict(type='Resize', scale=s, keep_ratio=True) for s in img_scales
], [
dict(type='RandomFlip', prob=1.),
dict(type='RandomFlip', prob=0.)
], [
dict(
type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape',
'img_shape', 'scale_factor', 'flip',
'flip_direction'))
]])]
```
以上数据增强管道将首先对图像执行 3 个多尺度转换,然后执行 2 个翻转转换(翻转和不翻转),最后使用 PackDetInputs 将图像打包到最终结果中。
这里有更多的 TTA 使用案例供您参考:
- [RetinaNet](../../../configs/retinanet/retinanet_tta.py)
- [CenterNet](../../../configs/centernet/centernet_tta.py)
- [YOLOX](../../../configs/rtmdet/rtmdet_tta.py)
- [RTMDet](../../../configs/yolox/yolox_tta.py)
更多高级用法和 TTA 的数据流,请参考 [MMEngine](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/test_time_augmentation.html#data-flow)。我们将在后续支持实例分割 TTA。
# 提交测试结果
## 全景分割测试结果提交
下面几节介绍如何在 COCO 测试开发集上生成泛视分割模型的预测结果,并将预测提交到 [COCO评估服务器](https://competitions.codalab.org/competitions/19507)
### 前提条件
- 下载 [COCO测试数据集图像](http://images.cocodataset.org/zips/test2017.zip)[测试图像信息](http://images.cocodataset.org/annotations/image_info_test2017.zip),和[全景训练/相关注释](http://images.cocodataset.org/annotations/panoptic_annotations_trainval2017.zip),然后解压缩它们,把 `test2017` 放到 `data/coco/`,把 json 文件和注释文件放到 `data/coco/annotations/`
```shell
# 假设 data/coco/ 不存在
mkdir -pv data/coco/
# 下载 test2017
wget -P data/coco/ http://images.cocodataset.org/zips/test2017.zip
wget -P data/coco/ http://images.cocodataset.org/annotations/image_info_test2017.zip
wget -P data/coco/ http://images.cocodataset.org/annotations/panoptic_annotations_trainval2017.zip
# 解压缩它们
unzip data/coco/test2017.zip -d data/coco/
unzip data/coco/image_info_test2017.zip -d data/coco/
unzip data/coco/panoptic_annotations_trainval2017.zip -d data/coco/
# 删除 zip 文件(可选)
rm -rf data/coco/test2017.zip data/coco/image_info_test2017.zip data/coco/panoptic_annotations_trainval2017.zip
```
- 运行以下代码更新测试图像信息中的类别信息。由于 `image_info_test-dev2017.json` 的类别信息中缺少属性 `isthing` ,我们需要用 `panoptic_val2017.json` 中的类别信息更新它。
```shell
python tools/misc/gen_coco_panoptic_test_info.py data/coco/annotations
```
在完成上述准备之后,你的 `data` 目录结构应该是这样:
```text
data
`-- coco
|-- annotations
| |-- image_info_test-dev2017.json
| |-- image_info_test2017.json
| |-- panoptic_image_info_test-dev2017.json
| |-- panoptic_train2017.json
| |-- panoptic_train2017.zip
| |-- panoptic_val2017.json
| `-- panoptic_val2017.zip
`-- test2017
```
### coco 测试开发的推理
要在 coco test-dev 上进行推断,我们应该首先更新 `test_dataloder``test_evaluator` 的设置。有两种方法可以做到这一点:1. 在配置文件中更新它们;2. 在命令行中更新它们。
#### 在配置文件中更新它们
相关的设置在 `configs/_base_/datasets/ coco_panoptical .py` 的末尾,如下所示。
```python
test_dataloader = dict(
batch_size=1,
num_workers=1,
persistent_workers=True,
drop_last=False,
sampler=dict(type='DefaultSampler', shuffle=False),
dataset=dict(
type=dataset_type,
data_root=data_root,
ann_file='annotations/panoptic_image_info_test-dev2017.json',
data_prefix=dict(img='test2017/'),
test_mode=True,
pipeline=test_pipeline))
test_evaluator = dict(
type='CocoPanopticMetric',
format_only=True,
ann_file=data_root + 'annotations/panoptic_image_info_test-dev2017.json',
outfile_prefix='./work_dirs/coco_panoptic/test')
```
以下任何一种方法都可以用于更新 coco test-dev 集上的推理设置
情况1:直接取消注释 `configs/_base_/datasets/ coco_panoptical .py` 中的设置。
情况2:将以下设置复制到您现在使用的配置文件中。
```python
test_dataloader = dict(
dataset=dict(
ann_file='annotations/panoptic_image_info_test-dev2017.json',
data_prefix=dict(img='test2017/', _delete_=True)))
test_evaluator = dict(
format_only=True,
ann_file=data_root + 'annotations/panoptic_image_info_test-dev2017.json',
outfile_prefix='./work_dirs/coco_panoptic/test')
```
然后通过以下命令对 coco test-dev et 进行推断。
```shell
python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE}
```
#### 在命令行中更新它们
coco test-dev 上更新相关设置和推理的命令如下所示。
```shell
# 用一个 gpu 测试
CUDA_VISIBLE_DEVICES=0 python tools/test.py \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
--cfg-options \
test_dataloader.dataset.ann_file=annotations/panoptic_image_info_test-dev2017.json \
test_dataloader.dataset.data_prefix.img=test2017 \
test_dataloader.dataset.data_prefix._delete_=True \
test_evaluator.format_only=True \
test_evaluator.ann_file=data/coco/annotations/panoptic_image_info_test-dev2017.json \
test_evaluator.outfile_prefix=${WORK_DIR}/results
# 用四个 gpu 测试
CUDA_VISIBLE_DEVICES=0,1,3,4 bash tools/dist_test.sh \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
8 \ # eights gpus
--cfg-options \
test_dataloader.dataset.ann_file=annotations/panoptic_image_info_test-dev2017.json \
test_dataloader.dataset.data_prefix.img=test2017 \
test_dataloader.dataset.data_prefix._delete_=True \
test_evaluator.format_only=True \
test_evaluator.ann_file=data/coco/annotations/panoptic_image_info_test-dev2017.json \
test_evaluator.outfile_prefix=${WORK_DIR}/results
# 用 slurm 测试
GPUS=8 tools/slurm_test.sh \
${Partition} \
${JOB_NAME} \
${CONFIG_FILE} \
${CHECKPOINT_FILE} \
--cfg-options \
test_dataloader.dataset.ann_file=annotations/panoptic_image_info_test-dev2017.json \
test_dataloader.dataset.data_prefix.img=test2017 \
test_dataloader.dataset.data_prefix._delete_=True \
test_evaluator.format_only=True \
test_evaluator.ann_file=data/coco/annotations/panoptic_image_info_test-dev2017.json \
test_evaluator.outfile_prefix=${WORK_DIR}/results
```
例子:假设我们使用预先训练的带有 ResNet-50 骨干网的 MaskFormer 对 `test2017` 执行推断。
```shell
# 单 gpu 测试
CUDA_VISIBLE_DEVICES=0 python tools/test.py \
configs/maskformer/maskformer_r50_mstrain_16x1_75e_coco.py \
checkpoints/maskformer_r50_mstrain_16x1_75e_coco_20220221_141956-bc2699cb.pth \
--cfg-options \
test_dataloader.dataset.ann_file=annotations/panoptic_image_info_test-dev2017.json \
test_dataloader.dataset.data_prefix.img=test2017 \
test_dataloader.dataset.data_prefix._delete_=True \
test_evaluator.format_only=True \
test_evaluator.ann_file=data/coco/annotations/panoptic_image_info_test-dev2017.json \
test_evaluator.outfile_prefix=work_dirs/maskformer/results
```
### 重命名文件并压缩结果
推理之后,全景分割结果(一个 json 文件和一个存储掩码的目录)将在 `WORK_DIR` 中。我们应该按照 [COCO's Website](https://cocodataset.org/#upload)上的命名约定重新命名它们。最后,我们需要将 json 和存储掩码的目录压缩到 zip 文件中,并根据命名约定重命名该 zip 文件。注意, zip 文件应该**直接**包含上述两个文件。
重命名文件和压缩结果的命令:
```shell
# 在 WORK_DIR 中,我们有 panoptic 分割结果: 'panoptic' 和 'results. panoptical .json'。
cd ${WORK_DIR}
# 将 '[algorithm_name]' 替换为您使用的算法名称
mv ./panoptic ./panoptic_test-dev2017_[algorithm_name]_results
mv ./results.panoptic.json ./panoptic_test-dev2017_[algorithm_name]_results.json
zip panoptic_test-dev2017_[algorithm_name]_results.zip -ur panoptic_test-dev2017_[algorithm_name]_results panoptic_test-dev2017_[algorithm_name]_results.json
```
**我们在 `tools/` 目录下提供了很多有用的工具。**
## MOT 测试时参数搜索
`tools/analysis_tools/mot/mot_param_search.py` 可以搜索 MOT 模型中 `tracker` 的参数。
它与 `tools/test.py` 的使用方式相同,但配置上**有所不同**
下面是修改配置的示例:
1. 定义要记录的期望评估指标。
例如,你可以将 `evaluator` 定义为:
```python
test_evaluator=dict(type='MOTChallengeMetrics', metric=['HOTA', 'CLEAR', 'Identity'])
```
当然,你也可以自定义 `test_evaluator``metric` 的内容。你可以自由选择 `['HOTA', 'CLEAR', 'Identity']` 中的一个或多个指标。
2. 定义要搜索的参数及其取值。
假设你有一个 `tracker` 的配置如下:
```python
model=dict(
tracker=dict(
type='BaseTracker',
obj_score_thr=0.5,
match_iou_thr=0.5
)
)
```
如果你想要搜索 `tracker` 的参数,只需将其值改为一个列表,如下所示:
```python
model=dict(
tracker=dict(
type='BaseTracker',
obj_score_thr=[0.4, 0.5, 0.6],
match_iou_thr=[0.4, 0.5, 0.6, 0.7]
)
)
```
然后,脚本将测试一共12种情况并且记录结果。
## MOT 误差可视化
`tools/analysis_tools/mot/mot_error_visualize.py` 可以为多目标跟踪可视化错误。
该脚本需要推断的结果作为输入。默认情况下,**红色**边界框表示误检(false positive),**黄色**边界框表示漏检(false negative),**蓝色**边界框表示ID切换(ID switch)。
```
python tools/analysis_tools/mot/mot_error_visualize.py \
${CONFIG_FILE}\
--input ${INPUT} \
--result-dir ${RESULT_DIR} \
[--output-dir ${OUTPUT}] \
[--fps ${FPS}] \
[--show] \
[--backend ${BACKEND}]
```
`RESULT_DIR` 中包含了所有视频的推断结果,推断结果是一个 `txt` 文件。
可选参数:
- `OUTPUT`:可视化演示的输出。如果未指定,`--show` 是必选的,用于即时显示视频。
- `FPS`:输出视频的帧率。
- `--show`:是否即时显示视频。
- `BACKEND`:用于可视化边界框的后端。选项包括 `cv2``plt`
## 浏览数据集
`tools/analysis_tools/mot/browse_dataset.py` 可以可视化训练数据集,以检查数据集配置是否正确。
**示例:**
```shell
python tools/analysis_tools/browse_dataset.py ${CONFIG_FILE} [--show-interval ${SHOW_INTERVAL}]
```
可选参数:
- `SHOW_INTERVAL`: 显示的间隔时间(秒)。
- `--show`: 是否即时显示图像。
# 学习更多与配置相关的事
我们用 python 文档作为我们的配置系统。你可以在 `MMDetection/configs` 底下找到所有已提供的配置文件。
我们把模块化和继承化设计融入我们的配置系统,这使我们很方便去进行各种实验。如果你想查看相关的配置文件,你可以跑 `python tools/misc/print_config.py /PATH/TO/CONFIG` 去看完整的详细配置。
## 完整配置的简要说明
一个完整的配置通常包含以下主要的字段:
`model`:一个模型的基本配置,包含 `data_preprocessor``detector``motion` 之类的模块,还有 `train_cfg``test_cfg` 等等;
`train_dataloader`:训练数据集的配置,通常包含 `batch_size``num_workers``sampler``dataset` 等等;
`val_dataloader`:验证数据集的配置,与训练数据集的配置类似;
`test_dataloader`:测试数据集的配置,与训练数据集的配置类似;
`val_evaluator`:验证评估器的配置,例如 `type='MOTChallengeMetrics'` 是 MOT 任务里面的测量标准;
`test_evaluator`:测试评估器的配置,与验证评估器的配置类似;
`train_cfg`:训练循环的配置,例如 `type='EpochBasedTrainLoop'`
`val_cfg`:验证循环的配置,例如 `type='VideoValLoop'`
`test_cfg`:测试循环的配置,例如 `type='VideoTestLoop'`
`default_hooks`:默认鱼钩的配置,包含计时器、日志、参数调度程序、检查点、样本种子、可视化;
`vis_backends`:可视化后端的配置,默认使用 `type='LocalVisBackend'`
`visualizer`:可视化工具的配置,例如MOT任务使用 `type='TrackLocalVisualizer'`
`param_scheduler`:参数调度程序的配置,通常里面设置学习率调度程序;
`optim_wrapper`:优化器封装的配置,包含优化相关的信息,例如优化器、梯度剪裁等;
`load_from`:加载预训练模型的路径;
`resume`:布尔值,如果是 `True` ,会从 `load_from` 加载模型的检查点,训练会恢复至检查点的迭代次数。
## 通过脚本参数修改配置
当使用 `tools/train.py``tools/test_trackin.py` 执行任务时,可以指定 `--cfg-options` 来就地修改配置。我们举几个例子如下。有关更多详细信息,请参阅[MMEngine](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)
### 更新 dict 链的配置键
可以按照原始配置中 `dict` 键的顺序指定配置选项,例如,设置 `--cfg-options model.detector.backbone.norm_eval=False` 会将模型主干中的所有 `BN` 模块更改为训练模式。
### 更新配置列表中的关键字
一些配置的 `dict` 关键字会以列表的形式组成,例如,测试管道中的 `test_dataloader.dataset.pipeline` 以列表形式出现,即 `[dict(type='LoadImageFromFile'), ...]`。如果你想在测试管道中将 `LoadImageFromFile` 更改为 `LoadImageFromWebcam`,可以设置 `--cfg-options test_dataloader.dataset.pipeline.0.type=LoadImageFromWebcam`
### 更新列表/元组的值
要被更新的可能是一个列表或一个元组,例如,你可以通过指定 `--cfg options model.data_processor.mean=[0,0,0]` 来更改 `data_preprocessor` 的平均值的关键字。请注意,指定值内不允许有空格。
## 配置文件结构
`config/_base_` 下有三种基本组件类型,即数据集、模型和默认运行时间。可以用它们来轻松构建许多方法,例如 `SORT``DeepSORT`。由 `_base_` 中的组件组成的配置称为基元。
对于同一文件夹下的配置文件,建议只有一个基元配置文件。其他配置文件都应该从基元配置文件继承基本结构,这样,继承级别的最大值为 3。
为了便于理解,我们建议贡献者继承现有的方法。例如,如果在 `Faster R-CNN` 的基础上进行了一些修改,用户可以首先通过指定 `_base_ = ../_base_/models/faster-rcnn_r50-dc5.py` 来继承基本的 `Faster R-CNN` 结构,然后修改配置文件中的必要字段。
如果你正在构建一个与任何现有方法都不共享结构的全新方法,则可以在 `configs` 下创建一个新文件夹 method_name。
有关详细文档,请参阅[MMEngine](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)
## 配置命名风格
我们根据以下风格去命名配置文件,建议贡献者遵从相同风格。
`{method}_{module}_{train_cfg}_{train_data}_{test_data}`
`{method}`: 方法名称,例如 `sort`
`{module}`: 方法的基本模块,例如 `faster-rcnn_r50_fpn`
`{train_cfg}`: 训练配置通常包含批量大小、迭代次数等,例如 `8xb4-80e`
`{train_data}`: 训练数据集,例如 `mot17halftrain`
`{test_data}`: 测试数据集,例如 `test-mot17halfval`
## 常问问题
### 忽略基本配置中的某些字段
有时候你可以设置 `_delete_=True` 去忽略基本配置中的一些字段,你可以参考[MMEngine](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html)进行简单说明。
### 跟踪数据结构介绍
#### 优点和新功能
`mmdetection` 跟踪任务中,我们使用视频来组织数据集,并使用 `TrackDataSample` 来描述数据集信息。
基于视频组织,我们提供了 `transform UniformRefFrameSample` 来对关键帧和参考帧进行采样,并使用 `TransformBroadcaster` 进行剪辑训练。
在某种程度上,`TrackDataSample` 可以被视为多个 `DetDataSample` 的包装器。它包含一个 `video_data_samples`,这是一个以 `DetDataSample` 组成的列表,里面每个 `DetDataSample` 对应一个帧。此外,它的元信息包括关键帧的索引和参考帧的索引,用与剪辑训练。
得益于基于视频的数据组织,整个视频可以直接被测试。这种方式更简洁直观。如果你的 GPU 内存无法容纳整个视频,我们还提供基于图像的测试方法。
## 要做的事
`StrongSORT``Mask2Former` 等算法不支持基于视频的测试,这些算法对 GPU 内存提出了挑战,我们将来会优化这个问题。
现在,我们不支持像 `MOT Challenge dataset` 这样的基于视频的数据集和像 `Crowdhuman` 用于 `QDTrack` 算法这样的基于图像的数据集进行联合训练。我们将来会优化这个问题。
## 数据集准备
本页面提供了现有基准数据集的准备说明,包括:
- 多目标跟踪
- [MOT Challenge](https://motchallenge.net/)
- [CrowdHuman](https://www.crowdhuman.org/)
- 视频实例分割
- [YouTube-VIS](https://youtube-vos.org/dataset/vis/)
### 1. 下载数据集
请从官方网站下载数据集,并将数据集的根目录建立软链接到 `$MMDETECTION/data` 目录下。
#### 1.1 多目标跟踪
- 对于多目标跟踪任务的训练和测试,需要下载MOT Challenge数据集之一(例如MOT17、MOT20),CrowdHuman数据集可以作为补充数据集。
- 对于中国的用户,可以从 [OpenDataLab](https://opendatalab.com/) 上高速下载如下数据集:
- [MOT17](https://opendatalab.com/MOT17/download)
- [MOT20](https://opendatalab.com/MOT20/download)
- [CrowdHuman](https://opendatalab.com/CrowdHuman/download)
#### 1.2 视频实例分割
- 对于视频实例分割任务的训练和测试,只需要选择一个YouTube-VIS数据集(例如YouTube-VIS 2019、YouTube-VIS 2021)即可。
- 可以从 [YouTubeVOS](https://codalab.lisn.upsaclay.fr/competitions/6064) 上下载YouTube-VIS 2019数据集。
- 可以从 [YouTubeVOS](https://codalab.lisn.upsaclay.fr/competitions/7680) 上下载YouTube-VIS 2021数据集。
#### 1.3 数据结构
如果您的文件夹结构与以下结构不同,则可能需要在配置文件中更改相应的路径。
```
mmdetection
├── mmdet
├── tools
├── configs
├── data
│ ├── coco
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ │ ├── annotations
│ │
| ├── MOT15/MOT16/MOT17/MOT20
| | ├── train
| | | ├── MOT17-02-DPM
| | | | ├── det
| │ │ │ ├── gt
| │ │ │ ├── img1
| │ │ │ ├── seqinfo.ini
│ │ │ ├── ......
| | ├── test
| | | ├── MOT17-01-DPM
| | | | ├── det
| │ │ │ ├── img1
| │ │ │ ├── seqinfo.ini
│ │ │ ├── ......
│ │
│ ├── crowdhuman
│ │ ├── annotation_train.odgt
│ │ ├── annotation_val.odgt
│ │ ├── train
│ │ │ ├── Images
│ │ │ ├── CrowdHuman_train01.zip
│ │ │ ├── CrowdHuman_train02.zip
│ │ │ ├── CrowdHuman_train03.zip
│ │ ├── val
│ │ │ ├── Images
│ │ │ ├── CrowdHuman_val.zip
│ │
```
### 2. 转换注释
在这种情况下,您需要将官方注释(Annotations)转换为COCO格式。我们提供了相应的脚本,使用方法如下:
```shell
# MOT17
# 其他 MOT Challenge 数据集的处理方式与 MOT17 相同。
python ./tools/dataset_converters/mot2coco.py -i ./data/MOT17/ -o ./data/MOT17/annotations --split-train --convert-det
python ./tools/dataset_converters/mot2reid.py -i ./data/MOT17/ -o ./data/MOT17/reid --val-split 0.2 --vis-threshold 0.3
# CrowdHuman
python ./tools/dataset_converters/crowdhuman2coco.py -i ./data/crowdhuman -o ./data/crowdhuman/annotations
# YouTube-VIS 2019
python ./tools/dataset_converters/youtubevis/youtubevis2coco.py -i ./data/youtube_vis_2019 -o ./data/youtube_vis_2019/annotations --version 2019
# YouTube-VIS 2021
python ./tools/dataset_converters/youtubevis/youtubevis2coco.py -i ./data/youtube_vis_2021 -o ./data/youtube_vis_2021/annotations --version 2021
```
运行这些脚本后,文件夹结构将如下所示:
```
mmdetection
├── mmtrack
├── tools
├── configs
├── data
│ ├── coco
│ │ ├── train2017
│ │ ├── val2017
│ │ ├── test2017
│ │ ├── annotations
│ │
| ├── MOT15/MOT16/MOT17/MOT20
| | ├── train
| | | ├── MOT17-02-DPM
| | | | ├── det
| │ │ │ ├── gt
| │ │ │ ├── img1
| │ │ │ ├── seqinfo.ini
│ │ │ ├── ......
| | ├── test
| | | ├── MOT17-01-DPM
| | | | ├── det
| │ │ │ ├── img1
| │ │ │ ├── seqinfo.ini
│ │ │ ├── ......
| | ├── annotations
| | ├── reid
│ │ │ ├── imgs
│ │ │ ├── meta
│ │
│ ├── crowdhuman
│ │ ├── annotation_train.odgt
│ │ ├── annotation_val.odgt
│ │ ├── train
│ │ │ ├── Images
│ │ │ ├── CrowdHuman_train01.zip
│ │ │ ├── CrowdHuman_train02.zip
│ │ │ ├── CrowdHuman_train03.zip
│ │ ├── val
│ │ │ ├── Images
│ │ │ ├── CrowdHuman_val.zip
│ │ ├── annotations
│ │ │ ├── crowdhuman_train.json
│ │ │ ├── crowdhuman_val.json
│ │
│ ├── youtube_vis_2019
│ │ │── train
│ │ │ │── JPEGImages
│ │ │ │── ......
│ │ │── valid
│ │ │ │── JPEGImages
│ │ │ │── ......
│ │ │── test
│ │ │ │── JPEGImages
│ │ │ │── ......
│ │ │── train.json (the official annotation files)
│ │ │── valid.json (the official annotation files)
│ │ │── test.json (the official annotation files)
│ │ │── annotations (the converted annotation file)
│ │
│ ├── youtube_vis_2021
│ │ │── train
│ │ │ │── JPEGImages
│ │ │ │── instances.json (the official annotation files)
│ │ │ │── ......
│ │ │── valid
│ │ │ │── JPEGImages
│ │ │ │── instances.json (the official annotation files)
│ │ │ │── ......
│ │ │── test
│ │ │ │── JPEGImages
│ │ │ │── instances.json (the official annotation files)
│ │ │ │── ......
│ │ │── annotations (the converted annotation file)
```
#### MOT15/MOT16/MOT17/MOT20中的注释和reid文件夹
以 MOT17 数据集为例,其他数据集的结构类似。
`data/MOT17/annotations` 文件夹中有8个JSON文件:
`train_cocoformat.json`: 包含MOT17数据集训练集的注释信息的JSON文件。
`train_detections.pkl`: 包含MOT17数据集训练集的公共检测结果的Pickle文件。
`test_cocoformat.json`: 包含MOT17数据集测试集的注释信息的JSON文件。
`test_detections.pkl`: 包含MOT17数据集测试集的公共检测结果的Pickle文件。
`half-train_cocoformat.json``half-train_detections.pkl``half-val_cocoformat.json``half-val_detections.pkl``train_cocoformat.json``train_detections.pkl` 具有类似的含义。`half` 表示将训练集中的每个视频分成两半。前一半的视频被标记为 `half-train` 集,后一半的视频被标记为 `half-val` 集。
`data/MOT17/reid` 文件夹的结构如下所示:
```
reid
├── imgs
│ ├── MOT17-02-FRCNN_000002
│ │ ├── 000000.jpg
│ │ ├── 000001.jpg
│ │ ├── ...
│ ├── MOT17-02-FRCNN_000003
│ │ ├── 000000.jpg
│ │ ├── 000001.jpg
│ │ ├── ...
├── meta
│ ├── train_80.txt
│ ├── val_20.txt
```
`train_80.txt` 中的 `80` 表示训练数据集在整个ReID数据集中的比例为80%。而验证数据集的比例为20%。
关于训练,我们提供了一个注释列表 `train_80.txt`。列表中的每一行包含一个文件名及其对应的真实标签。格式如下所示:
```
MOT17-05-FRCNN_000110/000018.jpg 0
MOT17-13-FRCNN_000146/000014.jpg 1
MOT17-05-FRCNN_000088/000004.jpg 2
MOT17-02-FRCNN_000009/000081.jpg 3
```
`MOT17-05-FRCNN_000110` 表示 `MOT17-05-FRCNN` 视频中的第110个人。
对于验证集,注释列表 `val_20.txt` 的格式与上述相同。
`reid/imgs` 中的图像是通过相应的 `gt.txt``MOT17/train` 中的原始图像中裁剪而来。真实标签的值应在 `[0, num_classes - 1]` 的范围内。
#### CrowdHuman 中的 annotations 文件夹
`data/crowdhuman/annotations` 文件夹下有两个JSON文件:
`crowdhuman_train.json`:包含 CrowdHuman 数据集训练集的注释信息的JSON文件。
`crowdhuman_val.json`:包含 CrowdHuman 数据集验证集的注释信息的JSON文件。
#### youtube_vis_2019/youtube_vis2021 中的 annotations 文件夹
There are 3 JSON files in `data/youtube_vis_2019/annotations` or `data/youtube_vis_2021/annotations`
`youtube_vis_2019_train.json`/`youtube_vis_2021_train.json`:包含 youtube_vis_2019/youtube_vis2021 数据集训练集的注释信息的JSON文件。
`youtube_vis_2019_valid.json`/`youtube_vis_2021_valid.json`:包含 youtube_vis_2019/youtube_vis2021 数据集验证集的注释信息的JSON文件。
`youtube_vis_2019_test.json`/`youtube_vis_2021_test.json`:包含 youtube_vis_2019/youtube_vis2021 数据集测试集的注释信息的JSON文件。
# 推理
我们提供了一些演示脚本去推理一个给出的视频,或者是推理包含一系列连续照片的文件夹。想要获取该代码资源,请点击 [这里](https://github.com/open-mmlab/mmdetection/tree/tracking/demo)
若输入为文件夹格式,你需要标明这点。并且,图片命名应该**易于整理**,以便于你根据文件名字中包含的数字信息来重新调整图片的顺序。我们现在只支持 `.jpg``.jpeg``.png` 格式的图片。
## MOT models 的推理
该脚本能够使用多任务跟踪或者视频实例分割方法来推理一段输入的视频/一张图片。
```shell
python demo/mot_demo.py \
${INPUTS}
${CONFIG_FILE} \
[--checkpoint ${CHECKPOINT_FILE}] \
[--detector ${DETECTOR_FILE}] \
[--reid ${REID_FILE}] \
[--score-thr ${SCORE_THR}] \
[--device ${DEVICE}] \
[--out ${OUTPUT}] \
[--show]
```
`INPUTS``OUTPUT` 参数支持 _mp4 视频_ 格式和_文件夹_格式。
**特别注意**:对于 `DeepSORT``SORT``StrongSORT`,他们需要单独加载 `reid``detector` 的权重。因此,我们会使用 `--detector``--reid` 来加载权重参数。其他的例如 `ByteTrack``OCSORT``QDTrack``MaskTrackRCNN` 以及 `Mask2Former` 这样的算法则使用 `--checkpoint` 来加载权重参数。
可选参数:
- `CHECKPOINT_FILE`: 可选择 checkpoint。
- `DETECTOR_FILE`: 可选择 detector。
- `REID_FILE`: 可选择 reid。
- `SCORE_THR`: bboxes 的得分阈值。
- `DEVICE`: 推理所需配置。可以选择 `cpu``cuda:0`,或者其他。
- `OUTPUT`: 输出结果可视化的示例。如果未指定, `--show` 将强制显示动态视频。
- `--show`: 是否即时显示视频。
**运行 mot model 的示例:**
```shell
# 示例 1:不指定 --checkpoint 使用 --detector
python demo/mot_demo.py \
demo/demo_mot.mp4 \
configs/sort/sort_faster-rcnn_r50_fpn_8xb2-4e_mot17halftrain_test-mot17halfval.py \
--detector \
https://download.openmmlab.com/mmtracking/mot/faster_rcnn/faster-rcnn_r50_fpn_4e_mot17-half-64ee2ed4.pth \
--out mot.mp4
# 示例 2:使用 --checkpoint
python demo/mot_demo.py \
demo/demo_mot.mp4 \
configs/qdtrack/qdtrack_faster-rcnn_r50_fpn_8xb2-4e_mot17halftrain_test-mot17halfval.py \
--checkpoint https://download.openmmlab.com/mmtracking/mot/qdtrack/mot_dataset/qdtrack_faster-rcnn_r50_fpn_4e_mot17_20220315_145635-76f295ef.pth \
--out mot.mp4
```
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