mmdetection 模型训练技巧

1. 预训练模型

      关于预训练模型,一般的检测都是使用ImageNet预训练的backbone,这是基本配置,官方也支持这种加载方式。

      高级一点的的就是针对数据集做一次预训练:即将所有的目标裁剪出来,然后训练一个不错的分类模型,这样的初始化相比ImageNet就要好很多。

      最后就是使用coco预训练的完整检测模型权重,这样的效果就是模型收敛速度快,而且效果一般都比较好,也是大家最常用的方法。由于每个任务的类别不同,需要对权重进行微调,这里给出mmdetection修改coco预训练权重类别的脚本。

      脚本以cascade rcnn为例,其他模型的修改与之类似。

# for cascade rcnn
import torch
num_classes = 21
model_coco = torch.load("cascade_rcnn_x101_32x4d_fpn_2x_20181218-28f73c4c.pth")

# weight
model_coco["state_dict"]["bbox_head.0.fc_cls.weight"].resize_(num_classes,1024)
model_coco["state_dict"]["bbox_head.1.fc_cls.weight"].resize_(num_classes,1024)
model_coco["state_dict"]["bbox_head.2.fc_cls.weight"].resize_(num_classes,1024)
# bias
model_coco["state_dict"]["bbox_head.0.fc_cls.bias"].resize_(num_classes)
model_coco["state_dict"]["bbox_head.1.fc_cls.bias"].resize_(num_classes)
model_coco["state_dict"]["bbox_head.2.fc_cls.bias"].resize_(num_classes)
#save new model
torch.save(model_coco,"coco_pretrained_weights_classes_%d.pth"%num_classes)

2. Soft-NMS

    Soft-NMS改进了之前比较暴力的NMS,当IOU超过某个阈值后,不再直接删除该框,而是降低它的置信度(得分),如果得分低到一个阈值,就会被排除;但是如果降低后任然较高,就会保留。

    在mmdetection中的设置如下:

test_cfg = dict(
    rpn=dict(
        nms_across_levels=False,
        nms_pre=1000,
        nms_post=1000,
        max_num=1000,
        nms_thr=0.7,
        min_bbox_size=0),
    rcnn=dict(
        score_thr=0.05, nms=dict(type='soft_nms', iou_thr=0.5), max_per_img=100),
    keep_all_stages=False)

3. GIoULoss

      一般情况下,用GIoULoss代替L1Loss后会涨点。

      原版用的配置文件(使用L1Loss)如下:

    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, 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', out_size=7, sample_num=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=10,
            bbox_coder=dict(
                type='DeltaXYWHBBoxCoder',
                target_means=[0.0, 0.0, 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))))

    添加GIoULoss后的配置文件如下:

    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, 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),
	reg_decoded_bbox=True,      # 使用GIoUI时注意添加
        loss_bbox=dict(type='GIoULoss', loss_weight=5.0)),
    roi_head=dict(
        type='StandardRoIHead',
        bbox_roi_extractor=dict(
            type='SingleRoIExtractor',
            roi_layer=dict(type='RoIAlign', out_size=7, sample_num=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=10,
            bbox_coder=dict(
                type='DeltaXYWHBBoxCoder',
                target_means=[0.0, 0.0, 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),
            reg_decoded_bbox=True,     # 使用GIoUI时注意添加
            loss_bbox=dict(type='GIoULoss', loss_weight=5.0))))

4. 模型瘦身小技巧

      mmdetection在保存模型时,除了保存权重,还保存了原始数据和优化参数。但是,模型在测试时,有些参数是没有用的,怎样去掉这些无用的参数使模型减小(大约减小50%)呢?见下面的代码:

import torch

model_path = "epoch_30.pth"
checkpoint = torch.load(model_path)
checkpoint['meta'] = None
checkpoint['optimizer'] = None

weights = checkpoint['state_dict']

state_dict = {"state_dict":weights}

torch.save(state_dict,  './epotch_30_new.pth')

5. 在线难例挖掘(OHEM)

   在线难例挖掘:在训练过程中在线的选择困难样本进行训练(选择loss较大的样本)。

   思想比较简单,在mmdetection中的应用如下:

   以faster rcnn为例子:

_base_ = './faster_rcnn_r50_fpn_1x_coco.py'
train_cfg = dict(rcnn=dict(sampler=dict(type='OHEMSampler')))

   第一行为你训练模型的配置文件,第二行把采样方式设置为在线难例挖掘。       

todo:

(1). GIoULoss  已经完成

(2). 在线难例挖掘  已经完成

(3). 混合精度训练

(4). 可变形卷积

(5). 多尺度训练

(6). 多尺度测试与数据增强测试

(7). Albu数据增强库的使用

(8). 模型融合

(9). 过分割测试

(10). mosaic数据增强

(11). PAFPN

(12). 样本均衡抑制长尾分布问题

猜你喜欢

转载自blog.csdn.net/Guo_Python/article/details/108148385