機械学習の予測精度を向上させるハイパーパラメータの調整

カバー

[!] この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ハイパーパラメータとは

ハイパーパラメータとは、機械学習において学習パフォーマンスやレイヤーの構成など、トレーニング中に変化しないパラメータのことを指します。
ハイパーパラメータには大きく分けて以下の2種類が存在します。

  • モデルハイパーパラメータ
    • 隠れ層の数と幅など、モデルの構造に影響する。
  • アルゴリズムハイパーパラメータ
    • 確率的勾配降下法の学習率やモーメンタムなど、学習アルゴリズムの速度と性質に影響する。

一般的に、ハイパーパラメータは予め複数の候補を用意しておき、それらの組み合わせを入れ替えて予測や推論を繰り返し、最終的に最も性能の良いハイパーパラメータの組み合わせを採用します。
このようなハイパーパラメータの組み合わせ毎の性能評価を自動化したものをハイパーパラメータチューニング、またはハイパーチューニングと呼びます。
ここでは、KerasTuner APIを使用したハイパーチューニングについて触れていきます。

環境構築

Keras Tunerは、Pythonで動作するので、事前にPythonをインストールしてください。
この記事の開発環境は以下の通りです。

  • OS : Windows 10 Pro
  • Python : 3.9.9

Pythonの仮想環境を作成

Pythonの開発では、パッケージのバージョン違いや依存関係が問題になることがよくあります。
そのため、仮想環境を作成して開発をおこなうことが一般的です。
ここでは、ktprojectという作業フォルダに仮想環境を作成します。
Windows PowerShellを起動し、以下のコマンドを実行して、作業フォルダを作成します。

PS > mkdir ktproject
PS > cd ktproject

続いて、以下のコマンドを実行して、仮想環境を作成および有効化します。

PS > py -3.9 -m venv .venv
PS > .\.venv\Scripts\Activate.ps1

以下のように表示されていれば、仮想環境が有効化されています。

(.venv) PS >

必要なパッケージをインストール

以下のコマンドを実行して、必要なライブラリをインストールします。

(.venv) PS > python -m pip install -U pip
(.venv) PS > pip install tensorflow
(.venv) PS > pip install tensorflow_datasets
(.venv) PS > pip install keras_tuner

これでKeras Tunerを使用する準備は完了です。

データセットについて

ここでは、MNISTデータセットを使用して手書き数字の画像を0~9のいずれかに分類します。
MNISTデータセットには以下のような手書き数字の画像が多数含まれています。

mnist.png

モデルについて

手書き数字の画像を分類するための単純なモデルを構築します。
ここでは、1つの平滑化の入力層、いくつかの全結合の隠れ層、0~9の数字に分類するための全結合の出力層からなるSequentialモデルを使います。

ハイパーチューニングの流れ

まずは、ハイパーチューニングのおおまかな流れを説明していきます。

ハイパーモデルの定義

ハイパーチューニング用にセットアップするモデルをハイパーモデルと呼びます。
ハイパーモデルは、モデルビルダー関数を使用するか、KerasTuner APIのHyperModelクラスをサブクラス化することで定義できます。また、あらかじめ定義されているHyperResNetHyperXceptionを利用することもできます。
ここでは、下記のモデルビルダー関数を使用して、画像分類モデルを定義します。

モデルビルダー関数内で、引数に渡されたHyperParametersインスタンスのIntメソッドやChoiceメソッドなどを呼び出すことでハイパーパラメータを定義します。
この関数が呼び出されると、定義されたハイパーパラメータを使用してモデルをハイパーチューニングし、コンパイル済みのモデルを返します。

def model_builder(hp):
    model = tf.keras.Sequential()

    # 入力層
    model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))

    # 隠れ層
    hp_n_hidden_layers = hp.Int("n_hidden_layers", min_value=1, max_value=5)
    for i in range(hp_n_hidden_layers):
        hp_units = hp.Int("units_%d" % (i + 1), min_value=32, max_value=512, step=32)
        model.add(tf.keras.layers.Dense(hp_units, activation="relu"))

    # 出力層
    model.add(tf.keras.layers.Dense(10, activation="softmax"))

    # 最適化アルゴリズム、損失関数、評価関数を指定してコンパイル
    hp_learning_rate = hp.Choice("learning_rate", values=[1e-2, 1e-3, 1e-4])
    model.compile(
        optimizer=tf.keras.optimizers.Adam(hp_learning_rate),
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"],
    )

    return model

チューナーのインスタンス化

KerasTuner APIには、RandomSearchHyperbandBayesianOptimization、およびSklearnチューナーがあります。
ここでは、以下のようにval_accuracyの収束を目的として指定し、Hyperbandチューナーをインスタンス化します。

tuner = kt.Hyperband(
    hypermodel=model_builder,
    objective="val_accuracy",
    max_epochs=10,
    directory=".cache",
    project_name="kt",
    overwrite=True,
)

