【YOLOv5】自作データを使って顔検出を行う

超解像コンペの側、物体検出も勉強してみようということで、有名なYOLOモデルの最新版を動かしてみて、自作データの作成、学習までの方法を紹介します。

# 環境
Mac OS Monterey ver12
python: 3.8.12
PyTorch: 1.9.0

# 学習済みモデルの準備
普段ならJupyterやColabでモデルを構築して学習させてとやるところですが、YOLOに関してはGithub上からリポジトリを引っ張ってきて学習させます。

```shell:ターミナル
# 作業フォルダ作成
mkdir YOLOv5
cd YOLOv5

# リポジトリをコピー,移動
git clone https://github.com/ultralytics/yolov5
cd yolov5
```
以降このリポジトリ内のフォルダやファイルを編集していきます。

# 自作データの作成
物体検出タスクでの自作データセットを作るには
1. 画像データ
2. 画像データに対するアノテーションデータ

の2つが必要になります。
アノテーションデータとは、画像のどこに物体があるかを示すデータのことで
1.物体のラベル
2.物体を囲む矩形の左上のx座標
3.物体を囲む矩形の左上のy座標
4.矩形の高さ
5.矩形の幅

の5つの情報で構成されています。

ではこの2つを作成していきます。

## 画像データ
今回は顔検出をしたいので、顔が写っている画像ならなんでもいいと思います。
[コチラ](https://qiita.com/okateru/items/6f9daf1094ef8c2d6d68)でスクレイピングして集めた櫻坂メンバーの画像フォルダから30枚ほど使います。
ただ理想は300枚ほど欲しいです。ただその分アノテーションデータの作成が苦行になります。

## アノテーションデータ
アノテーションデータ作成には、アノテーションツールを使います。
今回は`VoTT`というツールを使います。ダウンロードは[コチラ](https://github.com/Microsoft/VoTT/releases)。

![スクリーンショット 2021-11-02 12.07.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/9a38ae33-5c1e-e68d-b9fd-8511e6b02f0c.png)

macならdmgファイルを、windowsならexeファイルをダウンロードしてインストールしてください。

インストールして起動すると以下の画面が開かれるはずです。

![スクリーンショット 2021-11-02 9.13.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/76b49273-2e00-5ff6-9e95-017f9154d383.png)

新規プロジェクトをクリック。

![スクリーンショット 2021-11-02 9.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/4c635053-8c26-7c90-4b36-fe734fd85681.png)

`ソース接続`の横の`Add Connection`をクリック。
![スクリーンショット 2021-11-02 9.14.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/2dab5eb6-c698-22f6-e07e-b873b4c32ff1.png)

`表示名、説明`は自由
`プロバイダー`は`ローカルファイルシステム`を選択して`フォルダーパス`の`フォルダーを選択`をクリックしたら、アノテーション付けする画像が格納されたフォルダを選択します。

最後に`接続を保存`をクリック。

![スクリーンショット 2021-11-02 9.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/f73c20d5-92cc-b707-a891-cfe3e1c099aa.png)

そうしたら`ソース接続`がさっき設定したフォルダになっているはずです。
今回はフォルダ分けするのがめんどくさいので`ターゲット接続`も同じフォルダにします。

この`ターゲット接続`に設定したフォルダにアノテーションデータ等必要なものが保存されるので自分の好きなとこでいいと思います。

![スクリーンショット 2021-11-02 12.18.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/ee65083c-92dd-56e8-473c-b87eb9f3053d.png)

問題なければ一番下の`プロジェクトを保存`をクリック。
そうすると以下のように編集画面が開くはずです。

![スクリーンショット 2021-11-02 9.15.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/53ae4c50-098d-cdd7-7952-32c7f5f4b6ba.png)

使い方は
右の`TAGS`の`＋`を押して矩形領域につけるラベル名を作成、画像の領域をドラッグして囲って、ラベルを適用する
という流れになります。

![スクリーンショット 2021-11-02 9.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/ca4d41f5-f470-d10b-3227-cfbe7f3b3aa1.png)

上記のように顔の部分を囲って、右の`face`タグをクリックするだけで囲った矩形領域にfaceというラベルをつけることができます。
操作自体はシンプルで簡単なので、問題ないと思いますがこれを何百枚もやるというのは大変ですね、、、
また複数ラベルだったりすると、1枚アノテーション付けするのに時間がかかっちゃうので、、、（想像もしたくない）

今回は30枚で妥協させてください。

全部アノテーション付けが終わったら、中央のアイコン群の`プロジェクトをエクスポート`をクリックします。

![スクリーンショット 2021-11-02 12.29.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/3dc8152a-9bb9-1da3-8ade-5f4640c2eb15.png)
そうすると先ほど`ターゲット接続`に設定したフォルダ内に

![スクリーンショット 2021-11-02 12.31.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/f864667f-78bf-e1d5-9f70-319516db0181.png)

こうしたフォルダが作成されているはずです。この中に画像データとそれに対するアノテーションデータがひとまとめになって入っています。

さてこれで完了！学習と行きたいところですが、このままでは学習には使えません。
作成したデータをYOLOv5でも使える形式に変換する必要があります。

# アノテーションデータを変換

VoTTで作成したアノテーションデータをYOLOv5でも使えるように[roboflow](https://roboflow.com/)というツールを使って変換します。

アカウントを作成してログインすると以下のような画面になるはず（個人情報部分黒くしてます）

![スクリーンショット 2021-11-02 12.40.18（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/6e0820cd-978b-9aff-90a5-5c2af410ef4f.png)

初めてログインするとプロジェクトの種類を選ばされるはずなので、`Public Projects`でいいと思います。



`Create New Project`をクリック。

![スクリーンショット 2021-11-02 9.23.47（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/69723b96-2da3-c629-b01c-97851a29f5ef.png)

`Project Name`, `License`は自由
`Project Type`は物体検知なので`Object Detection(Bounding Box)`を選択
`Annotation Group`は何でもいいですが、アノテーション付けするグループ名（動物、乗り物、人とか）をつけとくといいのではと思います。

僕は以下のようにしました。

![スクリーンショット 2021-11-02 9.24.22（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/cf69acf7-90b6-fa79-da3b-fe2ef37b88d5.png)

これで`Create Public Project`を押すと以下の画面に。

![スクリーンショット 2021-11-02 12.54.37（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/e70dd11e-2a25-15f4-dab9-2f6e4a24586c.png)

ここに先ほどの`vott-json-export`フォルダを丸ごとアップロードします。

![スクリーンショット 2021-11-02 12.56.39（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/ac28f174-88c0-53b6-52ab-304380fa4003.png)

`All Images`と`Annotated`の数が一緒なら画像とアノテーションデータが一致して正しく読み込まれています。

大丈夫そうなら右上の`Finish Uploading`をクリック。

![スクリーンショット 2021-11-02 12.57.01（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/3d61bdd4-dd76-09b9-d314-bd4710c4eb18.png)

そうするとTrain, Valid, Testに分割する割合を選択できるので好きなように選択。
別に後で変更もできるので適当で大丈夫です。
`Continue`をクリック。

![スクリーンショット 2021-11-02 9.26.21（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/2583038a-9370-1e24-3b70-61e45c200c26.png)

そうしたら、ここまでで右の`Source Images`, `Train/Test Split`までの工程が完了しています。`Preprocessing`はデフォルトで`Auto-Orient`と`Resize`が設定されています。

![スクリーンショット 2021-11-02 13.06.38（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/e79b9566-9c6b-a42e-dc87-abca21cdaee1.png)

`Add Step`をクリックすると![スクリーンショット 2021-11-02 13.06.58（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/fd1eabb6-2c46-05d3-95bf-919189913693.png)


![スクリーンショット 2021-11-02 13.06.43（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/2fb7db7d-de98-ce66-4d36-37b2c90c1e95.png)

前処理のオプションを選択できるので、もし追加したい場合はここから好きなものを追加しましょう。
今回はデフォルトで行きます。`Continue`をクリックすると次は`Augmentation`の設定に移ります。

![スクリーンショット 2021-11-02 13.06.51（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/ca8a3f28-8959-475d-fcd1-ab33c79c7b25.png)

これも`Add Step`をクリックすると
![スクリーンショット 2021-11-02 13.06.58（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/9a379abc-d4d3-d1c4-21b4-dcc43434b64b.png)

こんな感じでたくさん選択できます。今回はさすがに30枚は少なすぎるので

![スクリーンショット 2021-11-02 9.30.16（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/36245743-b09b-97ba-99c5-6dbf80f9df56.png)

上記のような水増しで行きます。`Continue`を押して

![スクリーンショット 2021-11-02 13.15.13（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/6f527761-f431-ec0f-a872-eabc4332eca4.png)

`Maximux Version Size`を選択して、`Generate`をクリックします。無料枠だと3倍までしか選択できません。

![スクリーンショット 2021-11-02 9.30.48（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/d4e4c569-7b0d-1ad6-f205-1ae6aa31ce89.png)

![スクリーンショット 2021-11-02 9.35.44（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/558ec8e6-66bf-ef7a-9932-18e7db4d05cf.png)

こんな画面になるはずです。

もし新しい水増しを適用させたい場合は左の`New Version`をクリックすれば大丈夫です。

`Export`をクリックして

![スクリーンショット 2021-11-02 13.22.39（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/f7d375a1-4d6e-cd3b-5b7d-23e9be350d71.png)

Formatは今回はYOLOv5を使うので`YOLO v5 PyTorch`をダウンロード方法は好きな方を選択して`Continue`。

今回はzipでダウンロードしたので解凍すると

![スクリーンショット 2021-11-02 9.36.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/5d837064-c8b8-2c75-0948-4dde7fcd6300.png)

こんな中身になってるはず。

そしたらまずは、train,valid,testフォルダを丸ごと、先ほどコピーしたリポジトリ内の`data`ディレクトリに移動させます。Jupyter Labで見るとこんな感じ。

![スクリーンショット 2021-11-02 13.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/e6d475ae-9610-6f36-9c78-15f4df22042b.png)

次にdata.yamlファイルをyolov5ディレクトリ直下にあるdata.yamlファイルと置き換えます。

![スクリーンショット 2021-11-02 13.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/6b66af43-aaa5-e747-62cf-ab8c03b48c7d.png)

このままだとディレクトリを読み込んでくれないのでdata.yamlを以下のように編集します。

```python:data.yaml
train: ./data/train/images
val: ./data/valid/images
test: ./data/test/images

nc: 1
names: ['face']
```

別にtestの記載はなくてもいいです。

これで学習の準備は整いました。

# いざ学習

以下のコマンドをターミナルで実行します。

```shell:ターミナルで実行(yolov5ディレクトリにいる状態で)
python train.py --img 416 --data data.yaml --weights yolov5s.pt --batch-size 16
```

引数の詳細
`--img` で画像の入力サイズ
`--data`で学習用データの詳細を読み込むファイルを指定
`--weights`で使用する学習済みモデルの重みを選択

今回は一番小さい`yolov5s`を使います。

うまくいくと`runs/train/exp`ディレクトリに学習の詳細情報が保存されていきます。
`result.csv`なんかは各種lossの値などがcsv形式で確認できて便利です。

# 推論

正直データ枚数も少ないので精度は微妙です。
評価データの結果は、学習が終わった時に保存される`val_batch0_pred.jpg`に表示されていて、今回はこんな感じになりました。

![val_batch0_pred.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/cfbf5b40-7b11-dcc2-e8ff-a0a3d88e1f37.jpeg)

testデータの画像を推論したい場合は以下のコマンドを実行します。

```shell:ターミナル
python detect.py --source data/test/images --weights runs/train/exp/weights/best.pt --conf 0.1
```

引数の説明
`--source`は推論したい画像の格納先を指定
`--weights`は推論時のモデルの重みを選択
`--conf`はある物体が存在する確率がここに設定した確率値以上のものだけを矩形で囲む

学習した重みは`runs/train/exp/weights`ディレクトリの中に`best.pt`と`last.pt`の2つが保存されているので`best.pt`で推論します。

実行すると`runs/detect/exp`ディレクトリ内に結果画像が保存されています。

![000256_jpg.rf.33528e83238d4e13b2392c574833abdc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/1027b99f-504d-7d20-fbd7-a7d318717fd5.jpeg)
![000265_jpg.rf.b7ef83fbb405ce002db04ba08626e569.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/1e1edc45-a6c8-41ab-3136-255f90371b51.jpeg)
![000282_jpg.rf.7bde55da64d5991c7fc08091fe103964.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890361/41ca4ed1-31b7-13f8-711a-9647ab04bbd4.jpeg)

まぁ精度はダメダメですね、、、
30枚は少なすぎるので、データ枚数もっと増やす必要がありますね。もしくはエポック数増やすか、モデルを大きいものにするか。

# まとめ
YOLOv5を使って物体検知をやる流れを説明しました。
物体検知タスクへのハードルが下がれば幸いです。

知見が深まったら、物体検知の精度アップへの記事も書こうと思います。