【YOLACT】AIでじゃんけん検出

# ➊ はじめに
**リアルタイムで`手の形`を認識**できれば、手話など色々なものへ応用が利きそうですよね。

以前は、[`YOLO`](https://github.com/ultralytics/yolov5)を使用して、**バウンディングボックス**による「じゃんけん」検出を行いました。今回は、[`YOLACT`](https://github.com/dbolya/yolact)を使用して、セグメンテーションによる「じゃんけん」検出ができるかを検証したいと思います。なお、**バウンディングボックス**は画像内の物体の位置やクラスを検出しますが、**セグメンテーション**はそれに加えて画像内の各画素がどのカテゴリーに属するかまで検出するものです。
<img width=400 src='https://user-images.githubusercontent.com/69660581/123023417-4c53eb00-d412-11eb-8b6b-65503252e7f9.gif'>

なお、**セグメンテーション**での認識は、道路を認識したり、人や車を認識したりと**自動運転**などにも利用されている技術です。

# ➋ やること
「じゃんけん画像」から新たに**学習データを作成し**、[`YOLACT`](https://github.com/dbolya/yolact)により、新しい物体がセグメンテーションレベルで認識できるかの検証とそこまでのプロセスの確認をしたいと思います。（認識率云々ではなく、あくまで、物体認識までのプロセス確認がメインターゲットです。）

1. 「じゃんけん画像」から新たに学習データを作成
1. 「じゃんけん」がリアルタイムにセグメンテーションレベルで認識できるかの検証
1. 「じゃんけん」検出の全体プロセスの確認

# ➌ 開発環境
学習は**GPU**が使用できる`Google Colab`で実施し、リアルタイム認識は**webcam**が使える`Local PC`で実施したいと思います。

## (1)開発環境
|開発環境|備考欄|
|:-:|:--|
|Google Colab|学習(モデル生成)時に使用します。Googleアカウントがあれば誰でも無料で使用できます。GPUを利用でき学習スピードがとても早いためこちらを利用します。Google Colabでの利用の仕方は「[`tutorial.ipynb`](https://github.com/ultralytics/yolov5/blob/master/tutorial.ipynb)」を参照すると便利です。|
|Local PC<BR>with<BR>webカメラ|静止画撮影、ラベリング、物体検出時に使用します。今回は`Local PC`として、win10を使用しました。pythonの仮想環境はanacondaを利用しました。|

## (2)使用ツール
### ■Google Colab
|必要なツール類|備考欄|
|:-:|:--|
|[YOLACT](https://github.com/dbolya/yolact)|Google Colab上では、学習(モデル生成)時に使います。フリーウェア(MIT Licence)です。|

### ■ローカルPC
|必要なツール類|備考欄|
|:-:|:--|
|[YOLACT](https://github.com/dbolya/yolact)|ローカルPC上では、物体検出時に使います。|
|[カメラアプリ](https://support.microsoft.com/ja-jp/help/17444/windows-camera-app-webcams-help)<BR>![カメラ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/1486f4b2-57b0-1bc4-2050-0a3f613f398d.png)|win10標準アプリ。静止画撮影時に使います。相応のもので撮影できれば何でもOKです。|
|[coco-annotaror](https://github.com/jsbroks/coco-annotator)|学習データのアノテーションに使用します。フリーウェア(MIT License)です。|

# ➍ 学習データ収集
**➤`Local PC`で作業してください。**

静止画を集めるために、まず`Local PC(win10)`で[**`カメラアプリ`**](https://support.microsoft.com/ja-jp/help/17444/windows-camera-app-webcams-help)を起動し、グー・チョキ・パーの撮影を行います。`Local PC`にwin10以外を使用する方は、相応のアプリで写真を撮ってください。

## (1)カメラアプリ設定
カメラアプリの設定ですが、写真の`解像度を640x480`の設定にしました。`低速度撮影をON`にし、`2秒タイマー`をかけると連続撮影がとても楽です。
<img width="400" alt="カメラアプリ設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/f81fb12c-2f44-24ff-eee5-e5681f13885a.png">

## (2)静止画撮影
「`グー・チョキ・パー`」を色んな角度から写真を撮ってください。私はアノテーション作業を簡素化するために、「`グー・チョキ・パー`」それぞれ単体の写真を各2枚ずつ、計6枚写真を撮りました。（みなさんは、いっぱい撮影してくださいね😅）
<img width="400" alt="カメラアプリ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/ec6c40a6-534d-f698-cf12-a197852c2463.png">

# ➎ アノテーション
**➤`Local PC`で作業してください。**

作業内容は、記事にまとめていますので、[「こちらの記事」](https://qiita.com/PoodleMaster/items/39830656d69d34a39f34)をご参考にアノテーションを作成してください。
**ここでは説明を割愛します。**

<img width=800 src='https://user-images.githubusercontent.com/69660581/123023720-d69c4f00-d412-11eb-92d3-ff5ad8e052ba.png'>

作成したアノテーションデータは、`Local PC`では使用しませんが、後で、学習のため`Google Colab`へコピーしますので、以下のようにまとめておいてください。

``` txt:LocalPC
janken
  │
  ├─choki1.jpg     … 画像データ
  ├─choki2.jpg
  ├─goo1.jpg
  ├─goo2.jpg
  ├─par1.jpg
  ├─par2.jpg
  └─janken.json    … cocoフォーマット
```

※`janken.json`に画像データまでのPATHを記載する部分がありますが、`YOLACT`はここを参照しません。`YOLACT`の`configデータ`に画像までのPATHを記載するようになっていますので、画像のPATHを変更しても`janken.json`の編集は不要です。

# ➏ Google Colab作業
**➤`Google Colab`で作業してください。**
## (1)環境構築
環境構築の詳細は、記事にまとめていますので、[「こちらの記事」](https://qiita.com/PoodleMaster/items/d0bf9cac77e5af61c972)をご参照ください。

### ■ライブラリインストール
``` python:GoogleColab
!pip install cython
!pip install opencv-python pillow pycocotools matplotlib
!pip install torchvision==0.5.0
!pip install torch==1.4.0
```
### ■YOLACTインストール
``` python:GoogleColab
%cd /content
!git clone https://github.com/dbolya/yolact.git
```

## (2)学習データ移行
### ■学習データコピー
先程`Local PC`で作ったアノテーションデータ(`janken`)を`Google Colab`の「`yolact/data/`」配下へコピーしてください。

``` txt:GoogleColab
yolact
  └─data
    └─janken
       ├─choki1.jpg     … 画像データ
       ├─choki2.jpg
       ├─goo1.jpg
       ├─goo2.jpg
       ├─par1.jpg
       ├─par2.jpg
       └─janken.json    … cocoフォーマット
```
※`Google Colab`にコピーしたデータは、揮発しますので、ご注意を！長期的に学習を行う場合は、`Google Drive`等へ格納することをオススメします。

### ■YOLACTのCONFIG書き換え
アノテーションデータ(`janken`)を読み込めるように、「`config.py`」を書き換えます。以下の2箇所に「`janken_dataset`」と「`yolact_resnet50_janken_config`」を追加します。

> 「`config.py`」は、以下の場所にあります。
> yolact/data/config.py

#### ❖1箇所目：「DATASETS」の終わりに以下追加

``` python:GoogleColab（yolact/data/config.py）
                                   ︙
# ----------------------- DATASETS ----------------------- #
                                   ︙
################################# 追加 ####################################### 
janken_dataset = dataset_base.copy({
    'name'        : 'Janken',

    # 学習用
    'train_info'  : 'data/janken/janken.json',
    'train_images': 'data/janken/',

    # 検証用
    'valid_info'  : 'data/janken/janken.json',
    'valid_images': 'data/janken/',

    'has_gt'      : True,

    # クラス名
    # janken.jsonの[categories]-[name]を参照して設定すること
    'class_names' : ('choki', 'goo', 'par',),

    # ラベルマップ
    # janken.jsonの[categories]-[id]を参照して設定すること
    'label_map'   : { 9:1, 10:2, 11:3 }
})
################################# 追加 ####################################### 
                                   ︙
```

#### ❖2箇所目：「YOLACT v1.0 CONFIGS」の終わりに以下追加

``` python:GoogleColab（yolact/data/config.py）
                                   ︙
# ----------------------- YOLACT v1.0 CONFIGS ----------------------- #
                                   ︙
################################# 追加 ####################################### 
yolact_resnet50_janken_config = yolact_resnet50_config.copy({
	'name': 'yolact_resnet50_janken',

	# Dataset stuff
	'dataset': janken_dataset,
	'num_classes': len(janken_dataset.class_names) + 1,

	# Image Size
	'max_size': 640,
})
################################# 追加 ####################################### 
                                   ︙
```

## (3)学習用重みダウンロード
以下コマンドにて、学習用の重み「`resnet50-19c8e357.pth (約100MB)`」を、「`/yolact/weights/`」配下へダウンロードします。

``` python:GoogleColab
%cd /content/download_google_drive
!python download_gdrive.py\
            1Jy3yCdbatgXa5YYIdTCRrSV0S9V5g1rn\
            /content/yolact/weights/resnet50-19c8e357.pth
```


## (4)学習
### ■train.py実行
`train.py`により学習を始めます。`--batch_size=6`としているのは、学習データが6個のため。普通はこんな少ないことは無いと思いますが、学習データが7個以下(8個未満)の場合は、これをつけないとエラーになります。

``` python:GoogleColab
%cd /content/yolact/
!python train.py --config=yolact_resnet50_janken_config\
                 --batch_size=6\
                 --save_folder=weights/
```

### ■train.py実行結果
数分～数時間程度、放ったらかしにし学習を進めさせます…

``` python:GoogleColab
Scaling parameters by 0.75 to account for a batch size of 6.
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
Initializing weights...
Begin training!

/content/yolact/utils/augmentations.py:309: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  mode = random.choice(self.sample_options)
[  0]       0 || B: 5.329 | C: 17.079 | M: 4.833 | S: 2.806 | T: 30.047 || ETA: 19 days, 4:35:06 || timer: 1.554
/content/yolact/utils/augmentations.py:309: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  mode = random.choice(self.sample_options)
/content/yolact/utils/augmentations.py:309: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  mode = random.choice(self.sample_options)

Computing validation mAP (this may take a while)...


Calculating mAP...

       |  all  |  .50  |  .55  |  .60  |  .65  |  .70  |  .75  |  .80  |  .85  |  .90  |  .95  |
-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
   box | 52.59 | 100.0 | 100.0 | 100.0 | 58.58 | 50.17 | 50.17 | 50.17 | 16.83 |  0.00 |  0.00 |
  mask | 95.02 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 75.08 | 75.08 |
-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+

```

## (5)学習終了
### ■学習終了→モデル生成
`Calculating mAP`を見て、良い結果が得られたら学習を中断させます。学習を中断させると、そこまで学習させたネットワークが「`--save_folder`」に生成されます。`Google Colab`での中断のさせ方は、「`ストップボタン`」を押すか、「`CTRL＋MI`」で中断させることができます。
※PCで学習させている場合は、普通に「`CTRL＋C`」で中断です。

``` python:GoogleColab
Stopping early. Saving network...
```

生成されるモデルのファイル名は、「`<config>_<epoch>_<iter>.pth`」となります。
> 例えば、今回はこんな感じのファイル名でモデルが生成されました。yolact/weights/`yolact_resnet50_janken_1364_1364_interrupt.pth` (約120MB)

# ➐ Local PC作業
**➤`Local PC`で作業してください。**
## (1)環境構築
環境構築の詳細は、記事にまとめていますので、[「こちらの記事」](https://qiita.com/PoodleMaster/items/583b841016babaa8e41a)をご参照ください。

### ■Python環境構築
``` python:LocalPC
conda create -n yolact37 python=3.7
conda activate yolact37
```

### ■YOLACTインストール
``` python:LocalPC
git clone https://github.com/dbolya/yolact
cd yolact
```

### ■ライブラリインストール
``` python:LocalPC
pip install cython matplotlib opencv-python "pillow<7.0" PyQt5
pip install "git+https://github.com/philferriere/cocoapi.git#egg=pycocotools&subdirectory=PythonAPI"
pip install torch==1.2.0 torchvision==0.4.0 -f https://download.pytorch.org/whl/torch_stable.html
```
### ■モデルの保存
`Google Colab`で生成したモデル(`yolact_resnet50_janken_1364_1364_interrupt.pth`)を`Local PC`の「`yolact/weights/`」配下へダウンロードします。

## (2)物体検出
それではいよいよ今回のクライマックスです😊ドキドキ❤

### ■eval.py実行
`Local PC`で以下のコマンドを実行してください。
「`--video=0`」を別な番号(0, 1, 2, …)に変えると、別のデバイスを使うこともできます。

``` python:LocalPC
python eval.py --trained_model=weights/yolact_resnet50_janken_1364_1364_interrupt.pth --score_threshold=0.1 --top_k=3 --video_multiframe=1 --video=0
```
### ■eval.py実行結果
学習データがありえないくらい少ない状況でしたが、「`グー・チョキ・パー`」を**リアルタイムでちゃんと認識**できました😄🎉
しかし、学習データをケチったため、認識率はかなり低く、セグメンテーションもちょっと雑ですね。もっと学習データが欲しいです。
<img width=400 src='https://user-images.githubusercontent.com/69660581/123023417-4c53eb00-d412-11eb-8b6b-65503252e7f9.gif'>

# ➑ OMAKE
色々記事を書いているので、まとめておきます。

## (1)画像認識ツール紹介記事
|No.|ツール名|検出ターゲット|環境|記事|Thumbnail|
|:-:|:-|:-|:-|:-|:-:|
|1|[YOLO v5](https://github.com/ultralytics/yolov5)|じゃんけん検出|①GoogleColab<BR>②LocalPC+webcam|[【YOLO V5】AIでじゃんけん検出](https://qiita.com/PoodleMaster/items/5f2cc3248c03b03821b8)|<img width=150 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/3751a28e-af9f-66fa-a74c-008ff716c296.png'>|
|2|[YOLACT](https://github.com/dbolya/yolact)|じゃんけん検出|①GoogleColab<BR>②LocalPC+webcam|[【YOLACT】AIでじゃんけん検出](https://qiita.com/PoodleMaster/items/70cf03c1750fb58debb1)|<img width=150 src='https://user-images.githubusercontent.com/69660581/123023417-4c53eb00-d412-11eb-8b6b-65503252e7f9.gif'>|
|3|[YOLACT](https://github.com/dbolya/yolact)|COCOデータセット|①GoogleColab|[【リアルタム物体検知】YOLACT for Google Colab【YOLOを超えた？】](https://qiita.com/PoodleMaster/items/d0bf9cac77e5af61c972)|<img width=150 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/e2c2d113-2fa5-886d-2e26-204cedd08e8c.gif'>|
|4|[YOLACT](https://github.com/dbolya/yolact)|COCOデータセット|①LocalPC+webcam|[【リアルタム物体検知】YOLACT for win10+webcam【セグメンテーション検出】](https://qiita.com/PoodleMaster/items/583b841016babaa8e41a)|<img width=150 src='https://user-images.githubusercontent.com/69660581/122188431-e83d9e00-ceca-11eb-99b9-dd0a34657088.gif'>|

## (2)アノテーションツール紹介記事
|No.|ツール名|対応フォーマット|対応ツール|記事|Thumbnail|
|:-:|:-|:-|:-|:-|:-:|
|1|[labelImg](https://github.com/tzutalin/labelImg)|YOLO/PascalVOC形式|YOLO v5 …|[【YOLO V5】AIでじゃんけん検出](https://qiita.com/PoodleMaster/items/5f2cc3248c03b03821b8#5-%E3%83%A9%E3%83%99%E3%83%AA%E3%83%B3%E3%82%B0)|<img width=150 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/571f5a99-646f-8cfa-e5c2-eec0a3f57f2f.png'>|
|2|[coco-annotator](https://github.com/jsbroks/coco-annotator)|COCO形式|YOLACT …|[【coco-annotaror】アノテーションツール](https://qiita.com/PoodleMaster/items/39830656d69d34a39f34)|<img width=150 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/584a9a88-66fe-56b3-7e54-9e25eda70844.png'>|

# ➒ 以上
学習データがありえないくらい少なく、また教師データと検証データも同じという最悪の状況でしたが、なんとか**「じゃんけん」を認識してくれました**😊。セグメンテーションで物体検出をさせる場合、**学習データのアノテーション作業がとても時間がかかる作業**となってきます。仕事であれば発注したいレベルです。QiitaのAI好きが集まって「`学習データをみんなで作ろう会`」を発足したい気分でした😁。

ちなみに「じゃんけん」の検出において、セグメンテーション方式で検出する意味はないんじゃないかと思いましたが、AIがなぜそれを「Goo」と認識したのかなど**推論の見える化**ができて、これはこれでありなんじゃないかと思いました。

技術はどんどん進化していて、数年後にはこの技術も当たり前になっていると思うと、なんかワクワクしてきますね😉。

お疲れ様でした！