読者です 読者をやめる 読者になる 読者になる

Deep LearningでサノバウィッチOPから本編のキャラクターを識別した話

f:id:h1dia:20170101143907p:plain

(c)YUZUSOFT/JUNOS INC.
(敬称略です)

美少女ゲーム「サノバウィッチ」*1では、フロンティアチャイルドによるフルアニメのオープニングムービーが流れます。
www.youtube.com

しかしながら本編CGはむりりん、こぶいちによって描かれており、それぞれの絵を見比べてみるとやや絵柄が違うことが分かります。

私たちは一方の絵を見ても髪色などの情報からもう一方の絵がどのキャラクターなのかを正しく識別することが出来ます。では、機械も同様にキャラクターを識別することが可能なのでしょうか?
今回はConvolutional Neural Network(CNN)にサノバウィッチのオープニング動画のみを与え、本編のCGからキャラクターを正しく認識できるのかを検証してみます。

今回はこちらの記事を参考にさせていただきました。 christina.hatenablog.com

Neural Networkってなんだ

Twitterに適当なキャラクターの画像を貼り付けて適当に「これは○○ちゃんだ!」とツイートする、という作業を考えてみましょう。

f:id:h1dia:20170101155905p:plain

大きく間違えた場合には多くのユーザから東京湾に沈められそうになっています。このままでは命が危険なため「この解答は大きく間違っているんだ」と認識し、解答を正しい方向に大きく修正します。
大きくは間違えていないが微妙に違うような場合は一部のユーザから東京湾に沈められそうになっています。先程よりは命の危険が少ないため「この解答は少し間違っているんだ」と認識し、解答を正しい方向に修正します。 正しい回答をした場合は褒められこそしませんが、何も文句を言われていないので「ああ、この解答は正解しているんだな」と認識し、解答を修正しません。

この例のように、ヒトが経験から物事を学ぶのと同様にしてNeural Networkも経験から学びます。すなわちアメとムチです。 僕は小さい女の子にムチで叩かれるのが好きですが、ネットワークを叩くムチはTwitterの例と同様に「本来の解答とネットワークの出した答えとの差」になります。このムチを目的関数と言い、ネットワークはこの差を0にするように学習を行うことを目標とします。

ちなみに今回扱うCNNのConvolutionalは畳み込みの意で、Neural Networkに畳み込み処理を追加したものです。

顔画像の抽出

まずはネットワークに学習させる「オープニングに映っている各キャラクターの顔」を切り出します。顔検出器を作るのは今回やるべき仕事ではないのでlbpcascade_animefaceをお借りして顔画像を切り出すスクリプトを書きます。

github.com

あらかじめOP動画から連番のpngを出力しておいて、スクリプトに切り出し作業を全部投げたあと手作業で各キャラクターの顔をフォルダ分けしていきます。今回はヒロイン5人(寧々、めぐる、紬、憧子、和奏)とその他人物の顔、また顔検出器の誤検出を見越して顔以外、という7つの分類(7クラス)とします。

f:id:h1dia:20170101162447p:plain

検証用データセットはこの中から適当に分離しました。またOPの最後はむりりん、こぶいちによる絵のため学習データからは除外しています。

CNNを構築する

今回はTensorflowをバックエンドとしたKerasを利用してモデルを構築します。モデルの構成はKerasのチュートリアルにあるCNNによるCIFAR-10の10クラス分類の実装を流用します。
入力は32x32にリサイズされたBGR画像です。前の段階で得た画像をCNNに学習データとして与え、ネットワークを学習させます。 ただし、顔画像のデータセットが1クラスあたり50~100枚程度と非常に少ない*2ため、画像をランダムに拡大(±5%)・回転(±25度)・左右反転させたものを学習データとして扱い、疑似的に顔画像の枚数を増やしています。

gist.github.com

これでネットワークをOP動画のみ、すなわちフロンティアチャイルド絵のみによって学習させることができました。

立ち絵を識別してみよう

受け取った画像をOpenCVによって顔画像だけトリミングし、学習させたCNNを使って各画像をどのキャラクターなのか分類していきます。

gist.github.com

赤枠がCNNが受け取った領域、水色の文字が赤枠領域に対するCNNの解答です。 f:id:h1dia:20170101172146p:plain しっかりと全ヒロインが分類できています。
相馬さんがめぐるちゃんとして認識されるんじゃないかなあと思っていましたが、ちゃんとその他のキャラクターとして識別されました。

f:id:h1dia:20170101185252p:plain 目をつぶってもらいました。紬ちゃんだけ戸隠先輩として誤識別されています
目の情報が失われると認識精度が落ちるようです。単純に髪の色で判断してる訳ではなさそうですね

f:id:h1dia:20170101173153p:plain メガネとハイライト消しです。これは正しく分類されていますが、戸隠先輩の服が和奏ちゃんとして認識されるとんでもない事態が発生しています。
非顔画像は「OP動画で顔検出されたもののうち顔でないもの」として学習をサボったため、多分顔検出器の誤検出+それっぽい色でこのような識別結果になった可能性があります。 顔検出器のチューニングには触れない方針ならば、もっとCNN側に手作業で顔でない負例画像を追加してあげる必要があることが分かります。
めぐるちゃんの眼鏡画像は学習データには一切入っていないのですがよく分類できたなあと思います。やっぱり髪色が一番大きな特徴として捉えられてるのかなあ

ちなみに、冒頭の画像を前処理を行わずに学習させたCNNに投げると f:id:h1dia:20170101183249p:plain f:id:h1dia:20170101183407p:plain と、散々な結果になります。 データの定義域がある程度狭いことが分かっているならばある程度の学習データ数を用意し、それを適当な操作で増やすことによって認識精度を上げられるようです。

絵柄は識別に大きく影響せず、キャラクターの特徴をしっかりと掴めていれば異なる絵においてもちゃんと分類できることが分かりました。 CNNの画像分類は大分出尽くしている感があるので、少ないデータセットで認識精度を上げる方法を模索出来たら面白そうです。

おまけ

f:id:h1dia:20170101183546p:plain ですよねー!

*1:好評発売中

*2:数千枚単位で用意している例が多い