ショートカット

カスタマイズされたモデルと標準データセットとのトレーニング

このメモでは、標準データセットで独自のモデルのカスタマイズ、テスト、推論を行う方法を学習します。標準的な Cascade Mask R-CNN R50 モデルのカスタマイズされたトレーニングには、Cityscapes データセットを使用します。その方法を説明するための例として、デフォルトの FPN をネックとして使用し、トレーニング時に自動拡張として Rotate または TranslateX を追加し、AugFPN を使用します。

基本的な手順は次のとおりです。

  1. 標準データセットの準備

  2. 独自のモデルのカスタマイズの準備

  3. 設定の準備

  4. 標準データセットのモデルのトレーニング、テスト、推論。

標準データセットの準備

このメモでは、標準的な Cityscapes データセットを例として使用します。

データセットルートを $MMDETECTION/data にシンボリックリンクすることをお勧めします。フォルダ構造が異なる場合は、設定ファイルの対応するパスを変更する必要があります。

mmdetection
├── mmdet
├── tools
├── configs
├── data
│   ├── coco
│   │   ├── annotations
│   │   ├── train2017
│   │   ├── val2017
│   │   ├── test2017
│   ├── cityscapes
│   │   ├── annotations
│   │   ├── leftImg8bit
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── gtFine
│   │   │   ├── train
│   │   │   ├── val
│   ├── VOCdevkit
│   │   ├── VOC2007
│   │   ├── VOC2012

または、次からデータセットルートを設定できます。

export MMDET_DATASETS=$data_root

データセットルートを $MMDET_DATASETS に置き換えるので、設定ファイルの対応するパスを変更する必要はありません。

Cityscapes のアノテーションは tools/dataset_converters/cityscapes.py を使用して coco フォーマットに変換する必要があります。

pip install cityscapesscripts
python tools/dataset_converters/cityscapes.py ./data/cityscapes --nproc 8 --out-dir ./data/cityscapes/annotations

現在、cityscapes の設定ファイルでは、初期化するために COCO 事前トレーニング済みの重みを使用します。ネットワークが利用できないか遅い場合は、事前に事前トレーニング済みのモデルをダウンロードできます。それ以外の場合は、トレーニングの開始時にエラーが発生します。

独自のモデルのカスタマイズの準備

2 番目の手順では、独自のモジュールまたはトレーニング設定を使用します。既存のディテクタ Cascade Mask R-CNN R50 のデフォルトの FPN を、AugFPN という新しいネックに置き換える実装を想定しています。以下では、MMDetection で AugFPN を実装する方法を説明します。

1. 新しいネックの定義(例: AugFPN)

まず、mmdet/models/necks/augfpn.py という新しいファイルを作成します。

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 に追加するか、

from .augfpn import AugFPN

または、

custom_imports = dict(
    imports=['mmdet.models.necks.augfpn'],
    allow_failed_imports=False)

設定ファイルに追加して、元のコードの変更を回避できます。

3. 設定ファイルを修正する

neck=dict(
    type='AugFPN',
    in_channels=[256, 512, 1024, 2048],
    out_channels=256,
    num_outs=5)

独自のモデルのカスタマイズ(例:新しいバックボーン、ヘッド、ロスの実装など)やランタイムトレーニング設定(例:新しいオプティマイザの定義、勾配クリップの使用、トレーニングスケジュールやフックのカスタマイズなど)の詳細な使用方法については、ガイドラインCustomize ModelsおよびCustomize Runtime Settingsを参照してください。

設定ファイルを準備する

3番目のステップは、独自のトレーニング設定の設定ファイルを準備することです。AugFPNRotateまたはTranslateオーギュメンテーションを既存のカスケードマスクR-CNN R50に追加し、Cityscapesデータセットをトレーニングすると想定します。また、設定ファイルはディレクトリconfigs/cityscapes/にあり、cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes.pyという名前で保存されていると想定します。設定ファイルは次のようになります。

# The new config inherits the base configs to highlight the necessary modification
_base_ = [
    '../_base_/models/cascade-mask-rcnn_r50_fpn.py',
    '../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py'
]

model = dict(
    # set None to avoid loading ImageNet pre-trained backbone,
    # instead here we set `load_from` to load from COCO pre-trained detectors.
    backbone=dict(init_cfg=None),
    # replace neck from defaultly `FPN` to our new implemented module `AugFPN`
    neck=dict(
        type='AugFPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        num_outs=5),
    # We also need to change the num_classes in head from 80 to 8, to match the
    # cityscapes dataset's annotation. This modification involves `bbox_head` and `mask_head`.
    roi_head=dict(
        bbox_head=[
            dict(
                type='Shared2FCBBoxHead',
                in_channels=256,
                fc_out_channels=1024,
                roi_feat_size=7,
                # change the number of classes from defaultly COCO to 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,
                # change the number of classes from defaultly COCO to 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,
                # change the number of classes from defaultly COCO to 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,
            # change the number of classes from default COCO to cityscapes
            num_classes=8,
            loss_mask=dict(
                type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))))

# over-write `train_pipeline` for new added `AutoAugment` training setting
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'),
]

# set batch_size per gpu, and set new training pipeline
train_dataloader = dict(
    batch_size=1,
    num_workers=3,
    # over-write `pipeline` with new training pipeline setting
    dataset=dict(pipeline=train_pipeline))

# Set optimizer
optim_wrapper = dict(
    type='OptimWrapper',
    optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001))

# Set customized learning policy
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, val, test loop config
train_cfg = dict(max_epochs=10, val_interval=1)

# We can use the COCO pre-trained Cascade Mask R-CNN R50 model for a more stable performance initialization
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'

新しいモデルをトレーニングする

新しい設定ファイルを使用してモデルをトレーニングするには、次を実行します。

python tools/train.py configs/cityscapes/cascade-mask-rcnn_r50_augfpn_autoaug-10e_cityscapes.py

詳細な使用方法については、トレーニングガイドを参照してください。

テストと推論

トレーニングされたモデルをテストするには、次を実行します。

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

詳細な使用方法については、テストガイドを参照してください。