まっそのせかい

やった事のメモとか

卯月識別器の作成に挑戦した話

はじめに

機械学習とかDeepLearningとか、そういったワードを最近よく聞いてる気がするんですよ。 気になるのでそういうの触ってみたいなーとか思う訳ですよ。
僕は一応情報系の学科に所属する大学生で、パターン認識とかも少しくらいは勉強してる訳ですが、あまりプログラムとかは書いたことないなーって。
そんな中、今更ながら(?)ゼロから作るDeepLearningを読んでみたり、アニメキャラの識別をしている記事をいくつか読んだりして、「僕もなんかやってみたい!!!」ってなりました。

さて、プログラムを書く前に「まず何を識別しようか?」と考える訳ですが、やはりここは「推しキャラの識別に挑戦する」しかないでしょう。ちなみの僕の推しキャラはデレステ島村卯月です。卯月の笑顔はとても眩しくて、尊いです。

f:id:massoumen:20180102151718p:plain

なので、顔画像に対してそれが島村卯月かそうでないかを判定するプログラムの作成にチャレンジしました。
勉強も兼ねて、Pythonで作りました。作成の流れは以下のようになりました。

  1. 卯月と卯月以外の顔画像を集める
  2. サイズの統一や明るさの調節など顔画像に前処理を行う
  3. CNNに顔画像をぶち込んで学習させる

また、学習結果を利用し卯月なら赤い枠を、そうでないなら青い枠を付けるプログラムを作成しました。完成したプログラムにいくつか画像を入れて試してみた結果、以下のようになりました。

f:id:massoumen:20180102160002j:plain

f:id:massoumen:20180102160009j:plain

f:id:massoumen:20180102160016j:plain

f:id:massoumen:20180102160027j:plain

訓練用のデータは全てアニメのスクショなので、アニメの卯月の情報からゲームの卯月を識別できていると考えれば、悪くないのかなという気はします。(もちろん、うまく識別できなかったケースもありますが…)
以下、作業の内容とかを少し書いていこうかなと思います。

顔画像の収集

機械学習で良い結果を出すにはたくさんのデータが必要らしいので、まずはアニメのスクショをたくさん撮り、そこから顔を切り取り卯月とそれ以外に分けます。ここで、大量のスクショから顔を切り取るという作業が地獄だという事に気付いたので、先人たちを参考にし、OpenCVを用いたアニメ顔識別器を利用してスクショから顔画像を切り取ってもらいました。

卯月かどうかの判定よりアニメ顔を見つける事の方が難しいのではないか。

f:id:massoumen:20180102154910p:plain f:id:massoumen:20180102154951p:plain

こんな感じに切り取られた顔画像に対し、卯月と卯月以外に分ける作業を手作業で行いました。顔だと認識されていなかったり、顔以外のものが顔だと誤認識してるものもあるので、そういうのは自分で切り取ったり削除します。

プロデューサーと美城常務、顔認識されなさすぎる問題。(悲しいね)

最初は卯月とそれ以外で200枚と500枚くらい用意したのですが、これで学習させたらあまり上手くいかなかったので、最終的に550枚と1350枚くらいまで増やしました。ラブライブ!の人は6000枚以上、ごちうさの人は12000枚以上用意したらしいので、それに比べるとかなり少ないですね…けど、手作業で分類するの、結構疲れるんですよ…

プログラムに識別させるためにまず自分で識別してるの、なんだかなぁ。

顔画像の前処理

入力画像のサイズは統一する必要があるので、得られた顔画像を100*100の大きさに調節します。また、明るさの類は統一した方が良いのかなと思い、画素値の平均や標準偏差を揃えました。(この辺の処理は何が適切なのか正直良く分かっていない…いろんなパターンを試して比較するべきだった…)

f:id:massoumen:20180102170249p:plain f:id:massoumen:20180102170334p:plain

学習

集めた顔画像を訓練用とテスト用に分け、実際に学習させます。Kerasというライブラリを用いてCNNを構築し学習させました。また、ちゃんと卯月を見分ける事ができるかどうか、ゲームの画像を何枚か用意し自分で与え、判定させて試したりします。上手くいかなかったら訓練用の顔画像を増やすべくアニメのスクショを撮りに行ったり、Kerasに用意されているデータの水増し機能を試してみたりしました。
以下、いろいろ試した過程です。

卯月識別器1号

