MMDetection教程(二)训练数据集并分析

MMDetection(二)训练数据集并分析

训练

查找模型配置文件

Faster RCNN为例,讲解如何找到模型的配置文件和权重文件

  1. 首先找到模型的配置文件mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py,这里以ResNet50作为backbone, 使用FPN为多层特征提取的网络配置文件.

  2. 打开配置文件得到以下信息:

    _base_ = [
        '../_base_/models/faster_rcnn_r50_fpn.py',
        '../_base_/datasets/coco_detection.py',
        '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
    ]

    这里可以看到四个文件:

    • ../_base_/models/faster_rcnn_r50_fpn.py为模型的源码,配置文件.
    • ../_base_/datasets/coco_detection.py为训练模型使用的数据集的一些配置,比如数据集的预处理,缩放,数据集路径等信息.
    • ../_base_/schedules/schedule_1x.py为模型训练方式,其中包含优化器,学习率修改测率和训练的轮回数.
    • ../_base_/default_runtime.py为默认的训练运行时,其中包含保存断点权重的间隔数等.一般不需要修改.
  3. 得到这些configs后,可以对这些文件进行修改了,也可以创建新的文件

准备数据

修改配置文件

  1. 定义数据种类,需要修改的地方在mmdetection/mmdet/datasets/coco.py。把CLASSES的那个tuple改为自己数据集对应的种类tuple即可。例如:

    CLASSES = ('0B', '1B', '2B')
  2. 接着在mmdetection/mmdet/core/evaluation/class_names.py修改coco_classes数据集类别,这个关系到后面test的时候结果图中显示的类别名称。例如:

    def coco_classes():
        return ['0B', '1B', '2B']
  1. 修改configs/_base_/datasets/coco_detection.pytrain_pipelinetest_pipeline中的img_scale:

    dataset_type = 'CocoDataset'
    data_root = 'data/coco/'
    img_norm_cfg = dict(
        mean=[0.471,0.448,0.408], std=[0.234,0.239,0.242], to_rgb=True)
    train_pipeline = [
        dict(type='LoadImageFromFile'),
        dict(type='LoadAnnotations', with_bbox=True),
        dict(type='Resize', img_scale=(400, 300), keep_ratio=True),
        dict(type='RandomFlip', flip_ratio=0.5),
        dict(type='Normalize', **img_norm_cfg),
        dict(type='Pad', size_divisor=32),
        dict(type='DefaultFormatBundle'),
        dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
    ]
    test_pipeline = [
        dict(type='LoadImageFromFile'),
        dict(
            type='MultiScaleFlipAug',
            # 图像大小尺寸缩放
            img_scale=(400, 300),
            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=2,
        workers_per_gpu=2,
        train=dict(
            type=dataset_type,
            # 标记文件路径 和 数据集路径
            ann_file=data_root + 'annotations/instances_train2017.json',
            img_prefix=data_root + 'train2017/',
            pipeline=train_pipeline),
        val=dict(
            type=dataset_type,
            ann_file=data_root + 'annotations/instances_val2017.json',
            img_prefix=data_root + 'val2017/',
            pipeline=test_pipeline),
        test=dict(
            type=dataset_type,
            ann_file=data_root + 'annotations/instances_test2017.json',
            img_prefix=data_root + 'test2017/',
            pipeline=test_pipeline))
    evaluation = dict(interval=1, metric='bbox')
  1. 修改models/faster_rcnn_r50_fpn.py中的num_classes:

    model = dict(
        type='FasterRCNN',
        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(
            type='FPN',
            in_channels=[256, 512, 1024, 2048],
            out_channels=256,
            num_outs=5),
        rpn_head=dict(
            type='RPNHead',
            in_channels=256,
            feat_channels=256,
            anchor_generator=dict(
                type='AnchorGenerator',
                scales=[8],
                ratios=[0.5, 1.0, 2.0],
                strides=[4, 8, 16, 32, 64]),
            bbox_coder=dict(
                type='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),
            loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
        roi_head=dict(
            type='StandardRoIHead',
            bbox_roi_extractor=dict(
                type='SingleRoIExtractor',
                roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),
                out_channels=256,
                featmap_strides=[4, 8, 16, 32]),
            bbox_head=dict(
                type='Shared2FCBBoxHead',
                in_channels=256,
                fc_out_channels=1024,
                roi_feat_size=7,
                #类别数
                num_classes=3,
                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='L1Loss', loss_weight=1.0))))
    # model training and testing settings
    .........
  1. 修改_base_/schedules/schedule_1x.py中的配置:

    optimizer = dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001) #当gpu数量为8时,lr=0.02;当gpu数量为8时,lr=0.01;我只要一个gpu,所以设置lr=0.0025

    还可以修改训练的周期数.

  1. mmdetection的目录下新建work_dirs文件夹

