パンダ判別機を作ってみた

こんにちは！
2018年はシャンシャンが大きくなったり和歌山でパンダの赤ちゃんが生まれたりと、パンダな１年でしたね！
…！
というわけで、パンダ好きエンジニアとして一度やってみたかった、パンダ判別機を作ってみます。

# 概要
TensorFlowを使用して、シャンシャンとその両親のリーリー、シンシンの判別機を作ります。

# 作成の流れ
1. CentOS7上に環境を作る
2. シャンシャン、リーリー、シンシンの画像を集める
3. 集めた画像を、機械学習用に加工する（除外・トリミング・回転）
4. 加工した画像を学習させて、モデルを作る
5. モデルを使って判別させる
6. おまけ

# CentOS7上に環境を作る

今回はCentOS7上で試してみます。今回の判別機を作るために必要な、python3.6と各種pythonライブラリをインストールします。

## python3.6をインストールする
```Bash
$ sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm
$ sudo yum install -y python36u python36u-libs python36u-devel python36u-pip
```

バージョンを表示して、インストールできていることを確認します。

```Bash
$ python3.6 --version
Python 3.6.5
$ pip3.6 --version
pip 9.0.1 from /usr/lib/python3.6/site-packages (python 3.6)
```

無事にインストールできていることが確認できました。

## 必要なpythonライブラリをインストールする

次に、4つのpythonライブラリをインストールします。

```Bash
$ sudo pip3.6 install google_images_download
$ sudo pip3.6 install numpy
$ sudo pip3.6 install tensorflow
$ sudo pip3.6 install tensorflow_hub
```

google_images_downloadは学習用素材の収集に、numpy、tensorflow、tensorflow_hubは学習、判別のために必要になります。

## 学習用のコード、判別用のコードを取得する

最後に、学習と判別に用いるコードをgithubから取得します。

```Bash
$ curl -LO https://github.com/tensorflow/hub/raw/master/examples/image_retraining/retrain.py
$ curl -LO https://github.com/tensorflow/tensorflow/raw/master/tensorflow/examples/label_image/label_image.py
```

無事に取得できていることを確認します。

```Bash
$ ls
label_image.py  retrain.py
```

これで環境の構築は完了です。

# シャンシャン、リーリー、シンシンの画像を集める

環境構築にて準備したgoogle_images_downloadを利用して、シャンシャン、リーリー、シンシンの画像を集めます。

```Bash
$ googleimagesdownload -k シャンシャン
$ googleimagesdownload -k リーリー
$ googleimagesdownload -k シンシン
```

downloadsというディレクトリに、それぞれの画像が約100枚ずつ保存されています。

```Bash
$ ls downloads/
シンシン  リーリー  シャンシャン
```

# 集めた画像を、機械学習用に加工する（除外・トリミング・回転）

集めた画像を、機械学習用に加工します。
具体的には、正面を向いた顔だけに揃えるように、画像のトリミング・回転を行います。
正面を向いていない画像や顔に笹などが映り込んでしまっているものは除外します。
Windowsであれば、[PictBear](https://www.fenrir-inc.com/jp/pictbear/)というソフトが個人的にはオススメです。

たくさんのパンダ画像と戯れられる、至福の時間…！
しかしここで一つの不安が芽生えます。
[こちらのサイト](https://mainichi-panda.jp/contents/miwakekata.html)を参考にしながら、複数のパンダが映っている画像からどっちがどっちだっけとチェックしながら画像の加工をしていたのですが、リーリーとシンシン、人間でも見分けるのが大変…！！
判別できるようになるのでしょうか…？

加えて、正面を向いていない画像など学習には使用できない画像を除いたところ、

* シャンシャン：43枚
* リーリー：47枚
* シンシン：27枚

という結果になりました。枚数にもとても不安が残ります…！

# 加工した画像を学習させて、モデルを作る

不安を抱えながらも、作業を進めます。
加工した画像を、ディレクトリ名を変えつつ格納します。

```Bash
$ ls
downloads  label_image.py  pandas  retrain.py  riri.jpg  shinshin.jpg  xianxian.jpg
$ ls pandas/
riri  shinshin  xianxian
```

pandasというディレクトリに、「riri」「shinshin」「xianxian」として加工済みの画像を格納しています。
このとき、学習結果を評価するため、用意した画像から一枚ずつ「riri.jpg」「shinshin.jpg」「xianxian.jpg」として取り出しておきます。
取り出した画像は学習には利用せず、学習の結果作られたモデルで正しく判別できるかどうか確認のために利用します。

それではいよいよ学習を開始します！

```Bash
python3.6 retrain.py --image_dir pandas
```

このステップは結構時間がかかります。手元の環境では30分強かかりました。マシンスペックや判別したい種類の数、画像の枚数で大きく変わってくると思います。
学習が完了すると、/tmp配下に成果物が生成されています。

```Bash
$ ls /tmp/output*
/tmp/output_graph.pb  /tmp/output_labels.txt
$ cat /tmp/output_labels.txt
riri
shinshin
xianxian
```

ディレクトリ名がラベルになっていることが確認できます。

# モデルを使って判別させる

それでは、学習させて作ったモデルで、取り出しておいた画像を判別してみましょう。
まずは、シャンシャン。

```Bash
$ python3.6 label_image.py \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=xianxian.jpg
...
xianxian 0.9266557
shinshin 0.04356147
riri 0.029782834
```

シャンシャンは、正しく判別することができたようです！
次はリーリー。

```Bash
$ python3.6 label_image.py \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=riri.jpg
...
riri 0.8211787
shinshin 0.17438892
xianxian 0.004432354
```

ちょっとシンシンの可能性が高めに出たものの、リーリーも正しく判別することができました！

次は不安の種だったシンシン！

```Bash
$ python3.6 label_image.py \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=shinshin.jpg
...
shinshin 0.60328656
riri 0.39528912
xianxian 0.0014243503
```

ギリギリという感じではありますが、一応シンシンと判別することができました！でもホントにギリギリ…。

# 感想

パンダ好きエンジニアとして、パンダ判別機を作ってみました。
一文字もコードを書くことなく、しかも少ない枚数でシャンシャン、リーリー、シンシンを判別できるパンダ判別機を作ることができました！
もっと画像を増やすことができれば、精度を上げられるのだろうと思います。
今回はパンダの画像ということで、画像の準備（加工）は至福の時間でした…(´ω｀)
それでも結構時間と労力は必要だったので、噂には聞いていましたが機械学習用の素材の準備の大変さを垣間見た気がします。

# おまけ

パンダを手描きして、判別機にかけてみました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/322696/1b75df4e-e85b-3148-4b4d-76d8026befc8.png" width=10%>

```Bash
$ ls handwriting-panda.png
handwriting-panda.png
$ python3.6 label_image.py \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=handwriting-panda.png
...
riri 0.9999039
xianxian 9.354555e-05
shinshin 2.4552642e-06
```

今回の判別機によると、どうやらこの手描きパンダはめっちゃリーリーらしいです…！？

興味がある方は、オリジナルな判別機を作ってみてはどうでしょうか！