config
以mask-rcnn为例:
mask_rcnn_r50_fpn.py
# model settings
## 主干网络
model = dict(
type='MaskRCNN', # The name of detector
pretrained='torchvision://resnet50', #要加载的ImageNet预训练主干
bckbone=dict( #主干网络的配置(https://github.com/openmmlab/mmdetection/blob/master/mmdet/models/backbones/resnet.py#L288 for more details.)
type='ResNet', #主干的类型,
depth=50, #网络深度
num_stages=4, #主干的阶段数。
out_indices=(0, 1, 2, 3), #各阶段生成的输出特征图索引
frozen_stages=1, #一阶段的weight第一设是fronzen
norm_cfg=dict(type='BN', requires_grad=True), #BN的配置。 #标准层的类型,通常为BN或GN #是否在BN中训练gamma和beta
norm_eval=True, #是否冻结BN的统计数据
style='pytorch'), #主干的风格,“Pytorch”意味着步幅2层位于3x3 conv中,“caffe”表示步幅2层位于1x1 conv中。
neck=dict(
type='FPN', # The neck of detector is FPN.
#https://github.com/open-mmlab/mmdetection/blob/master/mmdet/models/necks/fpn.py#L10 for more details.
in_channels=[256, 512, 1024, 2048], # The input channels, this is consistent with the output channels of backbone
in_channels=[256, 512, 1024, 2048], #输入通道,这与主干的输出通道一致
out_channels=256, #金字塔特征图的每一级的输出通道
num_outs=5), #输出SCALE的数量
## RPN头
rpn_head=dict(
type='RPNHead', #RPN头的类型是“RPNHead”,
# Refer to https://github.com/open-mmlab/mmdetection/blob/master/mmdet/models/dense_heads/rpn_head.p
in_channels=256,#每个输入特征映射的输入通道,这与颈部的输出通道是一致的
feat_channels=256, #头部卷积层的特征通道。
anchor_generator=dict(#锚发生器的配置
type='AnchorGenerator',#大多数方法使用AnchorGenerator,SSD检测器使用SSDAnchorGenerator。
## https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/anchor/anchor_generator.py
scales=[8], #锚定的基本比例,锚定在特征地图的一个位置的面积将是 scale * base_sizes
ratios=[0.5, 1.0, 2.0],#高度和宽度之间的比率。
strides=[4, 8, 16, 32, 64]), #锚发生器的步幅。这与FPN的特性是一致的。如果未设置基本尺寸,则步幅将作为基本尺寸。
bbox_coder=dict(
type= 'DeltaXYWHBBoxCoder',#在训练和测试期间,配置盒子编码器对盒子进行编码和解码
# #箱式编码器类型DeltaXYWHBBoxCoder'适用于大多数方法
target_means=[.0, .0, .0, .0],#用于对框进行编码和解码的目标方法
target_stds=[1.0, 1.0, 1.0, 1.0]),#用于对方框进行编码和解码的标准方差
loss_cls=dict(#分类分支的损失函数配置
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),#对于分类分支的损失类型,我们还支持focaloss等。
# #RPN通常执行两类分类,因此通常使用sigmoid函数。#分类枝的失重。
loss_bbox=dict(type='L1Loss', loss_weight=1.0)),#回归分支的损失函数配置。#损失类型,我们还支持许多IoU损失和平滑L1损失
## RoIHead
roi_head=dict(
type='StandardRoIHead', #RoIHead封装了两级/级联探测器的第二级。 #RoI头的类型。
#https://github.com/open-mmlab/mmdetection/blob/master/mmdet/models/roi_heads/standard_roi_head.py
bbox_roi_extractor=dict(#bbox回归的RoI特征提取。
type='SingleRoIExtractor',#RoI特征抽取器的类型,大多数方法使用单RoI特征抽取器。
roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),#RoI层配置
# #还支持RoI层类型、DeformRoIPoolingPack和modulatedeformroipoolingpack。#feature map的输出大小。
# #提取RoI特征时的采样率。0表示自适应比率。
out_channels=256,#提取特征的输出通道。
featmap_strides=[4, 8, 16, 32]),#多比例尺特征图的进展。它应该与主干的体系结构保持一致。
bbox_head=dict(#bbox头的类型,
type='Shared2FCBBoxHead',
in_channels=256,#bbox head的输入通道。这与roi提取器中的out通道一致
fc_out_channels=1024,#输出FC层的特征通道。
roi_feat_size=7,#RoI特征的大小
num_classes=80,#分类类别数 #####################################
bbox_coder=dict(#第二阶段使用的box编码器。
type='DeltaXYWHBBoxCoder',#箱式编码器类型DeltaXYWHBBoxCoder'适用于大多数方法。
target_means=[0., 0., 0., 0.],#用于box进行编码和解码的方法
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', use_sigmoid=False, loss_weight=1.0),#对于分类分支的损失类型,我们还支持focaloss等。
# Whether to use sigmoid.
loss_bbox=dict(type='L1Loss', loss_weight=1.0)), #为回归分支配置损失函数。
# #损失类型,我们还支持多IoU损失和平滑L1损失等。
mask_roi_extractor=dict(#bbox回归的RoI特征提取。
type='SingleRoIExtractor',#RoI特征抽取器的类型,大多数方法使用单RoI特征抽取器。
roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0),#RoI层的配置,用于提取实例分割的特征
#还支持RoI层类型、DeformRoIPoolingPack和modulatedeformroipoolingpack #output_size要素图的输出大小。 #sampling_ratio提取RoI特征时的采样率。
out_channels=256,#提取特征的输出通道。
featmap_strides=[4, 8, 16, 32]),#多比ride
mask_head=dict(# type='FCNMaskHead', # Type of mask head,
num_convs=4,#掩模头的卷积层数。
in_channels=256,#输入通道,应与mask roi提取器的输出通道一致。
conv_out_channels=256,#卷积层的输出通道。
num_classes=80, # num_classes=80,mber of class to be segmented.
loss_mask=dict( #掩码分支的LOSS函数的配置。
type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))), # Type of loss used for segmentation
#是否只在正确类别上训练mask
# Loss weight of mask branch.
# model training and testing settings
## rpn和rcnn的训练超参数配置
#rpn训练配置
train_cfg=dict(#rpn和rcnn的训练超参数配置
rpn=dict(
assigner=dict(#rpn训练配置
type='MaxIoUAssigner',#Assigner配置 赋值器的类型MaxIoUAssigner用于许多常见的检测器
pos_iou_thr=0.7,
neg_iou_thr=0.3,
min_pos_iou=0.3,#iou>=阈值0.7将作为阳性样本
#iou<阈值0.3将作为负样本
#将盒子作为阳性样本的最小iou阈值
match_low_quality=True,#是否匹配低质量下的框(详见API文档)。
ignore_iof_thr=-1),#忽略bboxes的IoF阈值
sampler=dict(#正/负采样器配置
type='RandomSampler',#还支持采样器类型、伪采样器和其他采样器
num=256,#样本数
pos_fraction=0.5,#ZHENG样本占总样本的比例。
neg_pos_ub=-1,#基于正样本数的负样本上限。
add_gt_as_proposals=False),#CAI样后是否增加GT作为建议。
allowed_border=-1,#填充有效定位后允许的边框。
pos_weight=-1,#训练中zheng样本weight
debug=False),#是否设置调试模式
rpn_proposal=dict(#在培训期间生成建议的配置
nms_pre=2000,#NMS前的BBOX数
max_per_img=1000,#NMS后保留的BBOX数量。
nms=dict(type='nms', iou_threshold=0.7), ##NMS
min_bbox_size=0),
## #rcnn的配置
rcnn=dict(#roi头的配置。
assigner=dict(
type='MaxIoUAssigner',#第二阶段的赋值器配置,这与rpn中的不同
pos_iou_thr=0.5,
neg_iou_thr=0.5,
min_pos_iou=0.5,
#IoU>=阈值0.5将作为ZHENG样本
#IoU>=阈值0.5将作为ZHENG样本
#将盒子作为ZHENG样本的最小IoU阈值
match_low_quality=True,#是否匹配低质量下的框(详见API文档)。
ignore_iof_thr=-1),#忽略bboxes的IoF阈值
sampler=dict(
type='RandomSampler',#还支持采样器类型、伪采样器和其他采样器。
num=512,# Number of samples
pos_fraction=0.25,#阳性样本占总样本的比例。
neg_pos_ub=-1,#基于正样本数的负样本上限。
add_gt_as_proposals=True),#取样后是否增加GT作为建议。
mask_size=28,#遮罩尺寸
pos_weight=-1, #训练中阳性样本的重量。
debug=False)),#是否设置调试模式
## 用于测试rpn和rcnn的超参数的配置
test_cfg=dict(
rpn=dict(#在测试期间生成建议的配置
nms_pre=1000,#NMS前的箱数
max_per_img=1000,#NMS后保留的箱子数量。
nms=dict(type='nms', iou_threshold=0.7),# Config of nms
min_bbox_size=0),
rcnn=dict(#roi头的配置。
score_thr=0.05,#筛选框的阈值
nms=dict(type='nms', iou_threshold=0.5),#第二阶段配置
max_per_img=100,#每个图像的最大检测数
mask_thr_binary=0.5)))#掩模预测阈值
default_runtime.py
checkpoint_config = dict(interval=1)#保存间隔为1
# yapf:disable
log_config = dict( #配置以LOGS
interval=50,#打印日志的间隔
hooks=[
dict(type='TextLoggerHook'),
# dict(type='TensorboardLoggerHook')#也支持Tensorboard记录器
])
# yapf:enable
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')#参数设置分布式训练,端口也可以设置。
log_level = 'INFO'#日志记录的级别。
load_from = "/home/blake/PycharmProjects/Swin-Transformer-Object-Detection-master/swin_tiny_patch4_window7_224.pth"
#从给定路径将模型作为预先训练的模型加载。这将不会恢复训练。
resume_from = None #从给定路径恢复检查点,将从保存恢复训练。
workflow = [('train', 1)]
#运行程序的工作流train',1)]表示只有一个工作流,名为“train”的工作流执行一次。该工作流按12个阶段对模型进行训练。
work_dir = 'work_dir' #目录保存当前实验的模型检查点和日志。
dataset 配置
dataset_type = 'CocoDataset'
data_root = '/media/blake/ wys/coco2017/coco/'
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True, with_mask=True),
##Whether to use bounding box, True for detection
# Whether to use instance mask, True for instance segmentation
# Whether to convert the polygon mask to instance mask, set False for acceleration and to save memory
dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),#The largest scale of image
# whether to keep the ratio between height and width.
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg), # Augmentation pipeline that normalize the input images
dict(type='Pad', size_divisor=32),#填充配置 #填充图像的数字应该是可整除的
# dict(type='DefaultFormatBundle'),
dict(type='ImageToTensor'),#在PIPLINE收集数据的默认格式包
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']),#决定数据中哪些键应该传递给检测器的PIPLINE
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1333, 800),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
data = dict(
samples_per_gpu=1,# Batch size of a single GPU
workers_per_gpu=1,# Worker to pre-fetch data for each single GPU
train=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_train2017.json',
img_prefix=data_root + 'train2017/',
pipeline=train_pipeline),
val=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_val2017.json',
img_prefix=data_root + 'val2017/',
pipeline=test_pipeline),
test=dict(
type=dataset_type,
ann_file=data_root + 'annotations/instances_val2017.json',
img_prefix=data_root + 'val2017/',
pipeline=test_pipeline))
evaluation = dict(metric=['bbox', 'segm'])##构建评估
##evaluation = dict( # The config to build the evaluation hook, refer to https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/evaluation/eval_hooks.py#L7 for more details.
## interval=1, # Evaluation interval
## metric=['bbox', 'segm']) # Metrics used during evaluation
学习率相关
schedule.py
# optimizer
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
#优化器类型 # Learning rate of optimizers # Momentum # Weight decay of SGD
#用于构建优化器的Config,支持PyTorch中所有参数与PyTorch中参数相同的优化器
optimizer_config = dict(grad_clip=None) #Config used to build the optimizer hook, #大多数方法不使用grad_clip
# learning policy
lr_config = dict(
policy='step',
warmup='linear',
warmup_iters=500,
warmup_ratio=0.001,
step=[8, 11])
runner = dict(type='EpochBasedRunner', max_epochs=12)
#在总最大时间内运行工作流的运行程序
其他配置
defaultrunrime.py
checkpoint_config = dict(interval=1)#保存间隔为1
# yapf:disable
log_config = dict( #配置以LOGS
interval=50,#打印日志的间隔
hooks=[
dict(type='TextLoggerHook'),
# dict(type='TensorboardLoggerHook')#也支持Tensorboard记录器
])
# yapf:enable
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')#参数设置分布式训练,端口也可以设置。
log_level = 'INFO'#日志记录的级别。
load_from = "/home/blake/PycharmProjects/Swin-Transformer-Object-Detection-master/swin_tiny_patch4_window7_224.pth"
#从给定路径将模型作为预先训练的模型加载。这将不会恢复训练。
resume_from = None #从给定路径恢复检查点,将从保存恢复训练。
workflow = [('train', 1)]
#运行程序的工作流train',1)]表示只有一个工作流,名为“train”的工作流执行一次。该工作流按12个阶段对模型进行训练。
work_dir = 'work_dir' #目录保存当前实验的模型检查点和日志。
## FAQ
有时,可以将 delete=True 设置为忽略基本配置中的某些字段
例如,在MMDetection中,用以下配置更改Mask R-CNN的主干。
model = dict(
type='MaskRCNN',
pretrained='torchvision://resnet50',
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'),
neck=dict(...),
rpn_head=dict(...),
roi_head=dict(...))
## ResNet and HRNet 使用不同的结构
_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py'
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w32',
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)))),
neck=dict(...))
中间变量的使用
在configs文件中使用了一些中间变量,如数据集中的train_pipeline/test_pipeline。值得注意的是,
在修改子配置中的中间变量时,用户需要再次将中间变量传递到相应的字段中。例如,我们想用
多尺度策略来训练一个Mask R-CNN。train_ pipeline/test_ pipeline是我们
要修改的中间变量。
_base_ = './mask_rcnn_r50_fpn_1x_coco.py'
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True, with_mask=True),
dict(
type='Resize',
img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736),
(1333, 768), (1333, 800)],
multiscale_mode="value",
keep_ratio=True),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1333, 800),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
data = dict(
train=dict(pipeline=train_pipeline),
val=dict(pipeline=test_pipeline),
test=dict(pipeline=test_pipeline))
**首先定义新的train_pipeline/test_pipeline,并将其传递到数据中。**
Log Analysis
tools/analysis_ tools/analysis_logs.py
绘制给定训练日志文件的损失/映射曲线。首先运行pip install seaborn来安装依赖项。
python tools/analysis_tools/analyze_logs.py plot_curve [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}]
Examples:
#绘制loss
python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_cls --legend loss_cls
##保存
python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_cls loss_bbox --out losses.pdf
##对比两个模型的map
python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys bbox_mAP --legend run1 run2
##计算训练速度
python tools/analysis_tools/analyze_logs.py cal_train_time log.json [--include-outliers]
结果分析
tools/analysis_ tools/analysis_results.py计算单个图像映射,并根据预测结果保存或显示得分最高和最低的topk图像。
python tools/analysis_tools/analyze_results.py \
${CONFIG} \
${PREDICTION_PATH} \
${SHOW_DIR} \
[--show] \
[--wait-time ${WAIT_TIME}] \
[--topk ${TOPK}] \
[--show-score-thr ${SHOW_SCORE_THR}] \
[--cfg-options ${CFG_OPTIONS}]
## example
可视化
tools/misc/browse_dataset.py
帮助用户直观地浏览检测数据集(图像和边界框注释),或将图像保存到指定目录。
python tools/misc/browse_dataset.py ${CONFIG} [-h] [--skip-type ${SKIP_TYPE[SKIP_TYPE...]}] [--output-dir ${OUTPUT_DIR}] [--not-show] [--show-interval ${SHOW_INTERVAL}]
python tools/misc/browse_dataset.py /configs/yolo/yolov3_d53_320_273e_coco.py --output /home/blake/1 --not-show
Error Analysis
据不同的标准对每个类别的coco结果进行分析。它还可以绘制一个绘图,以提供有用的信息。
python tools/analysis_tools/coco_error_analysis.py ${RESULT} ${OUT_DIR} [-h] [--ann ${ANN}] [--types ${TYPES[TYPES...]}]
python tools/test.py \
configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py \
checkpoint/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth \
--format-only \
--options "jsonfile_prefix=./results"
###Get COCO bbox error results per category , save analyze result images to the directory results/
python tools/analysis_tools/coco_error_analysis.py \
results.bbox.json \
results \
--ann=data/coco/annotations/instances_val2017.json \
####Get COCO segmentation error results per category , save analyze result images to the directory results/
python tools/analysis_tools/coco_error_analysis.py \
results.segm.json \
results \
--ann=data/coco/annotations/instances_val2017.json \
--types='segm'
模型保存
Convert model from MMDetection to TorchServe
####convert model from MMDetection to TorchServe
python tools/deployment/mmdet2torchserve.py ${CONFIG_FILE} ${CHECKPOINT_FILE} \
--output-folder ${MODEL_STORE} \
--model-name ${MODEL_NAME}
python tools/deployment/mmdet2torchserve.py configs/swin/mask_rcnn_swin_tiny_patch4_window7_mstrain_480-800_adamw_3x_coco.py weight/mask_rcnn_swin_tiny_patch4_window7_1x.pth --output-folder /home/blake/1 --model-name mymodel
##Build mmdet-serve docker image
docker build -t mmdet-serve:latest docker/serve/
###########################
Run mmdet-serve
Check the official docs for running TorchServe with docker.
In order to run in GPU, you need to install nvidia-docker. You can omit the --gpus argument in order to run in CPU.
########################33
docker run --rm \
--cpus 8 \
--gpus device=0 \
-p8080:8080 -p8081:8081 -p8082:8082 \
--mount type=bind,source=$MODEL_STORE,target=/home/model-server/model-store \
mmdet-serve:latest
############################
4. Test deployment
curl -O curl -O https://raw.githubusercontent.com/pytorch/serve/master/docs/images/3dogs.jpg
curl http://127.0.0.1:8080/predictions/${MODEL_NAME} -T 3dogs.jpg
计算复杂度
python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}]
数据集
包含将Cityscapes数据集和Pascal VOC数据集转换为COCO格式的工具。
python tools/dataset_converters/cityscapes.py ${CITYSCAPES_PATH} [-h] [--img-dir ${IMG_DIR}] [--gt-dir ${GT_DIR}] [-o ${OUT_DIR}] [--nproc ${NPROC}]
python tools/dataset_converters/pascal_voc.py ${DEVKIT_PATH} [-h] [-o ${OUT_DIR}]
鲁棒检测基准
tools/analysis_tools/test_robustness.py tools/analysis_tools/robustness_eval.py
帮助用户评估模型的健壮性。核心思想来自目标检测中的鲁棒性基准测试:冬天来临时自动驾驶。有关如何评估损坏图像上的模型以及一组标准模型的结果的更多信息,请参阅robustness\u benchmarking.md
其他
评估度量
tools/analysis_tools/eval_metric.py
根据配置文件评估pkl结果文件的某些度量。
python tools/analysis_tools/eval_metric.py ${CONFIG} ${PKL_RESULTS} [-h] [--format-only] [--eval ${EVAL[EVAL ...]}]
[--cfg-options ${CFG_OPTIONS [CFG_OPTIONS ...]}]
[--eval-options ${EVAL_OPTIONS [EVAL_OPTIONS ...]}]
Print the entire config
python tools/misc/print_config.py ${CONFIG} [-h] [--options ${OPTIONS [OPTIONS...]}]