Tensorflowの画像分類でハムケツを判定する

機械学習を勉強してから画像がハムケツか否かを識別するプログラム作成を試みたのですがなかなか上手くいきませんでした。

Tensorflowを使えばプログラミングレスでいい感じにできそうだったので、Tensorflowに入門（というか体験）してみました。

この記事ではTensorflowの画像分類チュートリアルに実際に取り組んだ内容を中心に紹介します。

[How to Retrain an Image Classifier for New Categories](https://www.tensorflow.org/tutorials/image_retraining)

最後にこのプログラムを使ってハムケツ判定を行います。が、チュートリアルの学習画像を差し替えるだけです。

# 環境
- Python3.6.1（Anaconda 4.3.21）
- Tensorflow1.8
- Windows10

# Tensorflowチュートリアル
公式チュートリアルは花の分類学習を行います。

## 環境づくり
AnacondaでTensorflow用のPython環境を作り、tensorflow、tensorflow-hubをインストールします。

```shell
$ conda create -n tensorflow python=3.6.1
$ activate tensorflow
(tensorflow)$ pip install tensorflow
(tensorflow)$ pip install tensorflow-hub
```

## 学習データ取得
以下のファイルをダウンロードして適当なディレクトリに解凍します。

http://download.tensorflow.org/example_images/flower_photos.tgz


カテゴリ分けされた花の画像が格納されています。<img width="574" alt="2018-07-03_04h24_37.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/c94dcc08-7a0a-e2f8-fcce-d3e983917c75.png">


## ソースコード取得
githubに公開されている`retain.py`をダウンロードします。

https://github.com/tensorflow/hub/raw/r0.1/examples/image_retraining/retrain.py

## 実行
あとはプログラムを実行するだけです。`--image_dir`には先ほど解凍した学習データが格納されているフォルダを指定します。

```shell
(tensorflow)$ python retrain.py --image_dir ~/flower_photos
```

ここからボトルネック（画像の特徴点のようなもの？）の作成と、4,000ステップの学習が始まります。私の環境では終わるまでおおよそ1時間ほどかかりました。
<img width="734" alt="2018-07-05_00h43_35.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/83c97c8a-3282-6cc6-e098-8ef6becb05c5.png">

## 学習状況の確認
`tensorboard`コマンドを使って学習状況をリアルタイムに確認することができます。

デフォルトでは学習結果ファイルが`/tmp`（Windowsでは`C:/tmp`）に作成されています。

<img width="554" alt="2018-07-05_00h46_33.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/cca3e572-0fd8-337e-95fe-e9eddf168201.png">


`tensorboard`コマンドに上記の`/tmp/retains_logs`を指定して実行します。 
※tensorboardはtensorflowを導入したpython環境をactivateしてから実行します。

```shell
(tensorflow)$ tensorboard --logdir C:/tmp/retains_logs

TensorBoard 1.8.0 at http://hostname:6006 (Press CTRL+C to quit)
```

起動後にブラウザから```http://hostname:6006```にアクセスすると、学習データが表示されます。

<img width="570" alt="2018-07-05_22h02_54.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/f8e32e5e-cee4-76b5-e75b-391945bcdccc.png">

## テスト
できあがった学習データを使って、本当にうまく画像分類してくれるかをテストします。

`label_image.py`をgithubからダウンロードして適当なディレクトリに配置します。  
https://github.com/tensorflow/tensorflow/raw/master/tensorflow/examples/label_image/label_image.py

先ほど生成された学習データを`--graph'と`--labels'に、分類したい画像を`--image`に指定して`label_image.py`を実行します。

```shell
(tensorflow)$ python label_image.py \
--graph=C:/tmp/output_graph.pb --labels=C:/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=~/flower_photos/daisy/21652746_cc379e0eea_m.jpg
```

テスト画像はデイジー（ヒナギク）です。
![21652746_cc379e0eea_m.jpg](https://qiita-image-store.s3.amazonaws.com/0/183744/5ae0f367-1560-48a3-764d-7a1345f7cb37.jpeg)

実行してみると**「99%の確率でデイジー」と判定しました。**
<img width="175" alt="2018-07-05_22h32_47.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/81bf6bab-35f5-b2d8-5db4-bb51e2980215.png">

# ハムケツでチャレンジ
以上がチュートリアルです。ここからはハムケツでチャレンジします。

と言ってもテスト画像を差し替えるだけです。今回はhamketsuフォルダの中に、

- ハムケツばかりを集めた画像フォルダ「hamketsu」
- ハムケツによく似た大福ばかりを集めた画像フォルダ「nothamketsu」

の2種類を用意して画像を学習させます。枚数はそれぞれ約200枚です。

<img width="462" alt="2018-07-07_01h06_50.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/09895035-5772-7293-0402-799617b0f7d4.png">

<img width="505" alt="2018-07-07_01h08_15.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/f8167a0c-8902-7970-7812-336768ac0e5a.png">

ちなみに学習画像はgoogle、being、twitterから自前のプログラムで収集しました。
https://github.com/quotto/imagecrawler

<br/>
それでは学習させていきます。

```shell
(tensorflow)$ python retrain.py --image_dir ~/hamketsu
```

tensorboardで学習状況を見てみると、**特にvalidationはチュートリアルに比べて上手く学習できていないことが伺えます。**
<img width="359" alt="2018-07-05_22h53_21.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/151b357a-494e-782e-bf2e-805697cac124.png">


<br/>
学習が終わったらテストをしてみます。

```shell
(tensorflow)$ python label_image.py \
--graph=C:/tmp/output_graph.pb --labels=C:/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=~/test/テストする画像ファイル.jpg
```

まずは大福です。
![200px-Daifuku.jpg](https://qiita-image-store.s3.amazonaws.com/0/183744/9e4cd8cd-ae02-bf05-defe-1bdf901d9d54.jpeg)
（https://ja.wikipedia.org/wiki/%E5%A4%A7%E7%A6%8F）

**「86%の確率でハムケツじゃない」**となりました。まずまずです。
<img width="141" alt="2018-06-27_00h31_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/f2b242ba-1241-ed59-c321-919f82c63ef1.png">

<br/>
続いてハムケツです。
<img width="200" src="https://qiita-image-store.s3.amazonaws.com/0/183744/8dbf31b8-bc4c-8aa8-c33d-f9316c1eef22.jpeg">
（https://www.imgrumweb.com/post/Bi_-_uTBVHX）

**「99%以上の確率でハムケツ」**と判定しています。完璧です。
<img width="163" alt="2018-07-07_00h42_18.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/3bbf96d7-6de3-6329-2bee-e93ea8eb2669.png">



<br/>
しかしそう上手くもいきません。

例えばこの画像は「ハムスター」であって「ハムケツ」ではありません。
<img width="200" src="https://qiita-image-store.s3.amazonaws.com/0/183744/80c363b7-a0fd-2171-8a36-48fa818d29f3.jpeg">
（http://www.nicovideo.jp/watch/sm25188364）

しかし**「89%の確率ではハムケツ」**と誤判定されてしまいました。
<img width="135" alt="2018-06-28_00h09_45.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/f04d7ee8-e265-cf1d-dc30-8356a6815837.png">

<br/>
また、この画像は「子猫のケツ」です。
<img width="200" src="https://qiita-image-store.s3.amazonaws.com/0/183744/391e37d7-7234-07e3-9051-6d6792bd895c.jpeg">
（https://peco-japan.com/50783）

しかしこれまた**「98%でハムケツ」**と誤判定されてしまいました。
<img width="143" alt="2018-07-07_00h47_40.png" src="https://qiita-image-store.s3.amazonaws.com/0/183744/81771adf-bd4f-5613-851f-a71f2580b3cb.png">



以上のとおり、学習データも十分ではなくハムケツ判定の精度はイマイチでした。

しかしチュートリアルのように対象画像の範囲が限定される（例えば「花の画像」だと分かりきっている）場合は、ノンプログラミングでお手軽に画像分類ができます。

また公式ページには今回使用したプログラムのハイパーパラメータの指定方法なども掲載されているため、色々と試してみると良いかもしれません。