使用单GPU训练

python tools/train.py ${CONFIG_FILE} [optional arguments]

如果您想在命令中指定工作目录(保存训练过程日志等信息), 你可以添加参数 --work-dir ${YOUR_WORK_DIR}.

使用多GPU训练

./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]

可选参数:

  • --work-dir ${WORK_DIR}: 指定工作目录(保存训练过程日志等信息)
  • --resume-from ${CHECKPOINT_FILE}: 从之前的断点文件中继续训练

例如:

python tools/train.py configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py --work-dir cascade_rcnn

测试

测试数据集

可以使用单GPU和多GPU对测试数据进行测试,使用如下命令:

# 单GPU测试
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] [--show] [--cfg-options]

# 多GPU测试
./tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] [--cfg-options]

可选参数:

  • RESULT_FILE: 输出结果保存为pickle格式在指定目录下,如果不指定该参数,输出结果不保存。

  • EVAL_METRICS: 评价结果的标准。根据数据集可选择的评价标准有: proposal_fast, proposal, bbox, segm 可用在COCO数据集上; mAP, recall 可用在PASCAL VOC数据集上。

  • --show: 如果指定,检测结果将绘制在图像上并显示在一个新窗口中。仅适用于单GPU测试,用于调试和可视化。请确保GUI在你的环境中可用,否则您可能会遇到类似“无法连接到X服务器”的错误。

  • --show-dir: 如果指定,检测结果将绘制在图像上并保存到指定的目录中。仅适用于单GPU测试,用于调试和可视化。使用此选项时,环境中可以不需要可用的GUI。

  • --show-score-thr: 如果指定,则将删除分数低于此阈值的检测。

测试Faster R-CNN模型,并将结果可视化展示在窗口中,按任意键切换下一张图片:

python tools/test.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py save/epoch_9.pth --show detection_results --eval bbox

测试Faster R-CNN模型,不将结果可视化展示在窗口中,保存在文件中,为方便后续的可视化:

python tools/test.py configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py grid_rcnn/epoch_25.pth --show-dir detection_results --eval bbox

测试单张图片

python demo/image_demo.py ${IMAGE_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE} [--device ${GPU_ID}] [--score-thr ${SCORE_THR}]

例如使用Faster R-CNN模型测试demo.jpg图片,输入如下命令:

python demo/image_demo.py demo/demo.jpg configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py \
    checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth --device cpu

分析训练日志

通过训练生成的log文件可以画出loss/mAP曲线。首先需要安装pip install seaborn依赖。

python tools/analyze_logs.py plot_curve [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}]

绘制分类损失:

python tools/analyze_logs.py plot_curve faster_rcnn_1x_res50/20200928_120614.log.json --keys loss_cls loss_bbox --legend loss_cls loss_bbox

绘制分类损失和边界框损失:

python tools/analyze_logs.py plot_curve log.json --keys loss_cls loss_bbox

计算平均训练时间:

python tools/analyze_logs.py cal_train_time log.json

输出的格式如下:

-----Analyze train time of save/20200927_095440.log.json-----
slowest epoch 6, average time is 0.1322
fastest epoch 7, average time is 0.1202
time std over epochs is 0.0033
average iter time: 0.1271 s/iter