TensorFlow+KerasでCNNを使いミス同志社になれる確率を計算できるAIモドキを作成して、Flask+Herokuで公開してみた。

# できたもの
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/157806/125f8618-fbed-89e6-e0c9-1ab5dcbf8307.png)

[ミスAI同志社](https://miss-ai-doshisha.herokuapp.com/)（メモリ不足で落ちてたらすみません。。。）
**このアプリは過去のノミネート者に似ているかどうかから判断しています。実際のミス同志社の選ばれる尺度は様々です。
結果は自己責任でお楽しみください。**

もし判定したりしたらSNSとかで共有してもらうと私が喜びます。(もちろん顔画像はサーバ上で保存されません。)



# はじめに
私が在籍している同志社大学の授業でエンジニアリングコンテストたるものが開催され、その時に作成しました。
なぜ作ったのかというと


**同志社大学の在籍者数は約3万人　
→ミス同志社に選ばれるのは毎年6人だけ。。
→そんなのおかしい
→僕も出たい！！！！！
→ならAIで解決しよう！！**

といったふざけた理由です。(~~他の参加者はめちゃくちゃ真面目なプロダクトでした。恥ずかしかった~~)



# 実現過程

![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/157806/f1441a8a-96ac-531e-c24c-c5c8db62c3c2.png)

![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/157806/cc3415ff-afdb-3c69-5f4b-52466af7552e.png)
(実際に使用したスライドを使っています)

上記のような図のとおり作成しました。ここでは実装上に気にかけたエッセンスを紹介したいと思います。



## 画像をダウンロード
Google Apiを使用しました。(参考:[Googleの画像検索APIを使って画像を大量に収集する](https://qiita.com/ysdyt/items/02a9e6b4e70f26385abc))

無料枠の1日1000枚までというのに苦しめられながら生データを2000枚ほど集めました。
しかし、どうやら調べると、「google-images-download」という鼻血モノの超捗るライブラリがあったらしく、無知は罪を思い知る。([Googleから画像を一括でダウンロードするツール「google-images-download」](http://co.bsnws.net/article/295))


## OpenCVで顔画像切り抜き
[Python + OpenCV で顔切り出し](https://qiita.com/ShirataHikaru/items/a1dab6c6b5ba088123e0)
上記のサイトを参考にして作成しました。

## TensorFlow+KerasでCNN
CNNはKerasのgithubに上がっているcifar10のソースを参考にしました。([heroku github](https://github.com/keras-team/keras/tree/master/examples))

CNNについては下記リンクがわかりやすく説明してるので必読かも、
[Convolutional Neural Networkとは何なのか](https://qiita.com/icoxfog417/items/5fd55fad152231d706c2)


### ここで問題点・・・
私の予想では、〇〇さん65%、△△さん10%、××さん25%とばらけた感じで分類されて、その比率を元に確立を計算できたらいいなぁと思っていましたが、なんと完成したニューラルネットワークでは、○○さん99%、△△さん0%、××さん0%となり偏りまくりで一瞬眼の前が真っ暗に。結局治りませんでした。サンプル数の数が少ないからなのか、分類されるパターンの数(ミスファイナリスト6 + はずれ1　より7つに分類される)が少ないからなのか・・・

**なんでこうなるか誰か偉い人教えてくださいm(_ _)m**

####ーー（追記）教えてくれました ーー
コメント欄で[ayumu838](https://qiita.com/ayumu838)さんがコメント欄で**「最終層でソフトマックスを使ってたらそうなるよ！！！」**と教えてくださいました！ありがとうございますm(_ _)m
実際にソフトマックス層を除去してみたり、他のソフトプラス層に変更してみたりすると・・・確かに**バラけました。**
しかし、バラけたと同時に、正答率も下がりました。。。[ayumu838](https://qiita.com/ayumu838)さんが**「強引ではありますが、出てきた値をソフトマックスではなく、総和が1になるように正規化する」**とご教授いただきましたが、いろんなライブラリ・チュートリアルをリスペクト~~(パクリ)~~し続けた私にはムズすぎぃっ！！！

案外、こういうところの調整方法とかが大学での卒論になったりするのかなぁ・・・と思いました。ありがとうございます！！
####ーーーーーーーーーーーーー


### なんとかして確率を出す
とりあえず、グランプリ、準グランプリ、ファイナリスト、はずれの順に重みを小さくし、最近のファイナリストはより重い重みを・・・等の試行錯誤で主観的に確立を何とか出るようにしました。**タイトルをAIモドキとしたのもこれが理由です。**

## Flask + BootstrapでWebアプリ化
Pythonの軽量WebフレームワークとオープンソースのcssのBootStrapを使い、レスポンシブルなwebページを作成しました。
どうやらpython-bootstrap といったライブラリがあるようですが、私の環境ではうまくいかなかったので普通のflaskに普通のbootstrapを使って実装しました。html触ったことなかったので辛かった。。。

## Herokuで公開
ここも結構苦労しました。TensorFlowを使うとHerokuがメモリ不足で頻繁に落ちてましたので、GCを走らせたり、time.sleep()でバッファをもたせたり工夫しました。(~~落ちないとは言っていない~~)

opencvはherokuにデプロイするためにはどうやらdockerイメージを作成したりとものすごく困難らしいです。。。ですがこのwebサイトが既存のbuildpackを使ったりしていてとても簡単に実装できて参考になりました。ほんとにありがとう。。。
[OpenCV で星座検出(4) - Heroku と Python3 と OpenCV ](https://takasa-5.blogspot.com/2018/02/opencv-4-heroku-python3-opencv.html)

## 結果
他の方の成果物やライブラリの継ぎ接ぎで作成出来ました。皆様本当にありがとうございました。

完成した後に、もちろん自分で判定してみました。
![無題4.png](https://qiita-image-store.s3.amazonaws.com/0/157806/24a01629-5429-8982-5c96-e3cf290576ad.png)




###どうやら、僕はミス同志社になれそうにないらしいです。お、おかしいなぁ。。。。