第2回 Kerasで実践! Cats vs. Dogs (5/6)

技術特集

1_tensorflow_keras1_tit

tit_tensorflow_keras

5) 判定部分の実装

学習ができたところで、学習済みモデルを利用して未知の画像を判定する部分を実装していきます。

判定対象画像の読み込み

まず画像の読み込みですが、学習時とは違って特定の1枚の画像を読み込むという操作なので、ImageDataGeneratorとは違う方法を使っていきます。
具体的にはkeras.preprocessing.imageパッケージで提供されているload_imgimg_to_arrayを用います。

from keras.preprocessing.image import load_img, img_to_array
import numpy as np
 
...
 
    image_infer = load_img(args.infer, target_size=(input_size_x, input_size_y))
    data_infer = img_to_array(image_infer)
    data_infer = np.expand_dims(data_infer, axis=0)
    data_infer = data_infer / 255.0

load_imgで画像ファイルを読みこみ、img_to_arrayでKerasで扱える形式に変換します。
np.expand_dimsという部分は、「1枚の画像」を「1枚の画像を含む配列」に変換する操作です。
Kerasの判定処理を行う機能が「復数の画像を含む配列」という形式を要求するため、このような操作を行っています。
最後に画像データの各ピクセルの値を255で割っていますが、これは各ピクセルの値を0以上1以下に正規化する操作で、学習用のブロックでImageDataGenerator(rescale=1.0 / 255)とした部分に対応しています。

判定処理

判定を行う前にload_weightsメソッドで学習済みモデルを読み込む必要があります。
その後predictメソッドで判定処理を実行します。

    # 判定処理の実行
    model.load_weights(os.path.join(checkpoint_dir, 'mydnn_weights.hdf5'))
    result = model.predict(data_infer)[0] * 100
 
    # 判定結果の出力
    if result[0] > result[1]:
      print('Cat (%.1f%%)' % result[0])
    else:
      print('Dog (%.1f%%)' % result[1])

predictの結果としては「復数の画像に対する判定結果の配列」が返ってきます。今回は画像が1枚だけですので[0]で直接取り出しています。
個々の結果は[猫である確率, 犬である確率]という形式になっており、今回はこれに100をかけてパーセンテージの値を得ています。
猫が先に来ているのは、ImageDataGeneratorによる学習データ読み込み時にディレクトリ名を用いて順序が決められるためです。

コード完成

これらのコードを含めて、いよいよcat_dog_dnn_keras.pyの完成となります:

import argparse
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array
import numpy as np
import os
from mydnn_keras import MyDNN
 
input_size_x = 224
input_size_y = 224
batch_size = 20
input_size_c = 3
output_size = 2
epochs = 10
checkpoint_dir = 'ckpt'
 
parser = argparse.ArgumentParser()
parser.add_argument("--infer", action="store", nargs="?", type=str,
                    help="学習は行わず、このオプションで指定した画像ファイルの判定処理を行う")
args = parser.parse_args()
 
model = MyDNN(input_shape=(input_size_x, input_size_y, input_size_c),
              output_size=output_size)
 
if not args.infer:
    print("学習モード")
    # 学習データの読み込み
    keras_idg = ImageDataGenerator(rescale=1.0 / 255)
    train_generator = keras_idg.flow_from_directory('data/train',
                          target_size=(input_size_x, input_size_y),
                          batch_size=batch_size,
                          class_mode='categorical')
    valid_generator = keras_idg.flow_from_directory('data/valid',
                          target_size=(input_size_x, input_size_y),
                          batch_size=batch_size,
                          class_mode='categorical')
 
  
    # 学習の実行
    num_data_train_dog = len(os.listdir('data/train/dog'))
    num_data_train_cat = len(os.listdir('data/train/cat'))
    num_data_train = num_data_train_dog + num_data_train_cat
 
    num_data_valid_dog = len(os.listdir('data/valid/dog'))
    num_data_valid_cat = len(os.listdir('data/valid/cat'))
    num_data_valid = num_data_valid_dog + num_data_valid_cat
 
    model.fit_generator(train_generator,
                        validation_data=valid_generator,
                        epochs=epochs,
                        steps_per_epoch=num_data_train/batch_size,
                        validation_steps= num_data_valid/batch_size)
 
    # 学習済みモデルの保存
    os.makedirs(checkpoint_dir, exist_ok=True)
    model.save_weights(os.path.join(checkpoint_dir, 'mydnn_weights.hdf5'))
else:
    print("判定モード")
    # 判定する画像の読み込み
    image_infer = load_img(args.infer, target_size=(input_size_x, input_size_y))
    data_infer = img_to_array(image_infer)
    data_infer = np.expand_dims(data_infer, axis=0)
    data_infer = data_infer / 255.0
  
    # 判定処理の実行
    model.load_weights(os.path.join(checkpoint_dir, 'mydnn_weights.hdf5'))
    result = model.predict(data_infer)[0] * 100
 
    # 判定結果の出力
    if result[0] > result[1]:
      print('Cat (%.1f%%)' % result[0])
    else:
      print('Dog (%.1f%%)' % result[1])

判定モードのブロックが実装された他に、import部分が少し追加されていることに注意してください。