ぴよ猫ちゃんの機械学習

AI、人工知能、機械学習について色々記事にしています。

Kerasでアニメ顔分類をやってみた

OpenCVで顔認識 顔分類を作ってみたいんだけど、どういう方法があるの?
OpenCVで顔認識 顔分類はKerasを使うのが簡単です。
やり方を説明します💛

今回はKerasで顔分類を実装する方法を解説します。

本ブログはSony Neural Networkをメインに紹介していましたが、最近ようやくKerasを触ってみたので、今回はKerasでの顔分類を紹介します。
話がいきなり横道にそれますが、Kerasを使った感触としては、分かり易いのはやはりSony Neural Networkなので、初心者にはSony Neural Networkをお薦めしますが、 Kerasは一時期ディープラーニングデファクトスタンダードになっていただけあり使い易く、慣れたらKerasの方が使い易いと思いました。

1.顔認識と顔分類の違い

AIで人物の顔を判定することを、顔認識とか顔分類と言いますが、この2つは意味が違うので混同しない様にしましょう。
私は最初ごっちゃに認識していました(-_-;)

顔認識とは?

顔認識は写真などに写る人物の顔の場所を特定することです。
この顔は誰かではなく、顔は何処にあるかです。Who?ではなくWhere?です。

顔認識 = 顔は何処にあるか? = Where?

f:id:shibayu2002:20191106221208p:plain
顔認識

本記事で紹介する顔分類はこれではありません。
顔認識についてはこちら↓↓↓の記事で詳しく紹介していますので、良ければ御覧ください。
OpenCVで画像データから顔を抽出する方法

顔分類とは?

顔分類は分析対象の顔を分類することです。
分類の方法は例えば、

  • 男か女か?
  • 子供か?大人か?
  • 何処の国の人か?
  • 誰か?

など様々です。顔認識がWhere?なのに対し、顔分類はWho? What?です。
(分かり易くするつもりで5W1Hで例えていますが、分類を英語にするとclassification = クラス分けです。カテゴライズすることです。)

顔認識と顔分類はセットで使うことが多い

顔認識と顔分類はセットで用いられることが多いです。
顔分類をしようとすると、まず画像から顔を抜き出してから分類する必要があるため、顔分類の場合、顔認識と顔分類はセットで用いられます。
逆に、顔認識はそれ単独で利用することもあります。例えば証明書写真のため写した画像から顔の部分のみを切り出す様な場合は顔分類する必要は無いため、顔認識のみが用いられます。

2.顔分類を行う2つの方法

顔認識を行うには大きく2つの方法があります。

  1. GoogleAPIなどのAPIを使う
  2. 自作する(ディープラーニングをする)

GoogleAPIなどのAPIを使う

顔分類を行う最も手軽な方法がGoogle, Amazonなどが提供するAPIを使う方法です。

APIを用いた顔分類】
Googleの画像認識APIは最強!!画像認識API徹底比較結果 - ぴよ猫ちゃんの機械学習

APIはただ呼び出せばよいので最もお手軽です。 しかし、APIはサーバで動くのでクライアントで処理するより遅いことと、APIの使用料がかかることがデメリットとして挙げられます。 また、APIは有名人の顔分類や、性別の判定などの分類機能は備えていますが、APIが提供する分類以外の分類は出来ません。 そのため、本記事のタイトルの「アニメ顔分類」みたいなことはAPIでは出来ません。

自作する(ディープラーニングをする)

APIで出来ないことは自作するしかありません。 分類はディープラーニングの本ブログで数回紹介したCNNやResNetで実現できます。

syuuai.hatenablog.com

CNNやResNetを実装する方法は色々あり、

などで実現が出来ます。 最近はOpenCVが流行りな様ですが、まだまだ記事も少ないので、今回はKerasを試してみました。

3.Kerasで顔分類

Kerasとは

KerasはPythonで書かれたオープンソースニューラルネットワークライブラリです。中心的な開発者はGoogleのエンジニアのFrançois Cholletで、TensorFlow、Theanoの上で動作し、ディープニューラルネットワークを迅速に構築することが可能です。Kerasは機械学習ライブラリというより機械学習ライブラリを用いるインタフェースという発想で設計されています。

wikipediaより

Kerasの開発環境を整える

Kerasの開発環境を整える方法はQiitaに綺麗にまとまっていたので、Qiitaに丸投げします。
以下の記事がとても参考になります。

qiita.com

学習データの準備

今回用意する画像データのフォルダ構成は以下の通りです。

└─data
   ├─tran  ・・・ 教師データ格納フォルダ
   │  ├─akame   ・・・ アニメキャラ名毎のフォルダ。フォルダ毎に当該アニメキャラの画像を格納する。
   │  ├─akuserareta
   │  ├─aren
   │  ・・・
   │  ├─yui
   │  └─yuusuke
   └─test  ・・・ テストデータ格納フォルダ
       ├─akame   ・・・ アニメキャラ名毎のフォルダ。フォルダ毎に当該アニメキャラの画像を格納する。
       ├─akuserareta
       ├─aren
       ・・・
       ├─yui
       └─yuusuke

顔分類のプログラム(学習)

# coding: UTF-8
import os
import cv2
import csv
import numpy as np
import matplotlib.pyplot as plt

