見出し画像

はじめてのKeras 2層Affine構造のAIモデルで回帰を行うPythonソースコードの解説


Kerasの日本語ドキュメント

Kerasの日本語ドキュメントを探していたら、下記を見つけました。

ファイルの拡張子が"md"となっているものを左クリックすると、ドキュメントを参照することができます。

ドキュメントの本体は、sourcesディレクトリ以下にあります。

GitHubは、プログラムのソースコードを管理するものだと思い込んでいましたが、ドキュメントの管理にも使えるとは驚きました。

2層Affine構造のAIモデルで回帰を行うPythonプログラムのソースコード

2層Affine構造のAIモデルで回帰を行うPythonプログラムのソースコードを下記に示します。

import numpy as np
import pandas as pd
import argparse
import time
import matplotlib.pyplot as plt
import os

import keras
from keras.layers import Dense
from keras.callbacks import ModelCheckpoint


# Data format converter
# Label: 'x' or 'y'
# Data: Neural Network Console training/validation data(DataFrame形式)
def DataFormatConv(Label, Data):
    # Labelで指定された文字を含む列を抽出
    OutData = Data.filter(like = Label, axis = 'columns')

    # DataFrameをndarrayに変換
    OutData = OutData.to_numpy()

    return OutData


def main():
    # 下記のエラー対応
    # OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5 already initialized.
    os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"


    # コマンドライン引数の処理
    parser = argparse.ArgumentParser(description = '2 Affine neural network training and validation program')

    parser.add_argument('--e', type = int, default = 10, help = 'Number of Epoch(Default: 10)')
    parser.add_argument('--b', type = int, default = 64, help = 'Batch size(Default: 64)')
    parser.add_argument('--t', required = True, default = 'training.csv', help = 'Training data file name(Default: training.csv)')
    parser.add_argument('--v', required = True, default = 'validation.csv', help = 'Validation data file name(Default: validation.csv)')
    parser.add_argument('--m', default = 'Best_model.h5', help = 'Minimum val_loss model name(Default: Best_model.h5)')
    parser.add_argument('--o', default = 'Result_model_validation.csv', help = 'File name for best model evaluation results(Default: Result_model_validation.csv)')

    args = parser.parse_args()

    print('Training data: ', args.t)
    print('Validation data: ', args.v)

    # csvファイルのデータをDataFrameに入力
    TrainData = pd.read_csv(args.t, encoding = 'utf-8')
    ValidData = pd.read_csv(args.v, encoding = 'utf-8')


    # 学習データをKeras用に成形
    TrainDataX = DataFormatConv('x', TrainData)
    TrainDataY = DataFormatConv('y', TrainData)


    # 評価データをKeras用に成形
    ValidDataX = DataFormatConv('x', ValidData)
    ValidDataY = DataFormatConv('y', ValidData)


    # 2層Affine構造のニューラルネットワークを構築
    TestNN = keras.models.Sequential()
    TestNN.add(Dense(100, input_dim = 4, activation = 'relu')) # 入力層(4) + Affine_1(100) + ReLU_1
    TestNN.add(Dense(4, activation = 'linear')) # Affine_2(4)
    TestNN.summary()


    # 学習プロセスの設定
    TestNN.compile(loss = 'mean_squared_error', optimizer = 'adam', metrics = ['mae']) # 損失関数


    # 学習時間の計測開始
    FitTimeStart = time.perf_counter()


    # コールバックの設定
    CheckPointPath = args.m
    CallBack = ModelCheckpoint(filepath = CheckPointPath, monitor = 'val_loss', verbose = 1, save_best_only = True, mode = 'min', save_weights_only = False, save_freq = 'epoch')


    # AIモデルの学習
    Epochs = args.e
    BatchSize = args.b
    History = TestNN.fit(x = TrainDataX, y = TrainDataY, batch_size = BatchSize, epochs = Epochs, validation_data = (ValidDataX, ValidDataY), shuffle = True, callbacks = [CallBack])


    # 学習時間の計測終了
    FitTimeEnd = time.perf_counter()


    # 学習時間
    print()
    print('学習時間: ', '{:.2f}'.format(FitTimeEnd - FitTimeStart), '[s]')
    print()


    # 保存されたHDF5形式の最小val_lossモデルを読み込み
    ValidModel = keras.models.load_model(CheckPointPath)


    # 最小val_lossモデルを評価
    Result = ValidModel(ValidDataX)


    # EagerTensorをDataFrame形式に変換
    TmpResult = pd.DataFrame(Result)


    # 最小val_lossモデルの評価結果をファイルに保存
    TmpResult.to_csv(args.o, index = False)
    print('Validation results: ', args.o)


    # 損失をグラフ表示
    plt.plot(range(1, Epochs + 1), History.history['loss'], label = 'Loss')
    plt.plot(range(1, Epochs + 1), History.history['val_loss'], label = 'Val Los')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.yscale('log')
    plt.ylim(None, 10**6)
    plt.grid(axis = 'x', which = 'major')
    plt.grid(axis = 'y', which = 'both')
    plt.show()


