Python Keras使い方,サンプル解説:画像認識(機械学習)サーバーに使用するAIモデルを作成【ディープラーニング,ラズパイ】

ソケット通信と画像認識AIを組み合わせ、ネットワークを介して画像送付→認識結果取得を行うシステムを紹介しました。

https://nine-num-98.blogspot.com/2020/03/ai-socket-01.html

公開したプログラムの内容について解説します。


GitHub公開プログラム
https://github.com/kotetsu99/cnn_socket

↑のGitHub上で公開しているプログラムですが、主に3つのプログラムが存在します。

(1)01-cnn_train.py: 画像学習プログラム
・画像をAIに学習させ、画像認識AIモデルを生成。
・AIモデルは、CIFAR-10 画像データセット向けのAIモデル(9層畳み込みネットワーク)

(2)02-cnn_server.py: 画像認識AIソケットサーバー
・ソケット通信サーバー。(3)のクライアントから画像ファイルを受信し保存。
・受信した画像ファイルに対し、(1)で作ったAIで画像認識させ、結果をクライアントに返す。

(3)03-socket_client.py: 画像送信ソケットクライアント
・ソケット通信クライアント。画像ファイルを(2)のサーバーにバイナリデータで送信。
・サーバーの画像認識結果を受信して、コンソール画面に表示。


これらの動きをシーケンス図でラフに書くと以下のようになります。





かなり大雑把ですが、これで大体のシステム全体像をつかんでもらったうえで、以降の解説を読んでもらえればと思います。

ボリュームが多いため、(1)のAI部と(2)(3)のソケット通信部とに記事を分けて解説したいと思います。今回は、(1)のサンプルコードについて解説します。

※(2)(3)については、以下の記事で解説しています。
https://nine-num-98.blogspot.com/2020/03/ai-socket-03.html

画像学習プログラム


01-cnn_train.py は画像データセットをAIに学習させ、画像認識AIモデルを生成するプログラムです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import keras
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential, Model
from keras.layers import Input, Dense, Dropout, Flatten, Conv2D, MaxPooling2D, Activation
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import os
import sys
import time


# 画像リサイズ定義
img_width, img_height = 64, 107

# バッチサイズ
batch_size = 8
# エポック数(1エポックの画像サンプル数 = ステップ数 * バッチサイズ)
nb_epoch = 200

# 収束判定ループ(エポック)回数
nb_patience = 20
#nb_patience = nb_epoch
# 収束判定用差分パラメータ
# トレーニング用とバリデーション用の画像格納先
train_data_dir = 'dataset/train'
validation_data_dir = 'dataset/validation'

AI学習に関する各設定を行っています。ハイパーパラメータ関連については、これまで紹介したプログラムと大体同じです。本プログラムでは、画像データセットを、学習(トレーニング)に使うものと検証(バリデーション)に使うものとで分けて使用します。

両データセットの違いですが、これは後の処理に出てくるAIモデル学習への使われ方にあります。モデル学習では、エポックごとにまずトレーニング用画像で学習させたあと、バリデーション用画像でモデルの出来(損失関数値、予測精度)を確認するという処理が行われます。

main関数を見ていきます。

def main():

    # 環境設定(ディスプレイの出力先をlocalhostにする)
    os.environ['DISPLAY'] = ':0'

    # 時間計測開始
    start = time.time()

    # データセットのサブディレクトリ名(クラス名)を取得
    classes = []
    for d in os.listdir(train_data_dir):
        if os.path.isdir(os.path.join(train_data_dir, d)):
            classes.append(d)
    nb_classes = len(classes)
    print 'クラス名リスト = ', classes

    # 画像ファイルの確認
    if not len(sys.argv)==2:
        print('使用法: python 01-cnn_train.py モデルファイル名.h5')
        sys.exit()
    savefile = sys.argv[1]

    # モデル作成(既存モデルがある場合は読み込んで再学習。なければ新規作成)
    if os.path.exists(savefile):
        print('モデル再学習')
        cnn_model = keras.models.load_model(savefile)
    else:
        print('モデル新規作成')
        cnn_model = cnn_model_maker(nb_classes)
        # 多クラス分類を指定
        cnn_model.compile(loss='categorical_crossentropy',
                  optimizer=keras.optimizers.Adam(),
                  metrics=['accuracy'])

    # 画像のジェネレータ生成
    train_generator, validation_generator = image_generator(classes)
    print('trgen_len(train_steps)=', len(train_generator))
    print('vagen_len(val_steps)=', len(validation_generator))

    # 収束判定設定。以下の条件を満たすエポックがpatience回続いたら打切り。
    # val_loss(観測上最小値) - min_delta  < val_loss
    es_cb = keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=val_min_delta, patience=nb_patience, verbose=1, mode='min')

    # CNN学習
    history = cnn_model.fit_generator(
        train_generator,
        epochs=nb_epoch,
        validation_data=validation_generator,
        callbacks=[es_cb])

    # 学習モデル保存
    cnn_model.save(savefile)

    # 学習所要時間の計算、表示
    process_time = (time.time() - start) / 60
    print('process_time = ', process_time, '[min]')

    # 損失関数の時系列変化をグラフ表示
    plot_loss(history)