ハイパーチューニングの実施

最後に、チューナーを使ってハイパーチューニングを実施します。
searchメソッドの引数は、tf.keras.model.fitに使用される引数と同じです。

tuner.search(
    ds_train,
    epochs=10,
    validation_data=ds_test,
)

実際に動作させてみる

以下のコードをktsample.pyとして保存します。

import tensorflow as tf

# Tensor Flow のログを抑制
tf.get_logger().setLevel("ERROR")

import keras_tuner as kt
import tensorflow_datasets as tfds


def model_builder(hp):
    model = tf.keras.Sequential()

    # 入力層
    model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))

    # 隠れ層
    hp_n_hidden_layers = hp.Int("n_hidden_layers", min_value=1, max_value=5)
    for i in range(hp_n_hidden_layers):
        hp_units = hp.Int("units_%d" % (i + 1), min_value=32, max_value=512, step=32)
        model.add(tf.keras.layers.Dense(hp_units, activation="relu"))

    # 出力層
    model.add(tf.keras.layers.Dense(10, activation="softmax"))

    # 最適化アルゴリズム、損失関数、評価関数を指定してコンパイル
    hp_learning_rate = hp.Choice("learning_rate", values=[1e-2, 1e-3, 1e-4])
    model.compile(
        optimizer=tf.keras.optimizers.Adam(hp_learning_rate),
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"],
    )

    return model


def normalizer(image, label):
    return tf.cast(image, tf.float32) / 255.0, label


def main():
    # データセットをロードする
    (ds_train, ds_test), ds_info = tfds.load(
        "mnist",
        split=["train", "test"],
        as_supervised=True,
        with_info=True,
    )

    # 学習用のパイプラインを作成する
    ds_train = ds_train.map(normalizer, num_parallel_calls=tf.data.AUTOTUNE)
    ds_train = ds_train.cache()
    ds_train = ds_train.shuffle(ds_info.splits["train"].num_examples)
    ds_train = ds_train.batch(128)
    ds_train = ds_train.prefetch(tf.data.AUTOTUNE)

    # 検証用のパイプラインを作成する
    ds_test = ds_test.map(normalizer, num_parallel_calls=tf.data.AUTOTUNE)
    ds_test = ds_test.batch(128)
    ds_test = ds_test.cache()
    ds_test = ds_test.prefetch(tf.data.AUTOTUNE)

    # チューナーをインスタンス化する
    tuner = kt.Hyperband(
        hypermodel=model_builder,
        objective="val_accuracy",
        max_epochs=10,
        directory=".cache",
        project_name="kt",
        overwrite=True,
    )

    # ハイパーパラメータを検索する
    tuner.search(
        ds_train,
        epochs=10,
        validation_data=ds_test,
    )

    # 最も性能が良かったハイパーパラメータを使ってモデルをビルドする
    hp = tuner.get_best_hyperparameters(num_trials=1)[0]
    model = tuner.hypermodel.build(hp)

    # モデルに画像とラベルを学習させる
    model.fit(
        ds_train,
        epochs=6,
        validation_data=ds_test,
    )

    # 学習済みのモデルを保存する
    model.save("model")

    # モデルの構成を表示する
    model.summary()


if __name__ == "__main__":
    main()

以下のコマンドを実行して、ktsample.pyを実行します。

(.venv) PS > python ktsample.py

実行が完了すると、最も性能が良かったモデルがmodelフォルダ配下に保存されます。
保存されたモデルは、以下のようにkeras.models.load_modelメソッドでロードし、再利用する事ができます。

def normalizer(image, label):
    return tf.cast(image, tf.float32) / 255.0, label

(ds_train, ds_test), ds_info = tfds.load(
    "mnist",
    split=["train", "test"],
    as_supervised=True,
    with_info=True,
)

ds_test = ds_test.take(nrows * ncols)
ds_test = ds_test.map(normalizer, num_parallel_calls=tf.data.AUTOTUNE)
ds_test = ds_test.batch(ncols)
ds_test = ds_test.cache()
ds_test = ds_test.prefetch(tf.data.AUTOTUNE)

model = tf.keras.models.load_model('model')

output = model.predict(ds_test)

実際にモデルを再利用し、MNISTデータセットの数字画像を分類した結果は以下の通りです。

result.png

まとめ

今回は、分類モデルのモデルハイパーパラメータ、およびアルゴリズムハイパーパラメータに対してKeras Tunerによるハイパーチューニングを実施するところまでを紹介しました。
Keras Tunerを使えば、コンピュータビジョンで使われるような複雑なKerasモデルやKeras Function APIを使ったモデルなどを簡単にハイパーチューニングすることができます。

ぜひ一度、他のモデルで実践してみてください。


TOP
アルファロゴ 株式会社アルファシステムズは、ITサービス事業を展開しています。このブログでは、技術的な取り組みを紹介しています。X(旧Twitter)で更新通知をしています。