中文情報しかないSOTA2019 of Realtime object detectionのMMDetectionを動かす

# 0. Introduction
YOLO v3が一番高性能なんでしょ？何て言うのは束の間、既により高性能な新しいアルゴリズムがいくつも提案されている模様。
そこで、以下の1位(HTC+DCN+ResNet+FPN)であるMMDetectionを動作させたいと考えている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95636/7cf26441-7fd4-c649-a617-4dd7624b590f.png)

Multimedia Labolatroyという香港の大学が開発したものらしい。
https://arxiv.org/abs/1906.07155

案の定、中国語しか情報がない。
頑張って読んで行こう。

# 1. Installation
安装方法について説明する。

## Environment
取り合えず環境として以下を整える

```
CUDA=10.0
CUDNN=7.6.2
python=3.7
pytorch=1.2
cython
```

様々な安装方法があるみたいなので、動いた方法を以下に記す。

```
$ conda create -n open-mmlab python=3.7 -y
$ source activate open-mmlab
$ conda install pytorch torchvision -c pytorch
$ pip install mmcv
$ pip install scikit-learn
$ pip install cython
```

これで多分、環境は整うはず。
公式にも書かれていないいくつかの依存ライブラリがあるので
エラーが出るようなら、追加でインストールして適宜処置してください。

## Download
Gitからデータを持ってくる

```
$ git clone https://github.com/open-mmlab/mmdetection.git
```

おもむろにDocsを見てみる

```
$ cd docs
$ cat INSTALL.md
```

インストール方法が全部書かれている！と思いきや、殆ど動かない。

取り合えず、ルートディレクトリで以下を実行

```
python setup.py develop
```

放っておくと、`Finished processing dependencies for mmdet==1.0rc0+c5c7ef9`なんて表示されて終わっている。

## Datasets
`http://cocodataset.org/#download`に接続し、次をダウンロード

```
$ aria2c -x5 http://images.cocodataset.org/zips/train2017.zip
$ aria2c -x5 http://images.cocodataset.org/zips/val2017.zip
$ aria2c -x5 http://images.cocodataset.org/zips/test2017.zip
$ aria2c -x5 http://images.cocodataset.org/annotations/annotations_trainval2017.zip
```

次に、データを以下のように配置しよう

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

以下のような感じで既にダウンロード済みのファイルを`mmdetection`の各ディレクトリにリンクを張ろう。

```
$ mkdir coco
$ cd coco
$ ln -s /data/coco/annotations annotations
```

# 2. Training
`mmdetection`のルートディレクトリで作業を行う。

以下のコマンドで学習を開始できる。

```
$ python ./tools/train.py ./configs/ssd512_coco.py
```

学習が開始されれば以下のように表示される。

```
2019-09-10 10:25:19,585 - INFO - Epoch [1][50/73292]    lr: 0.00080, eta: 12 days, 8:25:21, time: 0.607, data_time: 0.031, memory: 6449, loss_cls: 18.6068, loss_bbox: 3.2373, loss: 21.8441
2019-09-10 10:25:43,886 - INFO - Epoch [1][100/73292]   lr: 0.00093, eta: 11 days, 2:57:32, time: 0.486, data_time: 0.014, memory: 6449, loss_cls: 12.4040, loss_bbox: 3.2519, loss: 15.6559
2019-09-10 10:26:08,312 - INFO - Epoch [1][150/73292]   lr: 0.00106, eta: 10 days, 17:30:14, time: 0.488, data_time: 0.014, memory: 6449, loss_cls: 8.3587, loss_bbox: 3.0604, loss: 11.4191
```

基本的には`configs`を変えれば、事前にプリセットで多く用意されているモデルを試すことが出来る。

## SOTA
次に最高性能を出すといわれている`Hybrid task cascade for instance segmentation`の`configs`を動かす。

このためには、cocoのstuffデータが必要。

```
$ aria2 -x5 http://calvin.inf.ed.ac.uk/wp-content/uploads/data/cocostuffdataset/stuffthingmaps_trainval2017.zip
$ unzip stuffthingmaps_trainval2017.zip
$ ln -s /data/coco/stuffthingmaps_trainval2017 stuffthingmaps
```

以下のようにリンクを張ろう。

```
mmdetection
├── mmdet
├── tools
├── configs
├── data
│   ├── coco
│   │   ├── annotations
│   │   ├── train2017
│   │   ├── val2017
│   │   ├── test2017
|   |   ├── stuffthingmaps
```

では、学習を行う。

```
$ python ./tools/train.py ./configs/htc/htc_r101_fpn_20e.py
```

学習が始まると以下のように表示される。

