TensorFlowによるももクロメンバー顔認識(中編)

  • 35
    いいね
  • 2
    コメント

前編はこちら
http://qiita.com/kenmaz/items/4b60ea00b159b3e00100

機械学習やディープラーニングについては全く初心者のソフトウェアエンジニアが、畳込みニューラルネットワークを用いて「ももいろクローバーZ」のメンバーの顔識別を行うアプリを作った話の続きです。

deeplearning

前編ではクローラーが集めてきた画像から顔画像を取り出し、学習用データを生成するところまで説明しました。ここからようやく学習に入ります。

機械学習部分のコードは、Tensorflowに付属にしている Deep MNIST for Expertsと、CIFAR-10 Classificationあたりのコードをベースに実装をすすめました。

CSVの生成と読み込み

gen_testdata.py
https://github.com/kenmaz/momo_mind/blob/master/deeplearning/gen_testdata.py

まず訓練データをTensorflowに食わせる部分ですが、MNISTのサンプルコードと同様、CSVを生成し、そいつを読みこませることにしました。前編では学習用のももクロメンバー画像をそれぞれMacのFinder上でフォルダ分けしましたが、そのフォルダ/ファイルの構造を元に、

訓練用画像のファイルパス,メンバー名を0-4に対応させた数値

という形式のCSVを吐く小さいスクリプトを書きました。

ちなみにTensorflowでは訓練データをこんなような protocol bufferでシリアライズして、TFRecordsというファイル形式に書き出すのがオススメらしいです。ちょっと面倒だったので今回は見送りました。

学習データの入力

以下がCSVを読み込み後述のモデルの入力データとなるTensorを構築するスクリプトです。
mcz_input.py
https://github.com/kenmaz/momo_mind/blob/master/deeplearning/mcz_input.py

TensorFlowにはテキストファイルを読み込む tf.TextLineReaderや、読み込んだデータをcsvとしてデコードしてくれるtf.decode_csv関数など、便利なクラスや関数が予め用意されています。こいつらを使って入力データを読み込めば、そのままTensorFlowへの入力データ形式であるtf.Tensorを自動的に構築してくれます。

さらに機械学習のテクニックとして、訓練サンプル画像を左右反転したり、ちょっと回転させたりズームさせたり、コントラスをランダムに変えるなどすることによって、訓練サンプル画像を「水増し」するテクニック(「データ拡張」と呼ぶらしい)がありますが、それらの処理もほとんどTensorFlowが用意してくれています。

ランダムに左右反転させるtf.image.random_flip_up_down(), 明るさをランダムに変えるtf.image.random_brightness()、同じくコントラストを変える tf.image.random_contrastなど。

最初はこれらの関数の存在に気づかず、自分でopenCVを使ってがんばっていたのですが、素直にTensorFlowのものを使ったほうが良さそうですね。

バッチ入力

今回は訓練データとして、各メンバー150枚ずつ、計750枚の顔画像を用意してあります。これらからランダムに120枚の画像を取り出し、上記の通りデータ拡張を行いランダム化させた上で、学習モデルの入力としてまとめてぶち込みます。この作業を1ステップとし、1000ステップ〜30000ステップほどひたすら学習を繰り返します。

学習モデル

今回作ったコードの中でおそらくいちばん重要な、学習/推論のモデルを組み立てるスクリプトです。
mcz_model.py
https://github.com/kenmaz/momo_mind/blob/master/deeplearning/mcz_model.py

モデルの検討その1

まずは以下のような畳み込みニューラルネットワークのモデル定義してみました。
https://github.com/kenmaz/momo_mind/blob/master/deeplearning/mcz_model.py#L6

- 入力 (28x28 3chカラー)
- 畳み込み層1
- プーリング層1
- 畳み込み層2
- プーリング層2
- 全結合層1
- 全結合層2

これはほとんどCIFAR-10のサンプルそのままのやつです。このモデルだと、分類精度だいたい65~70%程度しか出ませんでした。

そもそも入力28x28なのはCIFAR-10のサンプルをそのまま持ってきたからですが、28x28といえば、例えばこれ、28x28の画像です。
スクリーンショット 2016-05-24 3.19.59.png
うーん、誰でしょうね?(僕はわかりますけど

この荒い画像から特徴を探しださなきゃいけない、ってことで人間がやってもいかにも大変そうです。もっと高解像度にしたい。

モデルの検討その2

ということでもうちょい精度を高めたいなと思い、入力画像の解像度を倍にして、さらに畳み込み&プーリング層をひとつづつ追加しました。
https://github.com/kenmaz/momo_mind/blob/master/deeplearning/mcz_model.py#L53

- 入力 (56x56 3chカラー)
- 畳み込み層1
- プーリング層1
- 畳み込み層2
- プーリング層2
- 畳み込み層3
- プーリング層3
- 全結合層1
- 全結合層2

という畳み込みニューラルネットワークのモデルを定義しました。
すると精度は最終的に85%程度まで上昇しました。

56x56の画像といえばこんな感じです。
スクリーンショット 2016-05-24 3.19.36.png
今度は誰だかわかりましたよね?

このくらいの解像度になってようやくえくぼが認識できます。やっぱりこれくらいはほしいですよね。

さて、じゃあもっと解像度を上げて、層を増やせばもっと精度向上できるんだろうな、と思い、
実はさらに層を増やしたり、入力の解像度を高めたりしたバージョンも作っては見たのですが、なかなかクロスエントロピーが収束せず、うまく行きませんでした。原因はよくわかってません。すぎゃーん氏のブログによると112x112の入力で90-95%まで達成できたとのこと。どこで違いが出たのだろう。。

モデルのグラフ

TensorFlowには学習モデルをグラフで表示してくれる機能が付いているので、雑な説明つきで以下に貼っておきます。

スクリーンショット 2016-05-24 3.09.13.png

下から上に向けてデータが流れていくイメージです。

中編おわり

そろそろ眠くなってきたので、つづきはまた後日。