メンターとパンサーを人工知能に区別させてみた

# 挨拶

こんにちは。iPhoneメンターのへむへむです。
寒い冬にはやっぱりおでんですよね。しらたきはほどかずシャキシャキ食べる派です。

突然ですがLife is Tech ! 関係者のみんなは次のメンターを知っていますか？

<img width="158" alt="スクリーンショット 2016-12-04 9.35.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/761a5c6d-3d85-aee4-c780-95a692de8c3a.png">



知らないそこのあなた...!
ええ、知らなくて当然です。この方はお笑い芸人 [パンサー](http://search.yoshimoto.co.jp/talent_prf/?param=/r/s=i=2755/r=2757) の向井さんです。

![IMG_2099.jpg](https://qiita-image-store.s3.amazonaws.com/0/85972/1ed5ac20-11ce-a39e-cc16-623c4023b644.jpeg)

メンターはこっちです。そう、このアドベントカレンダー初日を書いてくれました。Webデザインメンターのちゃんちーです。


**に、似てる！！**(~~ということにします。~~)


これは困りました...これではWebデザインで質問をしたい時、ちゃんちーを呼べばいいのか向井さんを呼べばいいのかわからない！ そんな混乱した事態になってしまいます。



いや、俺iPhoneコースだし、Webの質問とかしないし...
って思った**そこのあなた！！！！**

次の写真を見てください。

![ふんじん.jpg](https://qiita-image-store.s3.amazonaws.com/0/85972/9bf325e8-b2b6-aa90-b8b3-2d822c26f4bd.jpeg)



どん！

キャンプやスクールで大活躍中、最近はあの**ランニングクラブ**でHADO world cupに出場し世界一の座に輝いたiPhoneメンターのフンジンです。([参考](http://news.ponycanyon.co.jp/2016/11/16709))

ん、んん？

次のGoogle画像検索結果をみてください。

<img width="743" alt="スクリーンショット 2016-12-04 9.52.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/907ae67f-e593-1578-5eb6-77e31a542234.png">


ふん..じん？
ではありません。この方はお笑い芸人パンサーの尾形さんです。


**に、似てる！！**(~~ということにします。~~)


ここで大きな問題が生じてしまいました。
え、フンジンなの？？尾形さんなの？？ちゃんちー？？向井さん？？え、そもそもメンターだっけパンサーだっけ？ 問題です。

<img width="638" alt="スクリーンショット 2016-12-03 20.19.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/b283a722-fc0b-06b5-1ebe-80f14f0fa33b.png">

今回はこの深刻な問題を、流行りの**人工知能**の技術を用いて解決したいと思います。


# 概要
メンターちゃんちーとパンサー向井さんを画像認識によって識別する。(使用言語はPython)
1.画像を収集
2.画像を切り取り増やす
３.Kerasでdeep learning
(コードは[github](https://github.com/rikky0611/cnn_classification)にあげており、本記事ではコードにはほぼ触れません。データ集めからテストまでのdeep learningのニュアンスを伝えていければと思います。)

※今回の内容は以前のインターン先でお世話になった方の[この記事](http://qiita.com/eve_yk/items/e0ccd7917237fed1607f)をすごく参考にしました。違うライブラリを使ってはいますが、コードに興味がある人はこっちも合わせてみるとよいと思います。

# 1.画像を収集する
一般に言われる機械学習(今回はdeep learning)は大量のデータから隠れたパターンをみつけるというのが本質です。そのため、**データ**が欠かせないのです。
今回必要なデータは
・ ちゃんちーの顔写真
・ 向井さんの顔写真
です。

ちゃんちーの顔写真は次のようにして集めました。

<img width="507" alt="スクリーンショット 2016-12-03 20.31.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/942aca44-2f21-fcb9-7d4b-1e20cead96f8.png">

簡単ですね！すぐにdropboxで共有してくれました！
**写りが良い写真が多かった**ことは秘密にしておきます！

次はパンサー向井さんの写真です。
こちらは幸いGoogle検索でごまんとでてきます！

<img width="659" alt="スクリーンショット 2016-12-03 1.14.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/b78ca415-f939-c4ad-cc7c-9c33bd0055e2.png">


これを一つ一つ右クリック->ダウンロードしてもいいのですが、エンジニアは3回以上繰り替えす行動はしないものです。
なので [**Google Custom Search API**](https://developers.google.com/custom-search/?hl=ja) を使って一気にまとめてダウンロードします。この辺のコードも[github](https://github.com/rikky0611/cnn_classification)にあげてますので、自分も楽して画像集めたいっ！って人は確認ください。

このようにしてちゃんちーの画像48枚、向井さんの画像54枚が集まりました。

# 2.画像を切り取り増やす
まず、私たちが欲しいのはちゃんちーと向井さんの顔の画像です。いまの画像のままだと背景や洋服などが多く写真に写り込んでしまっていて、それらが学習に悪影響を与えるかもしれません。
なので1.で集めた画像から**顔画像を切り取る作業**が必要です。実は画像を扱うために使用するライブラリ(Open CV)には顔認識をしてくれる便利な機能が[あります](http://qiita.com/olympic2020/items/04b1b26c1bc2e8081427)。

が、しかし、顔がきちんと正面を向いていない写真がデータにあったりなど、~~全てをちゃんと切り取ってくれるか不安だったため~~ **手で**一枚一枚クロッピングしました。(102枚)


> エンジニアは3回以上繰り替えす行動はしないものです。

:innocent::innocent::innocent::innocent::innocent:

・・・
さて、
これでおよそ50枚ずつ顔写真が手に入ったわけですが、実はこれでは **データが足りません。**ここでデータを増やす過程に入ります。

データを増やす方法は次の三つです。
・　画像を上下左右に数ピクセルずつずらす。
・　画像をその平面内で少しずつ回転させる。
・　画像を反転させる

<img width="600" alt="スクリーンショット 2016-12-03 11.13.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/ff4341a8-d99a-5333-e3f4-7cdfe54f4d4c.png">

こうすることで、機械により普遍的に人物の特徴量を学習させます。

さて、こうすることでわずか100枚ほどの画像を1200枚ほどに増量させることができました。
これだけあればトイプログラムとしては十分なので、いよいよ deep learningに入ります。
<img width="365" alt="スクリーンショット 2016-12-04 10.52.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/2a322442-a177-68f9-e338-da0d9f5124ae.png">

(ファイル名に意味はないです。)

# 3.Kerasでdeep learning
ディープラーニング、深層学習、といった言葉はもうお馴染みだと思いますが、いざやってみようとして調べると複雑な数式だったりに遭遇して実装を避けてしまう人が多いのではないのでしょうか？ 確かにちゃんと精度をあげたりするにはそういった知識も必要ですが、遊んでみる分には必要ありません。

deep learningには便利なライブラリがたくさんあります。むしろ**ありすぎます。**
Tensorflow, Chainer, Caffe, Theano, Keras,,,,
これらのライブラリの使い心地を比較した記事はたくさんありますので、興味あれば調べてみてください。

個人的には
・MLPのback propagationなどの背景アルゴリズムをTheanoでしっかり実装してみる
・CNNを使って画像認識など複雑なことをしたくなったのでTheano(とTensorflow)をバックグラウンドで使えるラッパーライブラリのKerasで遊ぶ
の流れで学習をしてきたので、今回はKerasで実装します。
(コードをみればわかりますが、本当に表面的な実装だけを行えばよく、今回のように軽い実験を行うには最適なライブラリだと思います。Kerasについては [ここ](http://aidiary.hatenablog.com/entry/20160328/1459174455) が参考になります。)


deep learningをめっちゃ噛み砕いて言うと
**様々な役割を持ったレイヤー(層)を積み重ねて、そこにinputとoutputを与えて、きちんとinputに対応したoutputがでるようにレイヤーを鍛える**
となります。

<img width="993" alt="スクリーンショット 2016-12-03 12.17.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/3ee66351-3bdb-096b-b39f-8db7ccb4593e.png">

各レイヤーがどのような役割をもってるの？とか考え始めるとどんどん数式の世界に入っていくので今回はあまり深入りしません。これをコードにすると次のような感じです。なんとなく`model.add`で層をたくさん積み重ねているのがわかると思います。


    def build_deep_cnn(num_of_classes=2):

       model = Sequential()
       model.add(Convolution2D(96, 3, 3, border_mode='same', input_shape=(3, 32, 32)))
       model.add(Activation('relu'))model.add(Convolution2D(128, 3, 3))
       model.add(Activation('relu'))
       model.add(MaxPooling2D(pool_size=(2, 2)))
       model.add(Dropout(0.5))

       model.add(Convolution2D(256, 3, 3, border_mode='same'))
       model.add(Activation('relu'))

       model.add(Convolution2D(256, 3, 3))
       model.add(Activation('relu'))
       model.add(MaxPooling2D(pool_size=(2, 2)))
       model.add(Dropout(0.5))

       model.add(Flatten())
       model.add(Dense(1024))
       model.add(Activation('relu'))
       model.add(Dropout(0.5))

       model.add(Dense(num_of_classes))
       model.add(Activation('softmax'))

       return model

Convolution2DとかMaxPooling2Dとかがいろんな役割ってことですね！


さてこうやってmodelを準備したらあとは2.で集めたデータを持ってきて
`model.fit(train_X, train_y,[option])`
とするだけです。今回は俗に言う**教師あり学習**をおこなっており、train_Xが入力の画像データ、train_yが正解データ(ちゃんちーor向井さん)になっています。

こうして実行すると、つぎのようにどんどんKerasが出力を吐いてくれます。

<img width="797" alt="スクリーンショット 2016-12-03 19.48.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/a82f2e33-0bba-dc94-4096-346bdb1e7b6f.png">

Epochというのは学習回数です。今回はトータルで50回学習を繰り返しています。注目して欲しいのはval_lossの値で、これは**誤差の値**です。すなわち、ちゃんちーと向井さんを誤判断した回数の指標で、少ないほど精度が高いと言えます。上の図をみると学習を繰り返すにつれて値が小さくなるのがわかり、しっかりと機械がちゃんちーと向井さんを区別し始めていることがわかります。

ある程度進むとval_lossの値が減らなくなって、学習の終わりが近づいてきます。
Kerasでは自動的に学習の終わりを検知してまだEpochが最後までいっていなくても終了してくれる便利な機能があります。

<img width="809" alt="スクリーンショット 2016-12-02 14.55.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/15a1fa99-09c8-2c71-ff97-7768b59307a0.png">

モデルの学習が終わったら最後は
`model.predict_classes(test_X)`
をして、テストデータに対し予測を行います。今回はテストデータに対する正解ラベルtest_yも既知なのでそれを元にどのくらいの精度だったかを調べます。
上記の画像の最後の一行がその精度にあたり、**87.6%**でちゃんちーと向井さんを見分けていることがわかります。

#考察
この87.6％という値はあまり高くはありません。今回のようにCNNを利用したdeep learningでは90後半の精度は出て欲しいものです。データの少なさが原因だと思います。


参考までにこの人工知能が見分けられなかったちゃんちーの画像の一部をリストアップします。

<img width="614" alt="スクリーンショット 2016-12-04 9.48.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/8e13fbdf-11cb-31fe-f9ad-2327f8d3e247.png">


#フンジンと尾形さんの区別について
こちらは試してないのですが、上と全く同じ方法で区別可能ですね！

#まとめ
どうだったでしょうか？
実際にデータを集め、それを加工し、プログラムに投げ結果を考察する、人工知能で画像認識を行う全体の流れをわかってもらえたでしょうか。
人工知能・機械学習の勉強などをしているとすでに用意されたデータセット(有名どころだと手書き数字の[MNIST](http://yann.lecun.com/exdb/mnist/))を使ってチュートリアルを行うと思います。たしかにアルゴリズムの勉強にはそのステップが大事なのですが、やはり学んだことは**身近なことに応用**してみたいですよね。 deep learningを身近なことに使用してみたい！アイデアはあるんだけど！という人の参考になれば幸いです。 


これでちゃんちーと向井さん、フンジンと尾形さんをきっちり見分けることができましたね！キャンプやスクールで困った時ももう大丈夫です！メンターとパンサーの区別がつくと思います。


あ、あれ？


パンサーって


<img width="229" alt="スクリーンショット 2016-12-04 9.46.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/85972/1137421c-79e9-b3ec-2d0c-06a5879f99a2.png">


と

トリオ？

そうです。
まだ一人残っていました。

**パンサーの菅さんです！！！**


でも安心してください。
菅さんに似ているメンターはいませんでした。(2016年12月４日現在、へむへむ調べ)
今後加入されたらきちんと人工知能に学習させたいと思います。






はい！以上になります！
質問・意見などあったらどしどしお願いします。

明日は関西からの刺客**ありたく**さんです！
なにやら面白そうなタイトルです。12月は毎日が楽しみですね！

ではでは！

(本記事のパンサーの画像は全てgoogle画像検索結果のスクリーンショットです。)