def learn(names):
  # 1.学習データの準備
  # 1-1. 教師データ画像の読み込みとラベル付け
  X_train = []
  Y_train = []
  for i in range(len(names)):
    img_file_name_list=os.listdir("./data/tran/"+names[i])
    for j in range(0,len(img_file_name_list)-1):
        n=os.path.join("./data/tran/"+names[i]+"/",img_file_name_list[j])
        img = cv2.imread(n, cv2.IMREAD_COLOR)
        b,g,r = cv2.split(img)
        img = cv2.merge([r,g,b])
        X_train.append(img)   # 画像データ
        Y_train.append(i)        # 画像の正解ラベル
  # 1-2. テストデータ画像の読み込みとラベル付け
  X_test = []
  Y_test = []
  for i in range(len(names)):
    img_file_name_list=os.listdir("./data/test/"+names[i])
    for j in range(0,len(img_file_name_list)-1):
        n=os.path.join("./data/test/"+names[i]+"/",img_file_name_list[j])
        img = cv2.imread(n, cv2.IMREAD_COLOR)
        b,g,r = cv2.split(img)
        img = cv2.merge([r,g,b])
        X_test.append(img)
        Y_test.append(i)
  X_train=np.array(X_train)   # 画像データ
  X_test=np.array(X_test)      # 画像の正解ラベル

  # 2.Kerasのインポート
  from keras.layers import Activation, Conv2D, Dense, Flatten, MaxPooling2D
  from keras.models import Sequential
  from keras.utils.np_utils import to_categorical

  y_train = to_categorical(Y_train) 
  y_test = to_categorical(Y_test)

  # 3.ディープラーニングのモデルを定義する(今回はCNNモデル)
  model = Sequential()
  model.add(Conv2D(input_shape=(64, 64, 3), filters=32, kernel_size=(3, 3), 
                 strides=(1, 1), padding="same"))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Conv2D(filters=32, kernel_size=(3, 3), 
                 strides=(1, 1), padding="same"))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Conv2D(filters=32, kernel_size=(3, 3), 
                 strides=(1, 1), padding="same"))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Flatten())
  model.add(Dense(256))
  model.add(Activation("sigmoid"))
  model.add(Dense(128))
  model.add(Activation('sigmoid'))
  model.add(Dense(len(names)))
  model.add(Activation('softmax'))

  # モデル表示
  model.summary()

  # 4.コンパイル
  model.compile(optimizer='sgd',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

  # 5.学習実行(バッチサイズ=8、エポック=50)
  history = model.fit(X_train, y_train, batch_size=8, 
                    epochs=50, verbose=1, validation_data=(X_test, y_test))

  # 汎化制度の評価・表示
  score = model.evaluate(X_test, y_test, batch_size=8, verbose=0)
  print('validation loss:{0[0]}\nvalidation accuracy:{0[1]}'.format(score))

  #acc, val_accのプロット
  plt.plot(history.history["accuracy"], label="acc", ls="-", marker="o")
  plt.plot(history.history["val_accuracy"], label="val_acc", ls="-", marker="x")
  plt.ylabel("accuracy")
  plt.xlabel("epoch")
  plt.legend(loc="best")
  plt.savefig(os.path.join(os.path.dirname(__file__), 'result/learn_result.png'))

  # 6.学習済モデルを保存
  model.save(os.path.join(os.path.dirname(__file__), 'result/my_model.h5'))

# メイン処理
if __name__ == '__main__':
  names = []
  list_file = os.path.join(os.path.dirname(__file__), 'charctor.list')
  with open(list_file, encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
      names.append(row['id'])
  print(names)
  learn(names)

顔分類のプログラム(評価)

# coding: UTF-8
import os
import cv2
import csv
import sys
from PIL import Image
from keras.models import load_model
from mylib import image_util as mi
import numpy as np

def exec(names, target):
  ret = dl_eval(target)
  nameInfo = names[ret]
  print(nameInfo['id'] + "," + nameInfo['title'] + "," + nameInfo['full_name'] + "," + nameInfo['power'])


# 評価
def dl_eval(target):
  # 1. 学習済モデルの読み込み
  model_file_path='my_model.h5'
  model = load_model(model_file_path)
  image = cv2.imread(target)
  b,g,r = cv2.split(image)
  image = cv2.merge([r,g,b])

  X_test = []
  X_test.append(image)
  X_test=np.array(X_test)

  # 2. 学習済モデルを用いて画像データを分類
  ret = model.predict(X_test)
  nameNumLabel = np.argmax(ret)
  return nameNumLabel

if __name__ == '__main__':
  names = []
  args = sys.argv
  list_file = os.path.join(os.path.dirname(__file__), 'charctor.list')
  with open(list_file) as f:
    reader = csv.DictReader(f)
    for row in reader:
      names.append(row)
  exec(names, args[1])

GITにソースアップしました

アニメ画像の取得スクリプトと合わせてGITにソース公開しました。 参考にしてみて下さい。 なお、ちゃんとディープラーニングしてはいるものの、なんちゃって画像分類です。 教師画像の整形が手抜きなので・・・。たぶん、あんまり精度は良くないです。

github.com

4.顔分類でスカウターを作って遊んでみた

今回、サンプルプログラムの実行結果は記事にしません。 どんな動きするか知りたい方は、こちらのアプリをダウンロードして下さいーーー m(_ _)m
上述のプログラムを使ってアニメ顔分類をしています。

syuuai.hatenablog.com

一応本当にアニメ顔分類してます。(;^_^A

画像解析API徹底比較 それではまたー💛