ディープラーニングについてディープにラーニング。

思いっきり、自分が学んだことのアウトプットしていきますが、何分初心者。もし何かアドバイス等頂けましたら幸いです!

ハイパラメータの検証

今日もアウトプット。


ハイパーパラメータとは

各層のニューロンの数とか、バッチサイズ、学習係数やWeight decayなど、
人の手で適正な値を設定しないといけないパラメータのことである。

検証データ

これまでは、学習データとテストデータの2つを用いていた。
用途としては、訓練データで学習を行い、テストデータでモデルの評価を行う。
そうすることで過学習になってないか?汎用性能はいいのか?とか判断してた。

じゃぁ、ハイパーパラメータもテストデータで検証…
はどうやらNGみたいだ。
それは、
テストデータを使ってハイパーパラメータを調整すると、
テストデータに対して適応してしまい、テストデータに過学習を起こしてしまうからである。
この、ハイパーパラメータの調整を実施するときのデータを検証データ(Validation data)という。

訓練データ→学習用
テストデータ→モデルの汎化性能用
検証データ→ハイパーパラメータ用

モデルによっては、
検証データを無理やり作らないといけな場合がある。

(x_train , t_train) , (x_test,y_test) = load_mnist()


x_train , t_train = shuffle_dataset(x_train,t_train)

validation_rate=0.2
validation_data = int(x_train.shape[0]*0.2)

x_val = xtrain[:validation_data]
t_val = t_train[:validation_data]modwe
x_train = x_train[validation_data:]
t_train = t_train[validation_data:]

学習データの2割をバリデーションデータとして使うコード。

ハイパーパラメータの最適化

では、やはり本筋になってくるのが、
パラメータの最適化(SGDやAdamとか…)が重要であったように、
ハイパーパラメータの最適化の手法も重要になってくる。

上記の通り、ハイパーパラメータは人の手で操作しなくてはいけないパラメータ。
残念ながら、パラメータみたいにテンプレート化されてない。
そこで、まずは下記の手順で行ってみるのが正。

①ハイパーパラメータの範囲の設定(ざっくりでOK)
②設定した範囲の中からランダムにサンプリング。
③ステップ2でサンプリングされたハイパーパラメータの値で学習を実施。
 検証データで精度を確認する。(エポック数は小さくでOK。本は50回とかでやってた)
④繰り返す


じゃあサンプルコードを丸記載。
今回は学習係数とWeight decayの2つを変える。

import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import matplotlib.pyplot as plt
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 = int(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()

上記のコードの中で、一つまたもや恥ずかしい話で、
マイナスの数字を累乗したらなんで小数点が増えるのか、についてまた一つ知った。

10の4乗=10000
10の3乗=1000
10の2乗=100
10の1乗=10
10の0乗=1
10の-1乗=0.1
10の-2乗=0.01

↓結果です。
f:id:kawam0t0:20191222113406p:plain

これを見ると、一番上のところがうまく最適化していることがわかる。


一応まとめ。
最適化の手法についてはSGD Adamとかあって、個々の目的は同じ。最適な重みやバイアスの数値を見つけて、
差分が最小になるように学習を重ねていくって話。
でも、複雑なネットワークや、学習データが少なかったりすると過学習が起こるので、
過学習を抑える努力がいる。
その方法としては、DropoutとかWeight decayといった方法がある。
また、ハイパーパラメータについても過学習、性能の良いモデルの構築には重要になる。




では、また。