顔写真からジャニーズ系かEXILE系かを判定する学習モデルを深層学習を用いて作成してみた(~学習モデルの作成から評価編~)

プログラミング
顔写真からジャニーズ系かEXILE系かを判定する学習モデルを作成してみました。
全3回の記事の予定です。

本記事は、 「データの前処理」から「テスト・評価」 (記事 2/3)を掲載しています。

はじめに

Udemyの機械学習講座を受講し終わったので、成果物として作ってみました。
詳細なソースコードはGitHubに上げていますので、よろしければそちらを参照ください。

また、画像のクローリング・顔検出処理の詳細は以前書いたこちらの記事を参考ください。

動作環境

・Anaconda 3
・TensorFlow (CPU版)

全体の処理フロー

全体の処理フローを下図に記します。
本記事では、「データの前処理」から「テスト・評価」について説明していきます。

データの前処理

収集した教師データの画像をTensorFlowが扱いやすい形(NumPy配列形式)に変換していきます。
そして変換されたNumPyファイルを出力します。
また、その際にscikit-learnを使って学習用と評価用のデータに分けてあげます。

モデルの定義

今回は深層学習ライブラリであるKerasを使ってモデルを定義してみました。

とりあえず複雑なことはせずに、Kerasの公式ドキュメンテーションを参考にニューラルネットワークを作ってみました。

今回は「ジャニーズ系」か「EXILE系」かの2クラスの画像分類問題ですので、出力層はノードが2つになります。
ソースコードはこちら。
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.utils import np_utils
import keras
import numpy as np

classes = ["exile", "jonnys"]
num_classes = len(classes)
image_size = 50

# メイン関数の定義
def main():
    x_train, x_test, y_train, y_test = np.load("judge_exile_johnnys.npy")
    # データの正規化
    x_train = x_train.astype("float") / 256
    x_test = x_test.astype("float") / 256
    # ラベルのone-hot-vector(正解は1, 他は0となるような処理)
    y_train = np_utils.to_categorical(y_train, num_classes)
    y_test = np_utils.to_categorical(y_test, num_classes)

    # モデルの生成
    model = model_train(x_train, y_train)

    # モデルの評価
    model_eval(model, x_test, y_test)

def model_train(x, y):
    #層の定義
    model = Sequential()
    model.add(Conv2D(32,(3,3), padding='same', input_shape=x.shape[1:]))
    model.add(Activation('relu'))
    model.add(Conv2D(32,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64,(3,3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(2))#クラスの数(今回は画像のクラスが2つ)
    model.add(Activation('softmax'))

    # 最適化の定義
    opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
    model.compile(loss='categorical_crossentropy',
                    optimizer=opt, metrics=['accuracy'])

    model.fit(x, y, batch_size=32, epochs=25)

    # モデルの保存
    model.save('./exile_johnnys_cnn.h5')

    return model

def model_eval(model, x, y):
    scores = model.evaluate(x, y, verbose=1)
    print('Test Loss: ', scores[0])
    print('Test Accuracy: ', scores[1])

if __name__ == "__main__":
    main()

 

トレーニング(教師あり学習)

作成したモデルを使って学習してみます。

結果がこちら。

結果
 ・トレーニング画像のAccracy: 82%
 ・テスト画像のAccruacy: 71%
パラメータチューニングも教師データの水増しもやっていないので、

こんなものかなって感じです。

テスト・評価

精度は大して良くないモデルですが、これを使っていくつか画像分類してみました。
評価に使った画像は未学習のグループにしました。

評価に用いたソースコードはこちら。

from keras.models import Sequential, load_model
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.utils import np_utils
import keras, sys
import numpy as np
from PIL import Image

classes = ["exile", "jonnys"]
num_classes = len(classes)
image_size = 50

def build_model():
    #層の定義
    model = Sequential()
    model.add(Conv2D(32,(3,3), padding='same', input_shape=(50,50,3)))
    model.add(Activation('relu'))
    model.add(Conv2D(32,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64,(3,3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(2))#クラスの数(今回は画像のクラスが2つ)
    model.add(Activation('softmax'))

    # 最適化の定義
    opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
    model.compile(loss='categorical_crossentropy',
                    optimizer=opt, metrics=['accuracy'])

    # モデルのロード
    model = load_model("./exile_johnnys_cnn.h5")

    return model

def main():
    image = Image.open(sys.argv[1])
    image = image.convert('RGB')
    image = image.resize((image_size,image_size))
    data = np.asarray(image)
    X = []
    X.append(data)
    X = np.array(X)
    model = build_model()

    result = model.predict([X])[0]
    predicted = result.argmax()
    percentage = int(result[predicted] * 100)
    print("{0} ({1} %)".format(classes[predicted], percentage))

if __name__ == "__main__":
    main()
・EXILEグループのメンバーはどう分類されたのか?
 使った画像は「THE RAMPAGE LIKIYA」さんです。

見事に正解しました。

・ジャニーズグループのメンバーはどう分類されたのか?
 使った画像は「NEWS 手越祐也」さんです。

分類に失敗して、EXILE系に分類されてしまいました。。

今回はニューラルネットワークのパラメータチューニングや教師データの水増しもやっていませんでしたが、
次回はこれらを実践してみて、どの程度精度があがるかを検証してみたいと思います。

参考

・顔写真から、乃木坂46系かAKB48系か一般人系か判定する学習モデル作ってみた
・Keras公式ドキュメンテーション

 

スポンサーリンク



タイトルとURLをコピーしました