記念すべき第1号です。データ数は卯月、卯月以外でそれぞれ200枚、500枚となっています。ゲームの画像を与えたところ、ラブレター卯月は卯月ではないと判定されました。道のりは険しそうです。

f:id:massoumen:20180102171649j:plain

卯月識別器2号

データ数をそれぞれ350枚、950枚に増やしました。ところが、全て卯月じゃないと判定されてしまいました。
訓練データの正答率が100%となってるあたり、いわゆる過学習という奴でしょうか。やはりデータが少ないようです。

f:id:massoumen:20180102171951j:plain

卯月識別器3号

OpenCVを使って顔画像を回転させ、データ数を3倍に増やしました。恒常卯月のみ卯月だと判定されました。
やはり、まだ足りないのでしょうか。頑張ってスクショ撮りましょう。(疲れるんだよなぁあの作業…)

f:id:massoumen:20180102172320j:plain

卯月識別器4号

データ数をそれぞれ550枚、1350枚に増やしました。1号に比べるとだいぶ増えましたね。(まだまだ少ない感が拭えませんが…)
回転させてデータ数を3倍にした場合もそうでない場合も、恒常卯月しか卯月と判定してくれませんでした。
訓練用に含まれていないアニメopの卯月も1枚用意してみたんですが、それも卯月じゃないと言い出す始末。

お前は何を見て育ったんだ。

f:id:massoumen:20180102172727j:plain

ループを回しすぎなのかなぁと思いループ数を減らしてみたら、天海春香島村卯月だと判定されてしまいました。

f:id:massoumen:20180102172848j:plain

ここで、最後の確認用のデータは手動で切り取っていたのですが、訓練データと同様にアニメ顔識別器で切り取った方が良いのではないか?と思いアニメ顔識別器を使って切り取って用いてみました。その結果、なんか精度が上がりました。訓練データの顔画像にはあまり髪の毛の部分が含まれていないので、そのせいで髪の毛を多く含んだラブレター卯月の顔画像は識別できていなかったのかなぁ…?(恒常佐久間まゆがうまく切り取られていなくて少し悲しかった。イーブイもダメだった。)

f:id:massoumen:20180102173223j:plain

卯月識別器5号

データ数はそのままですが、Kerasにデータを水増しする機能が含まれているらしいので使ってみる事に。(良く分かっていない顔)
学習にかかる時間が増えているっぽいので、たぶんちゃんと水増しされています。最後の確認用のデータも増やしてみましたが、今までで一番いい感じに識別できています。そろそろ疲れてきたのでこの辺で一旦完成という事にして学習結果を保存しました。

f:id:massoumen:20180102173713j:plain

卯月識別器の完成

得られた学習結果を利用し、画像が与えられたらアニメ顔認識器で顔を認識し、さらにそれが卯月であるかどうかを卯月識別器で判定するプログラムを作りました。記事の初めの方に載せた奴以外にもこんな感じの結果が得られました。顔認識がそもそもされていなかったり、されても卯月かどうかの判定に失敗していたりと、認識の難しさを感じる…

f:id:massoumen:20180102185154p:plain

f:id:massoumen:20180102185750j:plain

f:id:massoumen:20180102185800p:plain

f:id:massoumen:20180102185820p:plain

また、ゲームのイラストに関してはそこそこの精度でちゃんと卯月かどうか判定してくれるんですが、いろいろな絵師が描いた卯月については思ってた以上に精度が落ちますね…絵柄の違いが響いているのでしょうか。僕は絵柄とかによっては卯月かどうか判別しにくい場合があったりしますが、卯月識別器もそうなんですかね。いったい、何が「これは卯月である」と言わせているんですかね。

「卯月」とはいったい…(哲学)

感想

2,3日くらい卯月識別器と格闘していましたが、初めて挑戦したという事もあり、中々楽しかったですね。なんやかんやそれっぽく識別できてる感があるのもあり、いろいろな画像で試してみては「お~」って感じになってます。DeepLearningの類はデータがたくさん必要らしいですが、実際に動かしてみてそれを強く感じましたね…何はともあれ、使えるデータがたくさん必要だなと。今回はCNNの層の構成を変化させたり、画像の前処理などについてちゃんと調査したりしていないので、その辺についても調べていきたいですね。
また、今回いろいろ試してみて「まだまだ知識不足だな~」というのも強く感じたので、勉強も必要かなと。

気が向いたらソースコードどっかに上げたり改良版作ったりするかも…?