はじめに
Google Colaboratory上でCNNを使って画像認識を試しています。
ディープラーニングではハイパーパラメータの設定値によって学習結果がかなり異なる結果になることがあります。ハイパーパラメータの最適化を行うことができるoptunaを使っていろいろと試行錯誤してみましたので、その備忘録として記録を残したいと思います。
optunaについて
まず、optunaについておさらいします。
optunaとはPrefferdNetworks社が作成したディープラーニングの学習で使用するハイパーパラメータを最適化するフレームワークのことです。optunaを使ってハイパーパラメータの最適化を実施するためには、公式サイトに記載されているようにoptuna.create_study()で学習を開始し、optimize()で最適化を実施します。
これを実施することにより最適なハイパーパラメータを算出することができます。
trial.suggest_discrete_uniform() APIについて
まず、全結合層のユニット数を設定するため、以下のような設定としました。
def objective(trial):
mid_units = int(trial.suggest_discrete_uniform("mid_units", 128, 512, 128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
このコードで実行すると以下のようなWarningが発生しました。
FutureWarning: suggest_discrete_uniform has been deprecated in v3.0.0. This feature will be removed in v6.0.0. See https://github.com/optuna/optuna/releases/tag/v3.0.0. Use suggest_float(..., step=...) instead.
suggest_discrete_uniform() APIは、v3.0.0で非推奨となり、v6.0.0で削除されるとのこと。代わりにsuggest_float() APIを使ってくれ~と記載されていますね。
私が使用している環境のoptunaはv4.1.0でしたので、上記のWarningが出力されたということですね。Warningの指摘通り、suggest_float() APIを使うようにします。
trial.suggest_float() APIについて
suggest_discrete_uniform() APIではなくsuggest_float() APIを使ってくれ~とのことでしたので、単純に置き換えます。
公式Webでは、suggest_float() APIは以下のように説明されています。
suggest_float(name, low, high, *[, step, log])
lowからhighまでの小数点の値から任意の値を提案するためのAPIのようですね。オプションとしてstepで値の間隔を指定できるのだろうと思います。
128~512の範囲を128間隔で指定したかったので、以下のように記述してみました。
def objective(trial):
mid_units = int(trial.suggest_float("mid_units", 128, 512, 128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
このコードで実行すると以下のようなErrorが発生しました。
TypeError: Trial.suggest_float() takes 4 positional arguments but 5 were given
引数の数が異なっている??
いろいろと試行錯誤したところ、正しくは以下のようにstep=で数値の指定が必要なようです。
def objective(trial):
mid_units = int(trial.suggest_float("mid_units", 128, 512, step=128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
Sequentialモデルについて
Sequentialモデルを使ってCNNのモデルを以下のように作成しました。
IMG_HEIGHT = 100
IMG_WIDTH = 100
def create_model(mid_units):
model = models.Sequential()
model.add(keras.layers.Conv2D(filters=32, kernel_size=3,
activation="relu", padding="same", input_shape=(IMG_HEIGHT, IMG_WIDTH ,3)))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=64, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=128, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(mid_units))
model.add(keras.layers.Dense(2, activation="softmax"))
return model
def objective(trial):
mid_units = int(trial.suggest_float("mid_units", 128, 512, step=128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
これを実行すると、以下のようなWariningが発生しました。
UserWarning: Do not pass an input_shape
/input_dim
argument to a layer. When using Sequential models, prefer using an Input(shape)
object as the first layer in the model instead.
Sequentialモデルの場合は、最初のレイヤとしてConv2Dをいきなり配置するのではなくInputレイヤを配置してくれ~ということのようです。
そこで以下のように最初のレイヤとしてInputLayerを追加しました。
IMG_HEIGHT = 100
IMG_WIDTH = 100
def create_model(mid_units):
model = models.Sequential()
model.add(keras.layers.InputLayer(input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)))
model.add(keras.layers.Conv2D(filters=32, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=64, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=128, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(mid_units))
model.add(keras.layers.Dense(2, activation="softmax"))
return model
def objective(trial):
mid_units = int(trial.suggest_float("mid_units", 128, 512, step=128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
これを実行すると、以下のようなWariningが発生しました。
UserWarning: Argument input_shape
is deprecated. Use shape
instead.
どうもInputLayerではinput_shapeは非推奨のようですね。
以下のように設定することでWarningは解消しました。
IMG_HEIGHT = 100
IMG_WIDTH = 100
def create_model(mid_units):
model = models.Sequential()
model.add(keras.layers.InputLayer(shape=(IMG_HEIGHT, IMG_WIDTH, 3)))
model.add(keras.layers.Conv2D(filters=32, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=64, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Conv2D(filters=128, kernel_size=3,
activation="relu", padding="same"))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2), padding="same"))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(mid_units))
model.add(keras.layers.Dense(2, activation="softmax"))
return model
def objective(trial):
mid_units = int(trial.suggest_float("mid_units", 128, 512, step=128))
model = create_model(mid_units)
study.optimize(objective, n_trials=20)
おわりに
今回はoptuna実施時に発生したWarningやErrorについて備忘録として残しました。
optunaを使ってハイパーパラメータの最適化を実施していきたいと思います。