LoginSignup
5
7

More than 5 years have passed since last update.

TensorFlow + Kerasでフレンズ識別する - その3: 分類編

Last updated at Posted at 2017-08-12

学習済みのモデルを使って、未学習のファイルを分類させてみる。

分類

判定は、前述の通り「顔周辺」の画素を利用して行う。ただ、顔検出の部分から実装しはじめると本質的な部分に触れる前に処理が複雑になってしまう。そこで、まずは「手動で顔周辺のみを切り出した画像」を与えて正しく分類できるかを見てみる。

学習は「顔周辺」の情報だけを元に行なっているので、ここでいきなり全身が写った画像を入力して判定させてもいい結果は出ないので注意すること。

ソースコード

分類のコードは非常に短いため、先にコード全体を提示しておく。

# -*- coding: utf-8 -*-
import argparse
import numpy as np
from keras.models import load_model
from PIL import Image

parser = argparse.ArgumentParser(description='Predict.')
parser.add_argument('src_file', type=str, help='Source images file.')
parser.add_argument('model_file', type=str, help='Model file.')
parser.add_argument('--size', type=int, help='Width of image of model file.', default=48)
args = parser.parse_args()

image_size = args.size
model = load_model(args.model_file)

image = Image.open(args.src_file)
image = image.convert("RGB").resize((image_size, image_size), Image.ANTIALIAS)
image = np.asarray(image, dtype=np.float32).reshape(image_size, image_size, 3)
image /= 255.0

result = model.predict(np.array([image]), 1)[0]
for i, score in enumerate(result):
    print("Category-%d: %.2f"%(i, score))

まず、処理の本質的な部分ではないが、argparseを使って入力画像(判定したい画像)のパスと、判定に使用する学習済みモデルのパス、オプションで学習済みモデルの入力層に渡す画像のサイズを取得するようにしている。

model = load_model(args.model_file)

Kerasでは、load_modelメソッドを使って、学習済みモデルファイル(hdf5)から簡単にモデルを復元することができる。自分でソースコード上で学習時と同じモデル構造を再現し、そこに学習済みの重みをセットしていくのに比べて非常にコードがシンプルになる。別の構造を持ったモデルを使って推論をして、性能を比較したりしたい場合でも、ソースコードをいじることなく別のモデルを使用することができて非常に便利だ。

image = Image.open(args.src_file)
image = image.convert("RGB").resize((image_size, image_size), Image.ANTIALIAS)

入力画像は、ここではPillowを使って読み込み、3チャンネル化(グレースケールやアルファチャンネルが含まれている画像ファイルは、変換してやる必要がある)、入力層のサイズにあわせたリサイズを行っている。OpenCVを使っても実現は可能で、場合によってはOpenCVを使ったほうが良い場合(OpenCVの顔検出を使いたい、フィルターを適用したい、など)もあるが、必要がなければPython3系でも安定して使え、インストールが用意なPillowをお勧めしたい。

image = np.asarray(image, dtype=np.float32).reshape(image_size, image_size, 3)
image /= 255.0

その後、NumPyの機能を使って画像のピクセル配列をTensorFlowの入力層(image_size * image_size * 3チャンネル)に渡す用のfloat32の配列に変換する処理を行っている。同時に、正規化も行っている。image /= 255.0で配列の要素に対して一度に演算を行えるというのは、慣れないと不思議であると同時に便利だ。

学習時にはImageDataGeneratorがこの辺りの処理もやってくれていたが、今回は判定に使う一枚の画像をわかりやすく扱うため、ImageDataGeneratorを使わなかった。

result = model.predict(np.array([image]), 1)[0]

最後に、復元したモデルのpredictメソッドを使って、入力画像の分類を行う。predictメソッドは、一度に複数のデータを判定できるような構造になっているため、今回のように一個のデータ(1枚の画像)を判定させたい場合でも、要素一つの配列として入力を与え、結果の配列の一つ目を取り出して利用する形になる。

結果の配列には、各カテゴリのスコアが含まれているので、デバッグ用にそれを表示している。

この結果を見るとわかるように、結果はただのスコアの配列になってしまう。この配列の並びは学習時のカテゴリの並びと同一となるのだが、ここの管理は非常に重要であると同時に、適用にやっていたりするとあとで混乱の原因になるので注意したい。

顔の検出へ

ある程度未学習のデータでも正しく判定できてそうだったら、次は全身が写った画像を入力した場合でも正しく判定をできるように、顔検出と組み合わせてみる。

TensorFlow + Kerasでフレンズ識別する - その4: 顔周辺の切り出し編

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7