if __name__ == '__main__':
    main()

上記のPythonプログラムにおいて、主な構成は下記の通りです。

  • Pythonプログラムの主な構成

    • ライブラリのインポート

    • DataFormatConv関数

      • Neural Network Console用の学習データおよび評価データをKerasを使用したAIモデル向けのデータフォーマットに変換

    • main関数

      • Pythonのエラー対応

      • Pythonプログラム実行時の引数処理

      • 学習データおよび評価データの用意

      • 2層Affine構造のAIモデルの構築

      • 学習時間の計測準備

      • コールバック関数の設定

      • AIモデルの学習処理

      • 学習時間の計測

      • 最適なAIモデルのパラメータの読み込み

      • 最適なAIモデルの評価

      • 評価データのファイル出力

      • 各種エラーのグラフ表示

Pythonプログラムの実行方法

上記のPythonプログラムをfilename.pyというファイルに保存した場合、実行方法は下記となります。

> python filename.py --t training.csv --v validation.csv

上記において、training.csvはNeural Network Console用の学習データを、validation.csvはNeural Network Console用の評価データを指定します。

また、Pythonプログラム実行時のオプション一覧は、下記となります。

  • Pythonプログラム実行時のオプション一覧

    • --e: Epochを指定(デフォルト値: 10)

    • --b: バッチサイズを指定(デフォルト値: 64)

    • --t: 学習データを指定(指定必須のオプション)

    • --v: 評価データを指定(指定必須のオプション)

    • --m: 最適モデル保存ファイル名(デフォルト値: Best_model.h5)

    • --o: 最適モデルの評価結果保存ファイル名(デフォルト値: Result_model_validation.csv)

Pythonプログラムの詳細解説

上記の2層Affine構造のAIモデルで回帰を行うPythonプログラムにおいて、main関数内のポイントとなりそうな箇所を解説します。

学習データおよび評価データの用意

# csvファイルのデータをDataFrameに入力
TrainData = pd.read_csv(args.t, encoding = 'utf-8')
ValidData = pd.read_csv(args.v, encoding = 'utf-8')

# 学習データをKeras用に成形
TrainDataX = DataFormatConv('x', TrainData)
TrainDataY = DataFormatConv('y', TrainData)

Neural Network Console用の学習データおよび評価データを保存したファイルからそれぞれのデータを読み込み、Kerasを使用したAIモデル用のデータフォーマットに変換しています。

2層Affine構造のAIモデルの構築

# 2層Affine構造のニューラルネットワークを構築
TestNN = keras.models.Sequential()
TestNN.add(Dense(100, input_dim = 4, activation = 'relu')) # 入力層(4) + Affine_1(100) + ReLU_1
TestNN.add(Dense(4, activation = 'linear')) # Affine_2(4)
TestNN.summary()


# 学習プロセスの設定
TestNN.compile(loss = 'mean_squared_error', optimizer = 'adam', metrics = ['mae']) # 損失関数

上記の記述により、Neural Network Consoleでの下記の構造のAIモデルを構築しています。

2層Affine構造 AIモデル
2層Affine構造のAIモデル

今回は、Kerasのシーケンシャルモデルと呼ばれるものを使用しています。

下記のソースコードがシーケンシャルモデルの変数を作成している箇所です。

TestNN = keras.models.Sequential()

Kerasのシーケンシャルモデルは、必要なAIモデルのレイヤ(層)をaddにより追加することで、AIモデルを構築します。

上記のソースコードでは、Dense(Affine)を2つaddしています。

1つ目のDense(Affine_1に相当)では、活性化関数としてReLUをactivationで指定しています。

また、2つ目のDense(Affine_2に相当)では、活性化関数を使用しないのでactivation = 'linear'としています。

Neural Network ConsoleでのSquaredErrorは、Kerasではcompileの引数であるlossで指定します。

上記の例では、loss = 'mean_squared_error'としています。

また、optimizer = 'adam'は、AIモデルの学習時に使用される最適化アルゴリズムにAdaptive Moment Estimation(ADAM, 適応的モーメント推定)を指定しています。

ADAMの詳細については分かりませんが、Neural Network ConsoleでもADAMを最適化アルゴリズムに使用しています。

そして、metrics = ['mae']ですが、学習したAIモデルの評価に使用する精度指標(Metrics)としてMean Absolute Error(MAE, 平均絶対誤差)を指定しています。

これについては、回帰を行う場合は、この設定にするのが良いそうです。

summaryは、Python実行時に下記のAIモデルの構造に関する情報を出力する関数です。

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #
=================================================================
 dense (Dense)               (None, 100)               500

 dense_1 (Dense)             (None, 4)                 404

=================================================================
Total params: 904
Trainable params: 904
Non-trainable params: 0

