けものフレンズ解析機作ってみた。- 前編 -
はじめに
会社で学べること以外に自分で勉強して行かないといけないと思い、今流行りの機械学習でwebアプリを作ることに挑戦してみました。
何番煎じかわかりませんが、自分が好きな「けものフレンズ」の顔認識+判定機を作成してみることにしました。
記事公開しようと思っている矢先にネタが被った上になんかもっといい感じのやつが出ていました。。。
yokoeworld.hatenablog.com
フ、フレンズによって得意なことが違うから!
ちなみに、僕は機械学習に関してはほとんどわからない状態です。
色々な記事を追ったり、たまにコードをコピペして動くのをみていた程度です。
開発にはmacを使用しました。
目的
今回は以下2つを目的に作成しました。
- とりあえず機械学習を用いてなんらかのwebアプリを作成する
- サーバを立てて、公開しても問題ないようにする
作業をしていく上でつまるところが出てくる(特に機械学習部分)のでそこは、動けばとして次に進むことにします。
というのも、今まで期間をかけすぎてダレてしまって最終的に完成しなかったことが何回もあり、繰り返さないためにも自分でこういったルールを設けます。
また、今まで自分一人でサーバを立てて公開したことがないので、今後のことを考えると公開できるよにセットアップできるようにすることも学習の目的です。
製作物
こちらに公開しています。よかったら試してみてください。
現在休止中です。ご了承ください。
現在は「サーバル」「カバン」「アライさん」「フェネック」の4種類しか判定できません。
その他はフレンズと判定されるはずです。
最終的に製作に約2ヶ月かかりました。
作成期間中、空いている時間のほとんどを作業に当てていました。
なんとか満足がいくものができてよかったです。
構成
大まかの構成は以下のようになっています。
細かい内容に関しては後で解説していきます。
機械学習編
初心者にも優しそうなでかつ今回のアプリを作るのに役に立ちそうな、以下の2記事を読み込んで実行してみました。
今回機械学習において、ほとんどコードを参考にしたサイトから拝借してます。
一応参考にしたコードの多くはpython2だったのでそれをpython3に直して使っています。
フレンズの顔画像収集
まず機械学習に必要な顔画像を収集していきます。
事例を調べた限りだと、大量のスクショを集める→顔を判定して画像を切り出す→画像をラベルごとに整理する、という流れで作業を行うようです。
もし顔認識がうまくできないと、手動で全部切り出していくみたいです。
なので、まず顔認識を行えるか確認していきます。
顔認識について
アニメ顔に近いとlbpcascade_animefaceというもの先人の方々の知恵が使えるのですが、残念ながらフレンズの顔は一般的なアニメ顔とは異なるようで、判定はできるものの精度はそこまで高くありませんでした。
そのため自分で分類機を作成する必要が出てきて、こちらの記事にあるようにdlibにて判定機を作成することにしました。
作成用のコードも同じ記事から拝借して使用しています。
インストール
以下の4つのライブラリをインストールする必要があります。
調べてところopencvを入れるのにanacondaを使用している例が多かったので、pyenvでanaconda3-4.0.0
を入れました。
ただ、この際にanacondaのroot環境に直で入れてしまいました。一般的に複数バージョンを扱えるように環境を分けることが多いので、本当は分けたほうがいいです。
当時はそこまで気が回っていなかったのでそのままインストールしました。
opencvはそのまま入れただけでは動かないかも(メモを紛失してしまい定かではありませんが)しれないのでエラーでググって解決しましょう。
他のライブラリも全部anacondaからインストールしました。
brew等でもboostやpython-boostは入れられるのですが対象としているpythonのバージョンが異なったり、実行してもエラーが多発して、悩んだ挙句最終的に全部アンインストールしてanacondaでいいれたらすんなり入ったかからです。。。
詳しくない方はanacondaに任せるのがいいでしょう。
学習と確認
約150枚の画像から顔の位置をだいたい正方形になるようにして取ってきて、ファイルに保存、xmlファイル生成しました。
120枚を学習、30枚をチェックに使用して学習させました。
軽くチェックを行なった結果、かなりの精度で取れるのを確認しました。
また、学習に使ったのはサーバル、カバン、アライさん、フェネックの画像であったが、精度は高くないが他のフレンズの顔も検出できていました。
ただ、なぜかプリンセスのヘッドフォンの赤い丸を検出していました。。。
原因は不明ですが、目視でデータ整理する時に省くので問題はありませんでした。
顔画像の収集と水増し
次にdlibにて作成した判定装置を使って、大量のスクショから顔の画像を取り出しました。
スクショの画像は1から12話でなるべくシーンが被らないようにスクショしていきました。
この際、フレンズの顔以外のものを検出していたり、画像ファイルが破損している物があったので削除して整理しました。
集まった画像の枚数は以下の通りになります。
フレンズ | 画像枚数 |
---|---|
サーバル | 208 |
カバン | 167 |
アライさん | 40 |
フェネック | 42 |
どうしても出番が少ないアライさんとフェネックの画像数が減ってしまいました。
そこで、画像の水増しを行い6倍にします。
pillowを用いて一つの画像から
- 元の画像より明るいもの
- 元の画像より暗いもの
- 元の画像を反転したもの
- 元の画像を反転して明るくしたもの
- 元の画像を反転して暗くしたもの
を生成した水増しすることにしました。
これでそれぞれアライさんが236枚、フェネックが248枚になり十分な量の画像が用意できました。
何枚か画像が破損しているのもがあったので枚数は6倍ぴったりではないです。
カバンの画像が他に比べ少ないですが、多分大丈夫だろうと信じて水増しはしていません。
たつきを信じろ。
tensorflowでの学習
顔の画像が集まったのでtensorflowを用いた学習に入ります。
基本的にこちらの記事の手法とコードを拝借して行いました。
インストールしたtensorflowのバージョンが参考にしたサイトのものと異なるようで所々警告やエラーが出ました。
こちらの解説にあるように対応表を確認しながら修正しました。
ちなみに、学習の何回か行なったのですがうまくいかない時もありました。
ここの原因は不明です。
学習が終わるといくつかの中間データや最終生成物が出てきます。
以下の3つのファイルを判定に用います。
model.ckpt.data-00000-of-00001 model.ckpt.index model.ckpt.meta
バージョンの違いから参考にしたサイトの生成物が異なり、使用する際も以下のようにコードを修正するが必要があります。
# 前 saver.restore(sess, "/tmp/model.ckpt") # 後 saver = tf.train.import_meta_graph('/tmp/model.ckpt.meta') saver.restore(sess, "/tmp/model.ckpt")
参考 : https://stackoverflow.com/questions/41265035/tensorflow-why-there-are-3-files-after-saving-the-model
また、こちらのevalを実行する際に再帰的に判定する場合にはリセットが必要らしいので下記のリンクを参考に修正しました。
ただ、本質的に理解をしていないのでもしかしたら正しくないかもしれません。
参考 : https://stackoverflow.com/questions/41400391/tensorflow-saving-and-resoring-session-multiple-variables
元のeval.pyをdlibで判定できるように修正しました。
画像が排出され、ターミナルで判定結果が出ていることが確認でき正常に動いていることがわかりました。
これで機械学習部分は終わりです。
一応動くものはできましたが、コードをかけるようになるにはまだ勉強が必要だと思いました。
実際、学習させる顔画像の解像度をあげる方すらわかりません。。。
今回は動くものを作るのが目的なので、次にステップに進むことにしました。
あと、内容と関係ないのですが、長文を書くのは難しいなと痛感しました。
下手な小学生の日記みたいな「~でした。」の繰り返しで、すごく単調な文章になってしまいました。。。
ここら辺も勉強が必要なようです。
次はwebアプリの実装を行なっていこうと思います。