自前データをアノテーションしてMask R-CNNを学習させる

**Instance Segmentation**(物体検出+セグメンテーション) をするために
- 自前データを**アノテーション**
- **Mask R-CNN**を学習
ということを行なったのですが、他に役立つ記事が見当たらず苦労したので
メモ程度ですが僕が行なった手順を共有します。

Mask R-CNNについての解説は省略します。
以下を参考にしてください。
[最新のRegion CNN(R-CNN)を用いた物体検出入門 ~物体検出とは? R-CNN, Fast R-CNN, Faster R-CNN, Mask R-CNN~](https://qiita.com/arutema47/items/8ff629a1516f7fd485f9)

Mask R-CNNの実装は以下のレポジトリを利用しています。
https://github.com/facebookresearch/maskrcnn-benchmark

# Labelmeによるデータ作成

https://github.com/wkentaro/labelme
基本的には上の `README.md`の通りです
以下にざっとまとめます

## インストール
`$ pip install labelme`でも入るのですが、後ほどデータ変換でスクリプトを使うので `git clone` します

```.sh
$ git clone https://github.com/wkentaro/labelme.git
$ cd labelme
$ pip install -e .
```

## 起動
クラス名を改行で羅列した`class.txt`を作成してください。データの変換の際にエラーが出るかもなので一行目に`__ignore__`を追加します。
例:

```classes.txt
__ignore__
person
bicycle
car
...
```

以下のコマンドでlabelmeを起動します

```.sh
$ labelme <データフォルダのpath> --labels <classes.txtのpath> --nodata
```

## アノテーション
物体の境界をポチポチクリックしていくだけでできます。
以下サイトが参考になります。非常に簡単にアノテーションができます。
[セマンティックセグメンテーションの実装方法 -データの準備-]
(https://hituji-ws.com/code/python/dl-seg1/)


## データ形式変換
作成されたアノテーションデータ、元画像をMask R-CNN用に変換します。

```.sh
$ cd labelme/examplts/instance_segmentation
$ ./labelme2coco.py <データフォルダのpath> <作成するディレクトリ名> --labels <classes.txt>
```
これによって
`<作成するディレクトリ名>/JPEGImages`    ・・・画像が入ったディレクトリ
`<作成するディレクトリ名>/annotations.json` ・・・アノテーション情報が記されたjsonファイル
 が作成されます

# maskrcnnを学習させる
## インストール
https://github.com/facebookresearch/maskrcnn-benchmark
上を`README.md`にしたがってインストール

以下の記事が参考になります。
[Pytorch1.1+MaskRCNNで自前データ訓練(1)](https://qiita.com/kuroyagi/items/e66ca85f8d118c07eb95#7-%E8%A8%93%E7%B7%B4%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E8%87%AA%E5%88%86%E3%81%A7%E6%8E%A8%E8%AB%96)


## データ配置
データをmaskrcnnが読み込める位置に配置する 

上で作成した
`JPEGImages`,
`annotations.json`
を
`maskrcnn_benchmark/datasets/<新ディレクトリ名>/`
に配置

## データ登録
`maskrcnn_benchmark/config/paths_catalog.py` の `DATASETS` に以下を追加

COCO形式であることを読み込ませるために、**"新データ名"**に**COCO**を含ませるようにしてください。

```.json
"新データ名" : {
    "img_dir" : "<新ディレクトリ名>"
    "ann_file" : "<新ディレクトリ名>/annotations.json"
} 
```

## 学習実行
以上の処理で、**学習用** ,**テスト用** のデータを登録してください。

以下にて学習を開始できるはずです。

```.sh
$ python tools/train_net.py --config-file configs/e2e_mask_rcnn_R_50_FPN_1x.yaml DATASETS.TRAIN "(\"<新データ名(学習用)>\",)" DATASETS.TEST "(\"<新データ名(テスト用)>\",)"
```

`--config-file`を`configs/`から指定することで、ネットワーク構造等のconfigを指定できます。
**学習率**や**バッチサイズ**を変更したいときは、実行時に記すことで変更できます

例:

```.py
$ python tools/train_net.py --config-file configs/e2e_mask_rcnn_R_50_FPN_1x.yaml DATASETS.TRAIN "(\"<新データ名(学習用)>\",)" DATASETS.TEST "(\"<新データ名(テスト用)>\",)" SOLVER.BASE_LR 0.0025 SOLVER.IMS_PER_BATCH 2 TEST.IMS_PER_BATCH 1
```
`SOLVER.BASE_LR` : 学習スタート時の学習率 (逓減していきます )
`SOLVER.IMS_PER_BATCH` : 学習時バッチサイズ
`TEST.IMS_PER_BATCH` : テスト時バッチサイズ

全パラメータは
[maskrcnn_benchmark/config/defaults.py](https://github.com/facebookresearch/maskrcnn-benchmark/blob/master/maskrcnn_benchmark/config/defaults.py)
に書いてあります。

# 注意点
### 同じラベルの別物体が１つの物体として認識されてしまう
`labelme`のデータ変換時に、デフォルトだとまとめて１つの物体として認識するようになっています。
別々に認識させたい場合は、`labelme2coco.py`を以下にしたがって修正してください。
https://github.com/wkentaro/labelme/issues/419#issuecomment-511853597

### セグメンテーションが一つの物体にしか行われない
学習の際に`Pytorch`のバージョンによってラベルが全て一つの物体に対して作成されてしまうようです。

[maskrcnn_benchmark/data/datasets/coco.py#L94](https://github.com/facebookresearch/maskrcnn-benchmark/blob/57eec25b75144d9fb1a6857f32553e1574177daf/maskrcnn_benchmark/data/datasets/coco.py#L94)
の挙動が予期せぬものとなっていることがあるので
`target = target.clip_to_image(remove_empty=True)` を
`target = target.clip_to_image(remove_empty=False)`
に変更してください。

　
　
以上になります。
ありがとうございました！