【MMDetection】 既存モデルの学習編

## 概要
まだまだ日本語情報が少ない物体検出フレームワーク"MMDetection"について、学んだことを記録していこうと思います。間違い等ありましたらぜひコメントで教えてください。よろしくお願いします。

前回：[学習済モデルで物体検出編](https://qiita.com/bellpond/items/33c15c8eb62f46a51aba)

今回はMMDetectionを用いて、既存のモデルを学習する方法をまとめたいと思います。

## 既存モデルについて
MMDetectionでは、モジュールを組み合わせることでモデルを設計します。モデルの設計（と学習方法）は`mmdetecion/configs/*/*.py`に記述し、これをconfigファイルと呼びます。

MMDetectionでは、あらかじめ多数の有名なモデルのconfigファイルが用意されています。今回はこれらのconfigファイルを使って既存モデルの学習をしてみようと思います。

## configのファイル名について
`mmdetection/configs/*/`を覗くと多数のconfigファイルが見つかります。
これらは、そのファイル名からそのモデルの概要が理解できるように命名されています。
大まかには以下のように命名されています。詳細なルールは[こちら](https://mmdetection.readthedocs.io/en/latest/tutorials/config.html#config-name-style)。

```
{model}_{backbone}_{neck}_{schedule}_{dataset}.py
```

- {model}: モデル名（例：`faster_rcnn`, `mask_rcnn`）
- {backbone}：バックボーンのモデル名（例：`r50`(ResNet-50), `x101`(ResNeXt-101)`）
- {neck}：ネック（バックボーンの次のモジュール）（例：`fpn`, `pafpn`）
- {schedule}：学習エポック数。`1x`(12epochs), `2x`(24epochs), `20e`(20epochs)のどれか。
- {dataset}：データセット名（例：`coco`, `cityscapes`）


例えば`faster_rcnn_r50_fpn_1x_coco.py`の場合

- Faster R-CNN
- バックボーンはResNet-50
- ネックは[Feature Pyramid Networks](https://arxiv.org/abs/1612.03144)
- 学習エポック数は12
- coco datasetを使って学習する

## データセットの準備
今回は[COCOデータセット](https://cocodataset.org/#home)を使いたいと思います。
### 1. データセットのダウンロード
[こちら](https://gist.github.com/mkocabas/a6177fc00315403d31572e17700d7fd9)にダウンロード用のシェルスクリプト（公式ではない）が公開されているのでこれを実行するのが楽だと思います。

```bash
# データセットを管理しているディレクトリで実行する。（自分の場合は ~/data ）
bash coco.sh
```

### 2. データセットへのシンボリックリンクを張る。
`mmdetection/data/coco`ディレクトリを作成して、その下にデータセットへのシンボリックリンクを張ります。

```
mkdir data
cd data
mkdir coco
cd coco

ln -s [cocoデータセットのディレクトリまでのパス]/train2017 train2017
ln -s [cocoデータセットのディレクトリまでのパス]/val2017 val2017
ln -s [cocoデータセットのディレクトリまでのパス]/test2017 test2017
ln -s [cocoデータセットのディレクトリまでのパス]/annotations_trainval2017 annotations
```

## 既存モデルの学習
学習用のコードが用意されているので、簡単に学習を実行できます。
今回は、`configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py`を使ってFaster R-CNNを学習します。

学習は以下のコマンドで行えます。
※ 平気で1日かかったりするので注意しましょう。

```bash
python ./tools/train.py ./configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py
```

学習を実行すると、`mmdetection/work_dirs/faster_rcnn_r50_fpn_1x_coco`というディレクトリに、学習されたパラメータや学習のログ、configファイルのコピー等が作成されます。

このディレクトリ名は、学習実行時にオプションで`--work-dir [ディレクトリ名]`という風に設定できます。

## 評価
評価は以下のコマンドで行えます。

```bash
python tools/test.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py work_dirs/faster_rcnn_r50_fpn_1x_coco/epoch[エポック数].pth --eval bbox
```
しばらく待つと以下のようにモデルの評価が表示されます。

```
Evaluating bbox...
Loading and preparing results...
DONE (t=1.47s)
creating index...
index created!
Running per image evaluation...
Evaluate annotation type *bbox*
DONE (t=33.02s).
Accumulating evaluation results...
DONE (t=5.76s).
Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.374
Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=1000 ] = 0.581
Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=1000 ] = 0.404
Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=1000 ] = 0.212
Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=1000 ] = 0.410
Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=1000 ] = 0.481
Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.517
Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=300 ] = 0.517
Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=1000 ] = 0.517
Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=1000 ] = 0.326
Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=1000 ] = 0.557
Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=1000 ] = 0.648
OrderedDict([('bbox_mAP', 0.374), ('bbox_mAP_50', 0.581), ('bbox_mAP_75', 0.404), ('bbox_mAP_s', 0.212), ('bbox_mAP_m', 0.41), ('bbox_mAP_l', 0.481), ('bbox_mAP_copypaste', '0.374 0.581 0.404 0.212 0.410 0.481')])
```

## おまけ
今回学習したモデルを使って画像の物体検出をする実験は、前回の「[学習済モデルで物体検出編](https://qiita.com/bellpond/items/33c15c8eb62f46a51aba#1-%E3%83%86%E3%82%B9%E3%83%88%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E4%BD%9C%E6%88%90)」で紹介した方法でできると思います！

あと、リンクを「張る」とリンクを「貼る」で一瞬迷ったのですが、軽く調べたところ「張る」が正しいようです。

## 参考資料
- [公式ドキュメント](https://mmdetection.readthedocs.io/en/latest/index.html)
- [中文情報しかないSOTA2019 of Realtime object detectionのMMDetectionを動かす](https://qiita.com/harmegiddo/items/55da6020314a12ba5479)