```
2019-09-10 13:50:18,500 - INFO - Epoch [1][50/58633]    lr: 0.00797, eta: 13 days, 4:27:21, time: 0.972, data_time: 0.053, memory: 7557, loss_rpn_cls: 0.4004, loss_rpn_bbox: 0.0736, loss_semantic_seg: 1.0111, s0.loss_cls: 0.7468, s0.acc: 92.9082, s0.loss_bbox: 0.1077, s0.loss_mask: 0.7450, s1.loss_cls: 0.2681, s1.acc: 95.2305, s1.loss_bbox: 0.0332, s1.loss_mask: 0.3974, s2.loss_cls: 0.1186, s2.acc: 96.0312, s2.loss_bbox: 0.0058, s2.loss_mask: 0.2093, loss: 4.1170
2019-09-10 13:51:07,826 - INFO - Epoch [1][100/58633]   lr: 0.00931, eta: 13 days, 6:52:50, time: 0.987, data_time: 0.040, memory: 7557, loss_rpn_cls: 0.3023, loss_rpn_bbox: 0.0903, loss_semantic_seg: 0.9507, s0.loss_cls: 0.4658, s0.acc: 94.3926, s0.loss_bbox: 0.1136, s0.loss_mask: 0.6911, s1.loss_cls: 0.1425, s1.acc: 96.9160, s1.loss_bbox: 0.0350, s1.loss_mask: 0.3428, s2.loss_cls: 0.0523, s2.acc: 97.9414, s2.loss_bbox: 0.0057, s2.loss_mask: 0.1716, loss: 3.3637
2019-09-10 13:51:58,157 - INFO - Epoch [1][150/58633]   lr: 0.01064, eta: 13 days, 9:51:44, time: 1.007, data_time: 0.041, memory: 7717, loss_rpn_cls: 0.2357, loss_rpn_bbox: 0.0748, loss_semantic_seg: 0.9145, s0.loss_cls: 0.5364, s0.acc: 92.7969, s0.loss_bbox: 0.1564, s0.loss_mask: 0.6763, s1.loss_cls: 0.1477, s1.acc: 96.3887, s1.loss_bbox: 0.0472, s1.loss_mask: 0.3368, s2.loss_cls: 0.0493, s2.acc: 97.8340, s2.loss_bbox: 0.0067, s2.loss_mask: 0.1698, loss: 3.3514
2019-09-10 13:52:48,686 - INFO - Epoch [1][200/58633]   lr: 0.01197, eta: 13 days, 11:40:01, time: 1.011, data_time: 0.037, memory: 7717, loss_rpn_cls: 0.1984, loss_rpn_bbox: 0.0664, loss_semantic_seg: 0.8763, s0.loss_cls: 0.4840, s0.acc: 93.7109, s0.loss_bbox: 0.1395, s0.loss_mask: 0.6760, s1.loss_cls: 0.1330, s1.acc: 96.7891, s1.loss_bbox: 0.0440, s1.loss_mask: 0.3355, s2.loss_cls: 0.0423, s2.acc: 98.1230, s2.loss_bbox: 0.0064, s2.loss_mask: 0.1665, loss: 3.1682
2019-09-10 13:53:38,486 - INFO - Epoch [1][250/58633]   lr: 0.01331, eta: 13 days, 11:47:47, time: 0.996, data_time: 0.037, memory: 7744, loss_rpn_cls: 0.2124, loss_rpn_bbox: 0.0726, loss_semantic_seg: 0.8794, s0.loss_cls: 0.4503, s0.acc: 94.1387, s0.loss_bbox: 0.1260, s0.loss_mask: 0.6697, s1.loss_cls: 0.1218, s1.acc: 97.0117, s1.loss_bbox: 0.0362, s1.loss_mask: 0.3280, s2.loss_cls: 0.0416, s2.acc: 98.1328, s2.loss_bbox: 0.0047, s2.loss_mask: 0.1629, loss: 3.1054
```

# 3. Testing
Testは以下のコマンドで実行できる

```
python ./tools/test.py ./configs/htc/htc_r50_fpn_1x work_dirs/htc_r50_fpn_1x/epoch_2.pth --out results.pkl --eval bbox segm
```
全ての結果は`results.pkl`に格納されるため、これを参照して1つ1つ結果を取りだしてもよい。

## Detection detail
以下のコードで1枚1枚の識別を可能とする

``` python
from mmdet.apis import init_detector, inference_detector, show_result
import mmcv

config_file = '../configs/htc/htc_r50_fpn_1x.py'
checkpoint_file = '../work_dirs/htc_r50_fpn_1x/epoch_2.pth'

model = init_detector(config_file, checkpoint_file, device='cuda:0')

img = '/data/0.jpg'
result = inference_detector(model, img)
show_result(img, result, model.CLASSES)
```