画像データセットを指定クラスに分類する、分類問題型AIを学習させ作り上げます。本プログラムのメイン処理です。

留意すべきポイントについて、コメント箇所を引用しながら説明を記します。(行指定がわかりやすいのかもしれませんが、今後ソース修正の可能性もあり、その度に行番号がずれてしまうと、記事の修正もややこしくなるため。)

# データセットのサブディレクトリ名(クラス名)を取得
dataset/train 配下にあるサブディレクトリ名をクラスとみなし、登録する処理です。
ディレクトリ以外のもの(ファイル)などは無視するように工夫を入れています。

# モデル作成(既存モデルがある場合は読み込んで再学習。なければ新規作成)
コメント通りの処理をここで行っていますが、作成するモデルファイル名は実行コマンド「python 01-cnn_train.py ○○○」の最後で指定されています。このファイルが既にあれば、ロードして以降の処理で再学習。なければ新規のモデルファイルとして作成します。新規作成する場合は、ニューラルネットワークモデル構成を以下の関数を呼び出して定義します。
cnn_model_maker(nb_classes)

# 多クラス分類を指定
作成する多クラス分類AIモデルの学習方法に関する定義を行っています。
・損失関数: クロスエントロピー関数
・最適化アルゴリズム: Adam
・評価指標: 画像認識の正解率

# 画像のジェネレータ生成
後の image_generator(classes) 関数を呼び出して、画像データセットを生成するジェネレータを定義しています。

# CNN学習
Kersで提供されている fit_generator関数を用いて、画像認識AI(CNN: 畳み込みニューラルネットワーク)を学習させています。先述の画像ジェネレータを学習の入力データとする場合は、本関数を使用する必要があります。


続いて、main関数内で呼び出しているサブルーチンについて見ていきます。

まず、ニューラルネットワーク構成の定義を行う関数です。

def cnn_model_maker(nb_classes):

    # 入力画像ベクトル定義(RGB画像認識のため、チャネル数=3)
    input_shape = (img_width, img_height, 3)

    # CNNモデル定義(Keras CIFAR-10: 9層ニューラルネットワーク)
    model = Sequential()
    model.add(Conv2D(32, (3, 3), padding='same',
                     input_shape=input_shape))
    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(nb_classes))
    model.add(Activation('softmax'))

    return model

CIFAR-10 画像データセット向けのAIモデル(9層畳み込みネットワーク)の構成で定義しています。
https://keras.io/examples/cifar10_cnn/

多クラス分類であるため、最後方にある出力ニューロンはクラス数の数だけ存在します。活性化関数にはソフトマックス関数を選択しています。

上記で挙げたKerasによるデータ生成、ディープラーニング実装は、以下の書籍が参考になります。


必要な数学だけでわかる ディープラーニングの理論と実装
秀和システム (2019-06-05)
売り上げランキング: 169,082


続いて、画像データジェネレータを定義する関数です。

def image_generator(classes):
    # トレーニング画像データ生成準備
    train_datagen = ImageDataGenerator(
        rescale=1.0 / 255,
        zoom_range=0.2,
        horizontal_flip=False)

    # バリデーション画像データ生成準備
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)

    # ディレクトリ内のトレーニング画像読み込み、データ作成
    train_generator = train_datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        color_mode='rgb',
        classes=classes,
        class_mode='categorical',
        batch_size=batch_size,
        shuffle=True)

    # ディレクトリ内のバリデーション画像読み込み、データ作成
    validation_generator = validation_datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        color_mode='rgb',
        classes=classes,
        class_mode='categorical',
        batch_size=batch_size,
        shuffle=True)

    return (train_generator, validation_generator)

以前に紹介した画像認識AIプログラムにもあった同名の関数とよく似ていますが、トレーニング画像ジェネレータ(train_generator)と、バリデーション画像ジェネレータ(validation_generator)で、別々のディレクトリを指定している点が異なります。

なお以前のプログラムは、トレーニング/バリデーションともに同一のディレクトリを読み込んでデータ生成を行い、9割をトレーニング用、残り1割をバリデーション用としていました。


以上、(1)01-cnn_train.py: 画像学習プログラムの解説でした。

ソケット通信のプログラム
(2)02-cnn_server.py: 画像認識AIソケットサーバー
(3)03-socket_client.py: 画像送信ソケットクライアント

については、以下の記事で解説しています。

https://nine-num-98.blogspot.com/2020/03/ai-socket-03.html

スポンサーリンク