IT@程序员猿媛Python数据科学程序员

深度学习入门--参数更新的优化

2019-04-05  本文已影响6人  爱吃西瓜的番茄酱

神经网络学习的目的是找到使损失函数的值尽可能小的参数。这是寻找最优参数的问题,解决这个问题的过程称为最优化。而在深度神经网络中,参数的数量非常庞大,最优化问题也就十分复杂。

之前我们学过随机梯度下降法(SGD)来寻找最优参数,大致思路是:将参数的梯度作为线索,沿梯度方向更新参数,并重复步骤多次,从而逐渐靠近最优参数。

在随机梯度下降法中有两种求梯度的方式:

将SGD实现为一个Python类:

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr  # 学习率

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

虽然SGD简单,但在解决某些问题时,也会显得十分低效。低效的根本原因是:梯度的方向并没有指向最小值的方法。

为了避免SGD的缺点,还有Momentum、AdaGrad、Adam这三种方法可以取代SGD。。

Momentum

Momentum是“动量”的意思,和物理有关。用Python表示如下:

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

在神经网络的学习中,学习率的值lr很重要,学习率过小,会导致学习花费过多时间;反过来,学习率过大会导致学习发散而不能正确进行。

在关于学习率的有效技巧中,有一种被称为学习率衰减的方法,即随着学习的进行,学习率不断减小。AdaGrad正是基于这种思想,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 params.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) # 加上微小值1e-7,防止除数为零

Adam

Adam融合了Momentum和AdaGrad两个方法的优点,有望实现参数空间的高效搜索。此外,进行超参数的“偏置校正”也是Adam的特征。

class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None
        
    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)
        
        self.iter += 1
        lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)         
        
        for key in params.keys():
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)

对于SGD、Momentum、AdaGrad和Adam这四种更新参数的方式。它们各自的最优化的更新路径如下图:



其中SGD最简单,使用也最广泛。Adam的综合性能最好,最受欢迎。

我们以MNIST手写数字集为例,比较SGD、Momentum、AdaGrad和Adam这四种方法在学习进展上有多大程度的差异:

如上图所示,SGD的学习进度最慢,损失函数的值最大;Momentum、AdaGrad和Adam这三种方法的学习进度较快,其中AdaGrad的学习效果最好。

每天学习一点点,每天进步一点点。

上一篇下一篇

猜你喜欢

热点阅读