6章 最後に、ハイパーパラメータ(hyper-parameter)の検証について。
ハイパーパラメータは人為的に試行錯誤しながら調整がするので検証が必要である。
しかし、汎化性能を評価するには、最終的に評価するための本番のテストデータが使えない。
そこで、ハイパーパラメータ専用の検証データvalidation dataを訓練データから分離して検証が必要。
次にハイパーパラメータの最適化は以下の手順で行う。
ステップ0:ハイパーパラメータの範囲を10^-3から10^3などの範囲でざっくり指定する ↓ ステップ1:設定された範囲からランダムにサンプリングする ↓ ステップ2:サンプリングされた値で学習し、検証データで認識精度を評価する。ただしエポックは小さく設定しておく。 ↓ ステップ3:ステップ1−2を一定回数(100回など)繰り返し、さらにハイパーパラメータの範囲を狭めていく
以下、ハイパーパラメータの最適化をしていくサンプルコード
# coding: utf-8 import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np import matplotlib.pyplot as plt plt.switch_backend('agg') from dataset.mnist import load_mnist from common.multi_layer_net import MultiLayerNet from common.util import shuffle_dataset from common.trainer import Trainer (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) # 高速化のため訓練データの削減 x_train = x_train[:500] t_train = t_train[:500] # 検証データの分離 validation_rate = 0.20 validation_num = x_train.shape[0] * validation_rate x_train, t_train = shuffle_dataset(x_train, t_train) x_val = x_train[:validation_num] t_val = t_train[:validation_num] x_train = x_train[validation_num:] t_train = t_train[validation_num:] def __train(lr, weight_decay, epocs=50): network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10, weight_decay_lambda=weight_decay) trainer = Trainer(network, x_train, t_train, x_val, t_val, epochs=epocs, mini_batch_size=100, optimizer='sgd', optimizer_param={'lr': lr}, verbose=False) trainer.train() return trainer.test_acc_list, trainer.train_acc_list # ハイパーパラメータのランダム探索====================================== optimization_trial = 100 results_val = {} results_train = {} for _ in range(optimization_trial): # 探索したハイパーパラメータの範囲を指定=============== weight_decay = 10 ** np.random.uniform(-8, -4) lr = 10 ** np.random.uniform(-6, -2) # ================================================ val_acc_list, train_acc_list = __train(lr, weight_decay) print("val acc:" + str(val_acc_list[-1]) + " | lr:" + str(lr) + ", weight decay:" + str(weight_decay)) key = "lr:" + str(lr) + ", weight decay:" + str(weight_decay) results_val[key] = val_acc_list results_train[key] = train_acc_list # グラフの描画======================================================== print("=========== Hyper-Parameter Optimization Result ===========") graph_draw_num = 20 col_num = 5 row_num = int(np.ceil(graph_draw_num / col_num)) i = 0 for key, val_acc_list in sorted(results_val.items(), key=lambda x:x[1][-1], reverse=True): print("Best-" + str(i+1) + "(val acc:" + str(val_acc_list[-1]) + ") | " + key) plt.subplot(row_num, col_num, i+1) plt.title("Best-" + str(i+1)) plt.ylim(0.0, 1.0) if i % 5: plt.yticks([]) plt.xticks([]) x = np.arange(len(val_acc_list)) plt.plot(x, val_acc_list) plt.plot(x, results_train[key], "--") i += 1 if i >= graph_draw_num: break #plt.show() plt.savefig('hyperparameter_optimization_save.png')
以下、実行結果とグラフ(検証データ:実線、訓練データ:点線)
=========== Hyper-Parameter Optimization Result =========== Best-1(val acc:0.77) | lr:0.00757365478878744, weight decay:4.612578587686737e-07 Best-2(val acc:0.76) | lr:0.007433061542623079, weight decay:1.0344933324636203e-07 Best-3(val acc:0.76) | lr:0.0069442614770180554, weight decay:3.5083892101171096e-07 Best-4(val acc:0.76) | lr:0.00786568274411027, weight decay:2.128003163191066e-06 Best-5(val acc:0.76) | lr:0.009977128388270529, weight decay:5.034544517460483e-07 Best-6(val acc:0.75) | lr:0.006651552434409378, weight decay:9.770817734920272e-08 Best-7(val acc:0.72) | lr:0.006787994923710441, weight decay:1.538788471810156e-08 Best-8(val acc:0.69) | lr:0.005309167300473579, weight decay:7.092519614173075e-07 Best-9(val acc:0.65) | lr:0.004171913096880143, weight decay:3.7534502493629925e-07 Best-10(val acc:0.64) | lr:0.0036177186197134006, weight decay:3.419650414313433e-07 Best-11(val acc:0.55) | lr:0.004657623419509241, weight decay:1.3150591635104507e-05 Best-12(val acc:0.45) | lr:0.002600118643665009, weight decay:6.101368606264845e-06 Best-13(val acc:0.42) | lr:0.0014781722372820818, weight decay:6.555096165359242e-07 Best-14(val acc:0.35) | lr:0.00112894903737969, weight decay:6.35129426114411e-08 Best-15(val acc:0.35) | lr:0.001122116867042764, weight decay:2.8146026473082357e-05 Best-16(val acc:0.31) | lr:0.0019504915229014257, weight decay:4.5759839999890385e-08 Best-17(val acc:0.29) | lr:0.001523802348758895, weight decay:1.3898280180637062e-07 Best-18(val acc:0.22) | lr:0.0011058186976594655, weight decay:2.7502587954667702e-08 Best-19(val acc:0.21) | lr:0.0004461535980654127, weight decay:7.17362065696084e-05 Best-20(val acc:0.21) | lr:0.0006365291753190107, weight decay:4.449107159041093e-06
Best-5ぐらいまで順調に学習が進んでいることが分かる。
学習係数lrが0.001から0.01
Weight decay係数が10^-8から10^-6
このように、試行錯誤しながら、最適なハイパーパラメータを人為的に特定していかなければならない。
最後に、6章のまとめ問題
・パラメータの更新方法には、SGD以外に◯◯、◯◯、◯◯、などの手法がある ・重みの初期値の推奨は、「◯◯」や「◯◯」である ・◯◯を用いることで学習を加速でき、初期値に左右されにくい◯◯になる ・過学習を抑制する正則化技術として、◯◯や◯◯がある ・ハイパーパラメータの探索は、◯◯するのが効率的である