[Python] AI 13 Chainerによる動物認識学習モデル 読み込みと実行

[macOS Catalina 10.15.7]

pyenvのPython3.5環境でコードを走らせています。Dockerを使う手もありますが、個人開発者にはメリットが薄いのと時間的学習コストが掛かりそうなので今回は見送りです。

この種のモデルでGPUを使う場合はCUDA(CuPy)をそれ用に設定するのですが、NVIDIAによるサポートはmacOS High Sierra 10.13で終了しています。 したがってMojave 10.14以降ではGPUなしの設定のみ可能になるようです。

学習してモデルを保存するところは先を急ぐため省略します。

前回までの手書き数字認識学習モデルでは新しいChainer(7.8.0)でも問題なかったものの、このモデルでは5.0.0にダウングレードしないと動きませんでした。

また教本にはh5ファイルの保存方法について説明がありましたが、読み込み方法の説明は抜けていました。さらに調べる際、Kerasの学習ファイルと混同してしまったため、解決するのに時間が掛かりました

この教本にはpipでインストールしたライブラリのバージョンがほとんど載っていません。正に鮮度が命といった感じです。ネット記事でもそうですが、pip listも合わせて載せていただきたいものです。

chainer (5.0.0)
Keras (2.2.4)
Keras-Applications (1.0.8)
Keras-Preprocessing (1.1.2)
matplotlib (3.0.3)
numpy (1.18.5)
opencv-python (4.4.0.42)
Pillow (7.2.0)
pip (9.0.1)
PyQt5 (5.15.2)
PyQt5-sip (12.9.0)
tensorboard (1.15.0)
tensorflow (1.15.0)
tensorflow-estimator (1.15.1)
from PIL import Image
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
from chainer import serializers,Chain
from chainer.cuda import to_cpu

INPUT_WIDTH = 128
INPUT_HEIGHT = 128

def data_reshape(width_height_channel_image):
    image_array = np.array(width_height_channel_image)
    return image_array.transpose(2, 0, 1)

def convert_test_data(image_file_path, size, show=False):
    
    image = Image.open(image_file_path)

    # 共通の画像のリサイズ
    result_image = image.resize((INPUT_WIDTH, INPUT_HEIGHT), Image.LANCZOS)

    # 画像データの再形成
    image = data_reshape(result_image)

    # 型をfloat32に変換
    result = image.astype(np.float32)
    result = model.xp.asarray(result)

    # モデルに渡すデータフォーマットに変換
    result = result[None, ...]

    return result

class CNN(Chain):
  def __init__(self):
    super(CNN, self).__init__()

    with self.init_scope():
      self.conv1 = L.Convolution2D(None, out_channels=32, ksize=3, stride=1, pad=1)
      self.conv2 = L.Convolution2D(in_channels=32, out_channels=64, ksize=3, stride=1, pad=1)
      self.conv3 = L.Convolution2D(in_channels=64, out_channels=128, ksize=3, stride=1, pad=1)
      self.conv4 = L.Convolution2D(in_channels=128, out_channels=256, ksize=3, stride=1, pad=1)
      self.layer1 = L.Linear(None, 1000)
      self.layer2 = L.Linear(1000, 2)
  
  def __call__(self, input):
    func = F.max_pooling_2d(F.relu(self.conv1(input)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv2(func)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv3(func)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv4(func)), ksize=2, stride=2)
    func = F.dropout(F.relu(self.layer1(func)), ratio=0.80)
    func = self.layer2(func)
    return func

if __name__ == '__main__':
    model = L.Classifier(CNN())
    serializers.load_hdf5("chainer-dogscats-model.h5", model)
    
    image_path = '1.jpg'
    Image.open(image_path)

    # 学習時と同じ画像のサイズに変換
    test_data= convert_test_data(test_image_url, (INPUT_WIDTH, INPUT_HEIGHT))

    with chainer.using_config('train', False), chainer.using_config(
                'enable_backprop', False):
        test_teacher_labels = model.predictor(test_data)
        test_teacher_labels = to_cpu(test_teacher_labels.array)
        test_teacher_label = test_teacher_labels.argmax(axis=1)[0]
        if test_teacher_label == 0:
            retval = '猫'
        else:
            retval = '犬'

    print(retval)