AWS DeepRacer検出モデルを作ってみた（データ準備編）

# はじめに
オブジェクト検出（object detection）アルゴリズムを利用してAWS DeepRacerを検出するモデルを作ってみました。
作成したモデルは、ラップタイム計測や走行軌跡の視覚化などに活用できそうです。
AWS DeepRacerは機械学習の中では「強化学習」という手法ですが、今回は「教師あり学習」について学んだことを公開します。

本記事では、AWS DeepRacer検出モデルのデータ準備について説明しています。
その他の内容については、以下の記事をご確認ください。

- [AWS DeepRacer検出モデルを作ってみた（データ準備編）](https://qiita.com/dnp-ayako/items/31cb5ff63346296aecfa)※本記事
- [AWS DeepRacer検出モデルを作ってみた（モデル作成編）](https://qiita.com/dnp-ayako/items/56bf9aa2e5d146b9ff12)
- [AWS DeepRacer検出モデルを使ってみた（実践編）](https://qiita.com/dnp-ayako/items/fb6de68391a6246cb199)

#### こんな人におすすめ

- AWS DeepRacerをきっかけに初めて機械学習に触れた。（筆者のレベル）
- 教師あり学習、オブジェクト検出モデル作成に興味がある。
- Amazon Rekognition Videoや公開されているデータセットでオブジェクト検出を試してみたが、検出対象が一般化されておらず期待している精度がでなかった。
- シミュレーションと現実世界の比較をしたい、視覚化をしたい。
 - [AWS DeepRacerの走行軌跡を手で描画して比較してみた記事はこちら](https://qiita.com/dnp-ayako/items/a1c902daf882ef2f86c7)

# データ準備の概要
教師あり学習は多くの正解データが必要となるため、１～２の作業は当社のAWS DeepRacerチームに「みんなでAWS DeepRacer検出モデルを作ってみよう」と呼び掛け、協力してくれたメンバーと楽しみながら行いました。

1. 素材選定・収集
2. タグ付け作業（アノテーション）
3. データ変換、ファイル配置
4. S3にアップロード

# 1. 素材選定・収集
タグ付け作業に使う素材は[AWSシンガポールSummitのリーグ参加](https://qiita.com/dnp-hara/items/fdebbbc04d4c1daa44d2)、AWS東京Summitのリーグ参加で記録した動画や写真を使いました。

#### ポイント

- 同じデータが混在しないように、各個人で撮影した素材を使う
- 効率よく正解データを作成するため、写真より動画を使う
- 動画はmp4、写真の拡張子はjpgとする（拡張子のjpegは変更しておく）
- 同じファイル名にならないよう、ファイル名は社員番号を付けるなどユニークにしておく
- モデルの用途が主にコース上で使う想定のため、レース中心の素材を使う
- モデルの用途が動いている物体の検出をするため、多少ブレている動画、写真もOKとする


上記ポイントは実施してみて後からわかったことも含めています。
ファイル名の変更は後からでも可能ですが、収集段階で済ませておくと後工程で余計な作業をせずに楽になります。
また、作成したモデルをどのような場面、条件で利用するのかを事前に共有しておくとより適した素材選定ができるようになります。

# 2. タグ付け作業（アノテーション）

タグ付けにはMicrosoftから提供されているVoTTというアノテーションソフトを利用します。
AWSにもSageMaker Ground Truthというタグ付けサービスがありますが、現時点では動画は対応していないので、動画が使えるソフトを利用します。

VoTT
https://github.com/Microsoft/VoTT/releases
※本記事ではmac OS版のversion2.1.0を利用しています

#### VoTTを起動
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/97f6ade7-9e3f-ad6d-604a-f0a62ab6f510.png)

#### プロジェクト設定
コメントの無い項目はデフォルト値のままとしています。
![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/4728ffea-267e-1a1b-de5a-88fb111052ba.png)

#### 入力ソースの設定（Source connection）
![2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/7ab2ba8f-85e2-bb6a-adce-20ddcbfef181.png)

#### 出力ソースの設定（Target connection）
![2-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/0470829a-e228-13c4-d483-ecff1015e76f.png)

#### プロジェクト設定（続き）
![2-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/3fe312b6-cebd-4d05-47fc-57978bf81065.png)
![2-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/cdc20b50-e6c8-f6fb-6ccc-016a806cfc1d.png)

#### 動画ファイルの選択
![2-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/c090c355-81c5-55a7-026a-f18f7dd5321b.png)

#### タグ付け作業　①～③の手順を繰り返す
![2-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/726661af-de85-9938-7cca-c2578957ea6e.png)

#### （例）AWS DeepRacerをタグ付けした画面
![2-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/1d8be3e3-41e0-f5cb-76a9-afd7a5da8315.png)

#### データ出力（エクスポート）の設定
![2-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/a814dbb6-1c24-b4c4-1c7e-05c7c83c856e.png)

#### データ出力（エクスポート）の実行
![2-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426326/5151d55f-2245-bccc-81f4-f94971d8a1ad.png)

VoTTのTarget Connectionで指定したローカルの出力先に以下のような構成でファイルが出力されます。

```ruby:
[指定したローカル出力先]/
    vott-json-export/
        [ファイル名][フレーム情報].jpg	# 動画から切り出された画像（複数ファイル）
        [プロジェクト名]-export.json	# 座標とタグ情報を含むjsonファイル（１ファイル）
```


# 3. データ変換、ファイル配置
今回、オブジェクト検出の入力インターフェースにイメージ形式を選択しました。そのため、
VoTTでエクスポートされたjsonファイルをSageMaker用にフォーマット変換、分割を行います。
その後、画像ファイルとjsonファイルを４つのフォルダに分けて配置します。

[Amazon SageMaker開発者ガイド　オブジェクト検出アルゴリズムの入出力インターフェイス](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/object-detection.html#object-detection-inputoutput)

#### jsonファイルの変換、分割
フォーマット変換、分割を一括で行うスクリプトは以下のサイトを参考にしました。ありがとうございました。
[SageMakerで「うまい棒検出モデル」を作ってみた](https://dev.classmethod.jp/cloud/aws/sagemaker-umaibo-object-detection/)
[Amazon SageMakerで物体検出（うまい棒検出の記事を補足）](https://qiita.com/mhiro216/items/e7b3a4bbca591edd7141)

上記サイトのスクリプトを元に以下の調整、修正をしました。

- 入力ファイルと出力先を引数から指定できるように変更
- タグの種類（class）をdeepracerの1つに変更
- ファイル名に複数.(ドット)が含まれる場合を想定して抽出条件を変更

```python:convert_json.py
import json
import sys

args = sys.argv

input_file = args[1]		# 入力jsonファイル
output_dir = args[2]		# 出力先ディレクトリ
class_list = {'deepracer': 0}	# タグの種類はdeepracer１つ

with open(input_file) as f:
    js = json.load(f)

    for k, v in js['assets'].items():

        fileno = v["asset"]["name"].split(".jpg")[0]		#ファイル名の抽出条件を変更

        line = {}
        line['file'] = fileno + '.jpg'
        line['image_size'] = [{
            'width':v["asset"]["size"]["width"],
            'height':v["asset"]["size"]["height"],
            'depth':3
        }]

        line['annotations'] = []

        for annotation in v["regions"]:

            line['annotations'].append(
                {
                    'class_id':class_list[annotation['tags'][0]],
                    'top':annotation['boundingBox']["top"],
                    'left':annotation['boundingBox']["left"],
                    'width':annotation['boundingBox']["width"],
                    'height':annotation['boundingBox']["height"]
                }
            )

        line['categories'] = []

        for name, class_id in class_list.items():

            line['categories'].append(
                {
                    'class_id':class_id,
                    'name':name
                }
            )

        f = open(output_dir + '/' + fileno + '.json', 'w')
        json.dump(line, f)
        f.close()
```

#### スクリプトの実行例
```ruby:
# 第一引数 VoTTで生成されたjsonファイル、第二引数 出力先フォルダ
$ python3 ./convert_json.py vott-json-export/20190801-export.json ./output
```

実行例では、vott-json-export/20190801-export.jsonファイルを読み込み、outputディレクトリ以下に　画像ファイル名.json として分割された複数ファイルを生成します。
アノテーションに協力してくれたメンバーそれぞれがVoTTで生成したjsonファイルを全て変換し、最終的に画像ファイルの数とjsonファイルの数が一致することを確認します。

今回は**2878個のデータセット（jpg＋json）**ができました！


#### 出力ファイルの配置
作成したデータセットをSageMakerの入力インターフェースの形式に合わせるため、４つのフォルダに格納します。

```ruby:
train/			# トレーニング用　jpg画像を格納します
train_annotation/	# トレーニング用　json画像を格納します
validation/		# バリデーション用　jpg画像を格納します
validation_annotation/	# バリデーション用　json画像を格納します
```

バリデーションデータはトレーニング用と同じデータにならないように、今回出力したファイルの中から一部を選んで格納します。

同じ場面、画像に偏らないように、拡張子を除いたファイル名が2で終わるファイル（動画で出力するとフレーム情報にあたる数値で分別）をバリデーションに移動します。

```ruby:
$ mv -i *2.jpg ./validation/
$ mv -i *2.json ./validation_annotation/
```

これにより、トレーニング用データは2661個、バリデーションデータは217個となりました。

# 4. S3にアップロード
SageMakerが読み込むトレーニング用のS3バケットに４つのフォルダごとアップロードします。

AWS CLIを使う場合は以下のようにします。

```ruby:
$ ls
train            train_annotation    validation        validation_annotation
$ aws s3 cp ./ s3://[S3バケット名] /[任意のフォルダ]/ --recursive
```

アップロードが終われば、データの準備は完了です！

次はJupyterNotebookを使ったオブジェクト検出モデルの作成を行います。
[AWS DeepRacer検出モデルを作ってみた（モデル作成編）](https://qiita.com/dnp-ayako/items/56bf9aa2e5d146b9ff12)