-Deep Learning- 勾配法

機械学習の問題の多くは,学習の際に最適なパラメータを探索します.ニューラルネットワークも同様に最適なパラメータ(重みとバイアス)を学習時に見つける必要があります.ここで言う最適なパラメータとは,損失関数が最小値を取る時のパラメータの値です.
そこで,勾配を上手く利用して関数の最小値(またはできるだけ小さな値)を探すのが勾配法(gradient method)です.

ここでは,最小値を探す場合を勾配降下法(gradient descent method)の実装例を以下に示します.

 
# Import Module
import numpy as np
 
# Definition of Function
def numerical_gradient(f, x): 
    h = 1e-4                    # h = 0.0001
    grad = np.zeros_like(x)     # Generate an array with the same shape as x
 
    for idx in range(x.size): 
        tmp_val = x[idx]
        # Calculate f(x + h) 
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)
 
        # Calculate f(x - h)
        x[idx] = tmp_val - h
        fxh2 = f(x)
        grad[idx] = (fxh1 - fxh2) / (2 * h)
 
        x[idx] = tmp_val # Restore the value
 
    return grad
 
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
 
def function_2(x): 
    return x[0]**2 + x[1]**2
 
# Data setting
init_x = np.array([-3.0, 4.0])
 
# Solving problem
ans = gradient_descent(function_2, init_x = init_x, lr = 0.1, step_num = 100)
 
# Display results
print(ans)
 
実行結果は以下のようになります.
[-6.11110793e-10  8.14814391e-10]
 
上記の例では,初期値を (-3.0, 4.0) として,勾配法を使って最小値の探索を開始します.答えとしては (-6.1e-10, 8.1e-10) という結果であり,これはほぼ (0, 0) に近い結果が得られています.実際に真の最小値は (0, 0) なので,ほぼ正しい結果を得ることができています.
 
ここで,学習率の値 lr によってどのように変化するかを見てみます.
 
上記にプログラムで,
 
ans = gradient_descent(function_2, init_x = init_x, lr = 10.0, step_num = 100)
 
と書き換えて実行してみると以下のような結果が得られます.
[-2.58983747e+13 -1.29524862e+12]
学習率 lr が大きすぎると,大きな値に発散しています.
 
続いて,以下のように書き換えてみます.
 
ans = gradient_descent(function_2, init_x = init_x, lr = 1e-10, step_num = 100)
 
と書き換えてみると以下のような結果が得られます.
[-2.99999994  3.99999992]
学習率 lr が大きすぎると,値がほとんど更新されずに計算が終わってしまいます(step_num を大きくすれば計算は進みますが,計算時間が必要).
 

これらの結果から,適切な学習率を設定することが重要であることがわかります.