従って、summaryは無くても動作に影響はありません。

コールバック関数の設定

コールバック関数とは、別の関数の実行中に、予め設定された条件が成立した場合に実行される関数です。

CallBack = ModelCheckpoint(filepath = CheckPointPath, monitor = 'val_loss', verbose = 1, save_best_only = True, mode = 'min', save_weights_only = False, save_freq = 'epoch')

今回、コールバック関数を設定した目的は、AIモデルの学習中において、評価データを使用した場合の誤差が最小となる(つまり、最も性能の良い)AIモデルの内部パラメータを保存することです。

このAIモデルの内部パラメータは、後で呼び出して評価を行います。

コールバック関数で設定された各引数の意味は、以下の通りです。

  • filepath = CheckPointPath

    • AIモデルの内部パラメータを保存するファイルを指定します

  • monitor = 'val_loss'

    • 監視する変数を指定します

    • 今回は、評価データを使用した場合の誤差が最小となる条件を判定するためval_loss(評価データに対する誤差)を指定しています

  • verbose = 1

    • AIモデルの学習時に下記のログを出力します

    • Epoch ?: val_loss improved from ? to ?, saving model to ?

  • save_best_only = True

    • val_lossの値が最も小さい場合のAIモデルの内部パラメータを保存します

  • mode = 'min'

    • save_best_only = True かつ monitor = 'val_loss' の場合はminを設定するようです

  • save_weights_only = False

    • 条件成立時はAIモデル全体(内部パラメータ含む)が保存されます

  • save_freq = 'epoch'

    • 各Epoch毎に評価されます

ちなみに、上記に挙げたKerasの日本語ドキュメントでは、save_freqではなくperiodと記載されています。

しかし、periodを指定するとWarningが出力されますので、注意が必要です。

AIモデルの学習処理

History = TestNN.fit(x = TrainDataX, y = TrainDataY, batch_size = BatchSize, epochs = Epochs, validation_data = (ValidDataX, ValidDataY), shuffle = True, callbacks = [CallBack])

fitの実行でAIモデルの学習を行います。

各引数の意味は、次の通りです。

  • x = TrainDataX

    • xには学習データを代入します

  • y = TrainDataY

    • yには学習データに対する教師データを代入します

  • batch_size = BatchSize

    • AIモデルの学習に使用するバッチサイズを指定します

  • epochs = Epochs

    • Epoch数を指定します

  • validation_data = (ValidDataX, ValidDataY)

    • AIモデルの評価に使用する評価データと評価データに対する教師データを指定します

  • shuffle = True

    • 学習データのシャッフルを有効にします

  • callbacks = [CallBack]

    • 事前に設定したコールバック関数を代入します

AIモデルの学習中は、コールバック関数で指定した通り、評価データに対する教師データと比べて誤差が最小となるAIモデルと内部パラメータを保存します。

最適なAIモデルのパラメータの読み込み

# 保存されたHDF5形式の最小val_lossモデルを読み込み
ValidModel = keras.models.load_model(CheckPointPath)

AIモデルの学習中に保存された評価データに対する教師データと比べて誤差が最小となったAIモデルと内部パラメータを読み込みます。

最適なAIモデルの評価

# 最小val_lossモデルを評価
Result = ValidModel(ValidDataX)

評価データに対する教師データと比べて誤差が最小となったAIモデルの再評価を行います。

評価データは、変数Resultに代入されます。

評価データのファイル出力

# EagerTensorをDataFrame形式に変換
TmpResult = pd.DataFrame(Result)


# 最小val_lossモデルの評価結果をファイルに保存
TmpResult.to_csv(args.o, index = False)

AIモデルの評価データをcsvファイルに出力するため、一旦、DataFrame形式に変換した後、ファイルに出力します。

この評価データを使ってまとめた記事が、下記となります。

おまけ バッチサイズとEpochについて

AIモデルの学習方法にミニバッチ学習というものがあります。

ミニバッチ学習は、用意した学習データの一部を抜粋し、その抜粋した学習データを使用してAIモデルの学習を行う方法です。

例えば、学習データが30個、バッチサイズが10個である場合、ミニバッチ学習は下記のように実行されます。

  • 学習データが30個、バッチサイズが10個である場合のミニバッチ学習

    • 学習1回目: 学習データから10個を抜粋し、AIモデルの学習を実行

    • 学習2回目: 残る20個の学習データから10個を抜粋し、AIモデルの学習を実行

    • 学習3回目: 残る10個の学習データを使用し、AIモデルの学習を実行

上記の3回目が終了した時点で、1 Epochとなります。

Neural Network Consoleおよび今回作成したKerasを使用したAIモデルの学習は、ミニバッチ学習を使用しています。

ちなみに、学習データの個数がバッチサイズで割り切れない場合の動作については、良く分かりません。

この記事が気に入ったらサポートをしてみませんか?