MomentumとAdaGrad

MomentumとAdaGrad

前回まではパラメータの更新に確率的勾配降下法(SGD)を使いました。精度は30%ぐらいだったので、今回はMomentumとAdaGradを使ってどの位変わるか試してみます。

SGD

定義

 {x←x-\frac{∂L}{∂W}}

コード

SGDクラスを作成する。

class SGD:
    def __init__(self, lr=0.5):
        self.lr = lr
    
    def update(self, paramas, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]

Momentum

定義

 {v←αv-η\frac{∂L}{∂W}}

コード

Momentumクラスを作成する。

class Momentum:
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v ={}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)

        for key in params.keys():
            self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
            params[key] += self.v[key]

AdaGrad

定義

[tex: {h←h+\frac{∂L}{∂W}\frac{∂L}{∂W}}]
[tex: {W←W-η\frac{1}{\sqrt{h}}
\frac{∂L}{∂W}}]
学習回数が増えるにしたがい、パラメータ更新が小さくなる。

コード

AdaGradクラスを作成する。

class AdaGrad:
    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None

    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in pramas.items():
                self.h[key] = np.zeros_like(val)
            
        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]+1e-7))

mainプログラム

最適化手法を選べるようにプログラムを修正する。

ans_label = np.argmax(t_train, axis=1)
ans = 0
for i in range(100):
    network = LayerNet(2, 2, 2)
    optimizer = Momentum()       #最適化手法を選択
    for step in range(1001):
        batch_mask = np.random.choice([0,1,2,3], 1)
        x_batch = x_train[batch_mask]
        t_batch = t_train[batch_mask]

        grads = network.training(x_batch, t_batch)
        params = network.params
        optimizer.update(params, grads)

        if step == 1000:
            y = np.argmax(network.predict(x_train), axis=1)
            print("y:", y)
            a = (y == ans_label)
            if a.all():
                ans += 1
print("ans:", ans, "/ 100")

出力

Momentum

学習率0.01 運動量0.9

('ans:', 52, '/ 100')
('ans:', 53, '/ 100')
('ans:', 51, '/ 100')

学習率0.5 運動量0.9

('ans:', 0, '/ 100')
('ans:', 0, '/ 100')

学習率0.05 運動量0.9

('ans:', 18, '/ 100')

学習率0.01 運動量0.5

('ans:', 39, '/ 100')

AdaGrad

学習率0.01

('ans:', 0, '/ 100')
('ans:', 0, '/ 100')

学習率0.5

('ans:', 7, '/ 100')
('ans:', 6, '/ 100')

結論

学習率と運動量をうまく設定すれば、Momentumを使用することで精度があがる。 AdaGradはXOR回路ではうまくいかない。 ハイパーパラメータ(学習率,運動量など)はランダムに選んで、良い結果を導けるプログラムに修正すると尚よい。