YOLOv3でオリジナルの物体検知器作り方

## やりたいこと

人とか車とかデフォルトのモデルで物体検知ではなく、カスタマイズした物体を検知したい。

例えば、下記の記事のように将棋の「歩」を認識したいとかです。
https://qiita.com/shinmura0/items/f818bcbb92d5fff5279d

今回はClovaのクマを検知できるようにします。

## 前提知識

YOLO v3の論文
https://pjreddie.com/media/files/papers/YOLOv3.pdf

v3では53の畳み込み層を持っているそうです。

論文の日本語翻訳
https://qiita.com/mdo4nt6n/items/7cd5f106adc775e5d92b

DarknetはYOLOを使うためのフレームワークみたいです。

https://pjreddie.com/darknet/yolo/

めちゃくちゃ怪しいですが、これがDarknetの公式サイトです。

## 画像を集める

まずは、検知したい物体が写っている写真を用意します。
データオーギュメンテーション（水増し）については扱わないので、数十枚くらい画像があるといいと思います。

ちなみに、今回は雰囲気を掴むために、こんな画像3枚だけ用意しました。
![img3.jpg](https://qiita-image-store.s3.amazonaws.com/0/15074/8982ba13-aa3b-dab9-f42c-134bbcda275b.jpeg)

## 学習用のデータを作成する

YOLOで学習するためのデータセットを出力できるツールがいくつかあります。

MicrosoftのVoTTがMACでもWindowsでも使えるのでおすすめです。
https://github.com/Microsoft/VoTT

VoTTの使い方とか
https://www.softbanktech.co.jp/special/blog/cloud_blog/2018/0043/

こんな感じでラベルをつけます
![スクリーンショット 2019-01-29 16.26.42.png](https://qiita-image-store.s3.amazonaws.com/0/15074/e52dc98e-cd7a-abe8-3af3-0547d61d30a1.png)


## Google Colaboratoryにモデル作成環境を作る

いきなりGoogle Colabか！って話ですが、メモリ8G、
CPU 1.6 GHz Intel Core i5のMACでは、学習中に何もできなくなるし、ほとんど学習も進まなくなります。

DarknetではGPUを使うモードがあるので、Google Colabを使わせていただきましょう。

ちなみに、学習はデフォルトで45000回くらい回す設定（yolo-obj.cfgで設定）になってますが、そんなに待ってられないので、backupディレクトリに作成される作成途中のモデルを使用しましょう。ただ最低2000回くらいは回した方がいいとのことです。

学習はGoogle Colabでやった方がいいですが、モデルを使用して、物体検知をするのは、PCのDarknetで大丈夫です。

まずは、Google Colabでファイルを新規作成します。
![スクリーンショット 2019-01-29 15.44.05.png](https://qiita-image-store.s3.amazonaws.com/0/15074/89454265-f9f2-b49a-0bea-34741cd238e5.png)
ランタイムはPython3、GPUを選択しましょう！！

Google Colabはjupyter notebook的なUIですが、モデル作成手順は下記になります。

```sh
!apt install gcc-5 g++-5 -y

!ln -sf /usr/bin/gcc-5 /usr/bin/gcc 
!ln -sf /usr/bin/g++-5 /usr/bin/g++

# Google Driveとマウント
from google.colab import drive
drive.mount('/content/gdrive')

%cd /content/gdrive/My\ Drive/

!git clone https://github.com/pjreddie/darknet

%cd darknet

!apt update

!apt install cuda-9-2 -y
!ln -sf /usr/local/cuda-9.2 /usr/local/cuda

import os
os.environ['PATH'] += ':/usr/local/cuda/bin' 
os.environ['LD_LIBRARY_PATH'] += ':usr/local/cuda/lib64' 

# GPUを使うようにする
!sed -i 's/GPU=0/GPU=1/g' Makefile

!make

#　学習開始
!./darknet detector train data/obj.data data/yolo-obj.cfg

# おそらく、学習終わらないので、途中から再開したい場合、backupファイルを指定する
!./darknet detector train data/obj.data data/yolo-obj.cfg backup/yolo-obj.backup
```

上記手順とは別に、Darknetをcloneしてから、VoTTで作成したデータセットをdataディレクトリの中に配置する作業があります。

VoTTで出力されたディレクトリをそのまま使う場合、Google Driveのdarknetディレクトリの下記にそれぞれ配置します。
data/yolo-obj.cfg
data/obj（dirごと）
data/obj.data
data/obj.names
data/test.txt
data/train.txt

ちなみに、オススメしておいて難ですが、VoTTで出力したtrain.txt、test.txtが一行になって、
出力されたりすることがあるので、怒られたら確認してみてください。

## いや、なんか学習しようとしたら、Google Colabの実行キャンセルされるんだけど。。。？

2018/12にこの事象が発生した時は、<b>出力は何もなく</b>、実行がキャンセルされました。
2019/1にこの事象が発生した時は、ちょっと親切なメッセージが出ました。

なので、おそらく現在はわかるかと思いますが、メモリエラーが起きたら、学習させる画像のサイズをみてください。

スマホで撮った画像をそのまま学習させようとすると、大体やられる気がします。

## 学習したモデルで物体検知する

backupのweightsファイル or backupファイルをPCにダウンロードし、Google Colabと同様にDarknetをインストールします。

ちなみに、本家のDarknetではなく、下記の派生Darknetを使うと、
画像内での検出したボックスのポジションを出力させたりできるので、物体検知後に、さらに何かしたい人とかは使えるのかなと。

https://github.com/AlexeyAB/darknet#how-to-use-on-the-command-line

例えば、下記のコマンドをdarknetディレクトリで実行すると、
学習したモデルで物体検知ができ、その結果は、同じ階層のpredictions.jpgにて確認できます。

```sh
./darknet detector test ./data/obj.data ./data/yolo-obj.cfg yolo-obj_200.weights img1.jpg -thresh 0.06
```

流石に、学習画像3枚で、200回しか回してないモデルで実行したら、全然精度が出なかったので、スレッショルドでごまかしてますが、こんな感じです。
![predictions.png](https://qiita-image-store.s3.amazonaws.com/0/15074/8e8eeb66-9e1b-c930-a5e4-0f916ba6ee9a.png)


いまいちラベルをつけてくれないなーという場合にはスレッショルドを小さく設定すると、認識精度が低いものもラベル付けしてくれるので、楽しいです。

ポジションを取りたい場合

```console
// -ext_outputオプションをつける
$ ./darknet detector test data/obj.data data/yolo-obj.cfg yolo-obj.backup -ext_output img01.jpg -thresh 0.1

// 出力
clova-kuma: 26%	(left_x:  309   top_y:  390   width:   48   height:   27)
clova-kuma: 33%	(left_x:  330   top_y:  543   width:   83   height:   24)
clova-kuma: 40%	(left_x:  469   top_y:  539   width:   59   height:   26)
```

## まとめ

DarknetとGoogle Colabってパワーワード過ぎませんか？