1.总体框架
MMDetection Github地址是一个目标检测工具箱,包含了丰富的目标检测、实例分割、全景分割算法以及相关的组件和模块,MMDetection 由 7 个主要部分组成,apis、structures、datasets、models、engine、evaluation 和 visualization。
apis 为模型推理提供高级 API。
structures 提供 bbox、mask 和 DetDataSample 等数据结构。
datasets 支持用于目标检测、实例分割和全景分割的各种数据集。
transforms 包含各种数据增强变换。
samplers 定义了不同的数据加载器采样策略。
models 是检测器最重要的部分,包含检测器的不同组件。
detectors 定义所有检测模型类。
data_preprocessors 用于预处理模型的输入数据。
backbones 包含各种骨干网络。
necks 包含各种模型颈部组件。
dense_heads 包含执行密集预测的各种检测头。
roi_heads 包含从 RoI 预测的各种检测头。
seg_heads 包含各种分割头。
losses 包含各种损失函数。
task_modules 为检测任务提供模块,例如 assigners、samplers、box coders 和 prior generators。
layers 提供了一些基本的神经网络层。
engine 是运行时组件的一部分。
runner 为 MMEngine 的执行器提供扩展。
schedulers 提供用于调整优化超参数的调度程序。
optimizers 提供优化器和优化器封装。
hooks 提供执行器的各种钩子。
evaluation 为评估模型性能提供不同的指标。
visualization 用于可视化检测结果。
mmdetection主要对外提供三个API接口(定义在tools文件夹和mmdet.api文件夹下)
- train(主要通过mmcv的Runner来管理训练时的生命周期)
- test(在测试集上计算各种metric指标)
- inference(前向推理,输入若干张图片,得到bbox结果)
下面主要来学习各个模块的配置文件参数。
2. Model配置
model 字段来配置检测算法的组件;backbone、neck配置神经网络组件;data_preprocessor 负责对 dataloader 输出的每一批数据进行预处理; train_cfg 和 test_cfg 用于设置训练和测试组件的超参数。
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 预处的阈值
3.数据集、评测器、优化器配置
构建数据 dataloader 需要设置数据集(dataset)和数据处理流程(data pipeline)
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 配置
4. 钩子、运行相关配置
用户可以在训练、验证和测试循环上添加钩子,以便在运行期间插入一些操作。配置中有两种不同的钩子字段,一种是 default_hooks,另一种是 custom_hooks。
default_hooks 是一个字典,用于配置运行时必须使用的钩子。这些钩子具有默认优先级,如果未设置,runner 将使用默认值。如果要禁用默认钩子,用户可以将其配置设置为 None。
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 是一个列表。用户可以在这个字段中加入自定义的钩子
运行相关配置
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` 中的最新检查点。
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
# 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)
5.配置文件继承
在 config/base 文件夹下有 4 个基本组件类型,分别是:数据集(dataset),模型(model),训练策略(schedule)和运行时的默认设置(default runtime)。由 base 下的组件组成的配置,被我们称为 原始配置(primitive)。对于同一文件夹下的所有配置,推荐只有一个对应的原始配置文件。所有其他的配置文件都应该继承自这个原始配置文件。这样就能保证配置文件的最大继承深度为 3。
例如,如果在 Faster R-CNN 的基础上做了一些修改,用户首先可以通过指定 base = …/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py 来继承基础的 Faster R-CNN 结构,然后修改配置文件中的必要参数以完成继承。
如果你在构建一个与任何现有方法不共享结构的全新方法,那么可以在 configs 文件夹下创建一个新的例如 xxx_rcnn 文件夹。
当 base 为文件路径字符串时,表示继承一个配置文件的内容。
有时,您也许会设置 delete=True 去忽略基础配置文件里的一些域内容
基础配置的 Mask R-CNN 使用 ResNet-50,在需要将主干网络改成 HRNet 的时候,因为 HRNet 和 ResNet 中有不同的字段,需要使用 delete=True 将新的键去替换 backbone 域内所有老的键。
_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))
6. 推理接口
在 OpenMMLab 中,所有的推理操作都被统一到了推理器 Inferencer 中。推理器被设计成为一个简洁易用的 API,它在不同的 OpenMMLab 库中都有着非常相似的接口。 下面介绍的演示样例都放在 demo/inference_demo.ipynb 中方便大家尝试
使用 DetInferencer,需 3 行代码就可以获得推理结果。
from mmdet.apis import DetInferencer
# 初始化模型
inferencer = DetInferencer('rtmdet_tiny_8xb32-300e_coco')
# 推理示例图片
inferencer('demo/demo.jpg', show=True)
每个推理器必须使用一个模型进行初始化。初始化时,可以手动选择推理设备。
要用 MMDetection 的预训练模型进行推理,只需要把它的名字传给参数 model,权重将自动从 OpenMMLab 的模型库中下载和加载。
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco')
在 MMDetection 中有一个非常容易的方法,可以列出所有模型名称。
models 是一个模型名称列表,它们将自动打印
models = DetInferencer.list_models('mmdet')
将权重的路径或 URL 传递给 weights 来让推理器加载自定义的权重
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', weights='path/to/rtmdet.pth')
要加载自定义的配置和权重,把配置文件的路径传给 model,把权重的路径传给 weights
inferencer = DetInferencer(model='path/to/rtmdet_config.py', weights='path/to/rtmdet.pth')
在 GPU 1 上创建一个推理器
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', device='cuda:1')
在 CPU 上创建一个推理器:
inferencer = DetInferencer(model='rtmdet_tiny_8xb32-300e_coco', device='cpu'
输出:
默认情况下,每个推理器都以字典格式返回预测结果
visualization 包含可视化的预测结果。但默认情况下,它是一个空列表,除非 return_vis=True。
predictions 包含以 json-可序列化格式返回的预测结果。
如果你想要从模型中获取原始输出,可以将 return_datasamples 设置为 True 来获取原始的 DataSample,它将存储在 predictions 中。
除了从返回值中获取预测结果,你还可以通过设置 out_dir 和 no_save_pred/no_save_vis 参数将预测结果和可视化结果导出到文件中。
inferencer('demo/demo.jpg', out_dir='outputs/', no_save_pred=False)