前回、サンプルを元に適当にハイパーパラメーターを設定した。
今回は Optuna | 株式会社Preferred Networks を使って、いくつかのハイパーパラメーターの組み合わせを試して、一番良かった結果を報告してくれるやつを試す。
環境構築
前回 の環境に optuna
を追加。
ゼロから構築する場合には、以下コマンド群を叩く。
apt-get update
apt-get install -y python3-dev python3-pip python3-venv
python3 -m venv --system-site-packages ./tensorflow
source ./tensorflow/bin/activate
pip install --upgrade pip
pip install --upgrade optuna
pip install --upgrade keras
pip install --upgrade tensorflow
プログラム作成
ざっくり手順は以下の感じ。
- パラメーター候補の組み合わせを試して、学習結果の評価を返却する関数
- 以下コードの
objective
がその関数
- 以下コードの
optuna#create_study
で Study オブジェクトを作るStudy#optimize
に「1.」で作成した関数を渡す- Study クラスのオブジェクトが、「1.」で指定された組み合わせを色々試して、「試したパラメーターの組み合わせとその評価結果」を記録してくれる
- 「3.」の結果から、一番評価の良かったモデルを特定して、そのモデルで分類を行う
from keras.layers import Dense, Dropout, Activation
from keras.models import Sequential
from keras.optimizers import SGD, Adam
from keras.utils import np_utils
from sklearn import datasets
from sklearn.model_selection import train_test_split
from tensorflow import keras
import numpy as np
import optuna
import tensorflow as tf
# パラメーター候補の組み合わせを試して、学習結果の評価を返却する関数
def objective(trial):
# dropout_rate を 0.25 から 0.5 の間で試す
dropout_rate = trial.suggest_uniform('dropout_rate', 0.0, 0.5)
# 試す損失関数の種類を列挙。今回は `categorical_crossentropy` のみ。
loss = trial.suggest_categorical('loss', ['categorical_crossentropy'])
# 試す最適化の種類を列挙。今回は `sgd` と `adam` を試す。
optimizer = trial.suggest_categorical('optimizer', ['sgd', 'adam'])
# 試す活性化関数の種類を列挙。今回は `tanh` と `relu` を試す。
activation = trial.suggest_categorical('activation', ['tanh', 'relu'])
# 試す metrics の種類を列挙。今回は `accuracy` のみ。
metrics = trial.suggest_categorical('metrics', ['accuracy'])
# 試すレイヤー数を指定。 1 から 5 層を試す。
n_layer = trial.suggest_int('n_layer', 1, 5)
# Sequential モデル生成
model = Sequential()
# 入力パラメーターが以下 4 つなので input_dim=4
# - sepal length: がくの長さ
# - sepal width: がくの幅
# - petal length: 花弁の長さ
# - petal width: 花弁の幅
input_dim=4
# 出力は以下 3 種なので units=3
# - 0: Iris-Setosa(セトナ)
# - 1: Iris-Versicolour(バーシクル)
# - 2: Iris-Virginica(バージニカ)
units=3
# 入力層
model.add(Dense(input_dim))
# 隠れ層
# dropout_rate が一様というのはダメな気がするがとりあえず optuna の使い方の練習ということで。
for i in range(n_layer):
model.add(Dense(units, activation=activation))
model.add(Dropout(dropout_rate))
# 出力層
model.add(Activation('softmax'))
# モデルのコンパイル
model.compile(loss=loss, optimizer=optimizer, metrics=metrics)
# 学習
history = model.fit(train_x, train_t, batch_size=32, epochs=1000)
# モデルの保存
model.save("./trials/{}.model".format(trial.number))
# 学習結果の評価を返却
return 1 - history.history[metrics][-1]
## データ準備
# 乱数を固定値で初期化し再現性を持たせる
np.random.seed(0)
# pip パッケージ scikit-learn の datasets から、 iris データをロード
# X: インプットデータ
# T: 正解データ
iris = datasets.load_iris()
X = iris.data
T = iris.target
# 数値を、位置に変換 [0,1,2] ==> [ [1,0,0],[0,1,0],[0,0,1] ]
T = np_utils.to_categorical(T)
# データを訓練用とテスト用に分割
train_x, test_x, train_t, test_t = train_test_split(X, T, train_size=0.8, test_size=0.2)
# パラメーター最適化。 `n_traials` の数だけ試す。
study = optuna.create_study()
study.optimize(objective, n_trials=100)
# 最適化結果表示
print("study.best_trial: {}".format(study.best_trial))
print("study.best_params: {}".format(study.best_params))
#print("study.best_trials: {}".format(study.best_trials))
#print("study.best_value: {}".format(study.best_value))
#print("study.trials: {}".format(study.trials))
# 一番成績の良かったモデルをロード
model = keras.models.load_model("./trials/{}.model".format(study.best_trial.number))
# 学習済みモデルでテストデータを分類する
Y = np.argmax(model.predict(test_x), axis=-1)
## 結果検証確認
# to_categorical の逆変換
_, T_index = np.where(test_t > 0)
# 結果出力
print()
print('RESULT')
print(Y == T_index)
実行結果省略、以上。