关于参数更新的常用函数说明

本文参考:深度学习入门:基于Python的理论与实现 斋藤康毅(作者)

SGD:

随机梯度下降法是最简单的参数更新方法之一。

本方法将参数的梯度作为线索,使用参数的梯度,沿梯度更新参数,并多次重复该步骤,从而逐渐靠近最优参数。

缺点:如果函数的形状非均向,比如呈延申状,搜索路径将会非常低效,其根本原因是梯度的方向有时候并不是指向最小值的方向。

例如:

上图为函数f(x,y)的图形和等高线,下图为其梯度图像。

这个梯度的特征是,在y轴方向上大,x轴方向上小,换句话说,就是y轴方向的坡度大,而x轴方向的坡度小,从图中可以看出,虽然该函数在(0,0)点取得最小值,但很多梯度并不指向最小值点,所以其寻找路径就是之字形,如图

 

Momentum:

Momentum是动量的意思,用数学公式表达如下所示:

和前面的 SGD 一样,但这里新出现了一个变量 v ,对应物理上的速度。式(6.3)表示了物体在梯度方向上受力,在这个力的作用下,物体的速度增加这一物理法则。如图 6-4 所示,Momentum 方法给人的感觉就像是小球在地面上滚动。

式(6.3)中有av这一项。在物体不受任何力时,该项承担使物体逐渐减速的任务(α 设定为 0.9 之类的值),对应物理上的地面摩擦或空气阻力。下面是 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]

实例变量 v 会保存物体的速度。初始化时,v 中什么都不保存,但当第一次调用 update() 时,v 会以字典型变量的形式保存与参数结构相同的数据。剩余的代码部分就是将式(6.3)、式(6.4)写出来,很简单。

现在尝试使用 Momentum 解决式(6.2)的最优化问题,如下图所示。

中,更新路径就像小球在碗中滚动一样。和 SGD 相比,我们发现“之”字形的“程度”减轻了。这是因为虽然 x 轴方向上受到的力非常小,但是一直在同一方向上受力,所以朝同一个方向会有一定的加速。反过来,虽然 y 轴方向上受到的力很大,但是因为交互地受到正方向和反方向的力,它们会互相抵消,所以 y 轴方向上的速度不稳定。因此,和 SGD 时的情形相比,可以更快地朝 x 轴方向靠近,减弱“之”字形的变动程度。

 

 

AdaGrad

在关于学习率的有效技巧中,有一种被称为学习率衰减 (learning rate decay)的方法,即随着学习的进行,使学习率逐渐减小。实际上,一开始“多”学,然后逐渐“少”学的方法,在神经网络的学习中经常被使用。

 

逐渐减小学习率的想法,相当于将“全体”参数的学习率值一起降低。而 AdaGrad进一步发展了这个想法,针对“一个一个”的参数,赋予其“定制”的值。

AdaGrad 会为参数的每个元素适当地调整学习率,与此同时进行学习(AdaGrad 的 Ada 来自英文单词 Adaptive,即“适当的”的意思)。下面,让我们用数学式表示 AdaGrad 的更新方法。

这里新出现了变量 1/√h ,如式 (6.5) 所示,它保存了以前的所有梯度值的平方和(式(6.5)中的⊙表示对应矩阵元素的乘法)。然后,在更新参数时,通过乘以1/√h ,就可以调整学习的尺度。这意味着,参数的元素中变动较大(被大幅更新)的元素的学习率将变小。也就是说,可以按参数的元素进行学习率衰减,使变动大的参数的学习率逐渐减小。

AdaGrad 会记录过去所有梯度的平方和。因此,学习越深入,更新的幅度就越小。实际上,如果无止境地学习,更新量就会变为 0,完全不再更新。为了改善这个问题,可以使用 RMSProp 方法。RMSProp 方法并不是将过去所有的梯度一视同仁地相加,而是逐渐地遗忘过去的梯度,在做加法运算时将新梯度的信息更多地反映出来。这种操作从专业上讲,称为“指数移动平均”,呈指数函数式地减小过去的梯度的尺度。

现在来实现 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)

        self.h[key] += grads[key] * grads[key]


        params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

这里需要注意的是,最后一行加上了微小值 1e-7 。这是为了防止当 self.h[key] 中有 0 时,将 0 用作除数的情况。在很多深度学习的框架中,这个微小值也可以设定为参数,但这里我们用的是 1e-7 这个固定值。

 

现在,让我们试着使用 AdaGrad 解决式(6.2)的最优化问题,结果下图所示。

由上图 的结果可知,函数的取值高效地向着最小值移动。由于 y 轴方向上的梯度较大,因此刚开始变动较大,但是后面会根据这个较大的变动按比例进行调整,减小更新的步伐。因此,y 轴方向上的更新程度被减弱,“之”字形的变动程度有所衰减。

 

Adam:

Momentum 参照小球在碗中滚动的物理规则进行移动,AdaGrad 为参数的每个元素适当地调整更新步伐。如果将这两个方法融合在一起会怎么样呢?这就是 Adam方法的基本思路(这里关于 Adam 方法的说明只是一个直观的说明,并不完全正确。)

Adam 是 2015 年提出的新方法。它的理论有些复杂,直观地讲,就是融合了 Momentum 和 AdaGrad 的方法。通过组合前面两个方法的优点,有望实现参数空间的高效搜索。此外,进行超参数的“偏置校正”也是 Adam 的特征。

如下图所示,基于Adam的最优化更新路径

基于 Adam 的更新过程就像小球在碗中滚动一样。虽然 Momentun 也有类似的移动,但是相比之下,Adam 的小球左右摇晃的程度有所减轻。这得益于学习的更新程度被适当地调整了。

Adam 会设置 3 个超参数。一个是学习率,另外两个是一次 momentum系数 β1和二次 momentum系数β2。根据原作者论文,标准的设定值是 β1 为 0.9,β2 为 0.999。设置了这些值后,大多数情况下都能顺利运行。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值