機械学習のお勉強(オプティマイザーと学習率とエポック、イテレーション)
オプティマイザー
勾配
勾配(微分に負をかけたもの)が示す方向は関数の値を減らす方向になる。
↓数値微分。シンプルだが計算に時間がかかる。
def numerical_gradient(f,x): h = 1e-4 # 0.0001 grad = np.zeros_like(x) for idx in range(x.size): tmp_val = x[idx] x[idx] = tmp_val + h fxh1 = f(x) x[idx] = tmp_val - h fxh2 = f(x) grad[idx] = (fxh1 - fxh2)/(2*h) x[idx] = tmp_val return grad
この勾配の計算を高速に求める手法として、誤差逆伝播法が存在する。
勾配降下法
勾配方向に一定距離だけ進み、そこで勾配を求め再度進む。これの繰り返しによって関数の値を減らす。
以下の式のlrは学習率(learning rate)はあらかじめ人が決める(試行錯誤的に決める)必要があり、ハイパーパラメータと呼ばれる。
このパラメータはバイアスや重みと異なり自動で決めることはできない、かつ、正しく学習するうえで重要。
def gradient_descent(f, init_x, lr = 0.01, step_num = 100): x = init_x for i in range(step_num): grad = numerical_gradient(f, x) x -= lr * grad return x
確率的勾配降下法
上記のxをランダムに選んだサンプル一つだけで計算したもの
ミニバッチ確率勾配降下法
上記の1つのサンプルだけではなく、k個のサンプルを1回の更新に利用
モーメンタムSGD
def gradient_descent(f, init_x, lr = 0.01, step_num = 100): x = init_x for i in range(step_num): grad = numerical_gradient(f, x) v = gamma * pre_v + (1 - gammma) * grad x -= lr * v pre_v = v return x
v = gamma * pre_v + (1 - gamma) * grad
とする、gamma=0.9などにすることが多い。
また、v[t] = (1 - gamma) * sum(gamma**k * grad[t-k] for k in range(t))
と過去の勾配の和として書くことができる。
学習率
上記の
x -= lr * grad
のlrにあたるもの。
学習の速さや最終的なロス値にトレードオフがあるため適切な学習率の設定が必要
AdaGrad
学習率を勾配が大きい時は小さく、小さい時は大きくする方法
eps = 1e-4 # 0.0001 G_2 = pre_G**2 + grad**2 x -= lr / sqrt(G_2 + eps) * grad pre_G = G_2
G_2 は増加し続けるため、学習が進まなくなることがある
Adam
Momentum SGDの重み付き平均 と AdaGradの重み付き分散を踏まえ、
上記の問題を解決した手法
eps = 1e-4 # 0.0001 bias = sum(gamma**k * grad[t-k] for k in range(t)) # 重み付き平均 var = (bata * pre_var**2 + (1- beta) * grad**2) / (1 -beta) x -= lr * bias / sqrt(var + eps) pre_var = var
参考:
Optimizer : 深層学習における勾配法について - Qiita
エポックとイテレーション
エポック
すべての学習サンプルを学習するのに要した機関
イテレーション
重みを1回更新すること
まとめ
学習率を表す際、イテレーションはバッチサイズに依存してしまうため不適切。
エポックの場合、勾配降下法なのかミニバッチ確率的勾配降下法なのかでかわらない、つまりバッチサイズに依存しない。