如何理解Adam算法(Adaptive moment estimation)?

作者:薰风初入弦
链接:https://www.zhihu.com/question/323747423/answer/790457991
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

文章和论文看不懂,通常有三个原因:

  1. 对前置知识掌握不佳
  2. 没有结合理论与实践
  3. 没有对知识形象理解

Adam本质上实际是RMSProp+动量。但如果你对随机梯度下降SGD的知识,以及Adam之前的几个更新方法一无所知。那么当你看到一个“复杂的”Adam看了就头大(请不要嘲笑初学者,当年我也觉得深度学习各个地方都超复杂)。

即使你看了论文和文章,如果不结合代码与实现,知道的也只是别人口中的“xxx的本质其实是xxx”,但这种别人的本质对你自己了解帮助不大。

最后,如果有个动图,Demo,实例,那么对你的帮助当然就更大啦。

这里我就结合这三点,好好讲一讲什么是Adam

本文翻译&改编自CS231n课件,链接见参考文献部分

一、引言 Introduction

现在假设你对反向传播的计算梯度的内容比较了解(不了解的欢迎在评论留言,我考虑有时间写),一旦能使用反向传播计算解析梯度,梯度就能被用来进行参数更新了。

进行参数更新有好几种方法,接下来都会进行讨论。深度网络的最优化是现在非常活跃的研究领域。(具体的细节看论文,请)

二、前置知识(Adam有关的更新方法)

  1. 普通更新

最简单的沿着负梯度方向改变参数(梯度指向的是上升方向,但要最小化损失函数)。

假设有一个参数向量x及其梯度dx,那么最简单的更新的形式是:

# 普通更新
x += - learning_rate * dx

其中,learning_rate是一个超参数,它是一个固定常量

当在整个数据集上进行计算时,只要学习率足够低,总是能在损失函数上得到非负的进展。

2. 动量(Momentum)更新

该方法从物理角度上对于最优化问题得到的启发。

损失值是山的高度(因此高度势能

 

,所以有

 

)。最优化过程可以看做是模拟参数向量(即质点)在地形上滚动的过程。因为作用于质点的力与梯度潜在能量

 

)有关,质点所受的力就是损失函数的(负)梯度。

重力势能,中学常识之一

还有,因为 F=ma,所以在这个观点下(负)梯度与质点的加速度成比例

注意这个理解与随机梯度下降(SDG)不同,在SGD中,梯度影响位置

而在这个版本的更新中,物理观点建议梯度只是影响速度,然后速度再影响位置

    # 动量更新
    v = mu * v - learning_rate * dx # 与速度融合
    x += v # 与位置融合
    

在这里引入了一个初始=0的 变量v 和一个超参数mu。变量 mu 在最优化的过程中被看做动量(一般值设为0.9),但其物理意义与摩擦系数更一致

这个变量有效地抑制了速度,降低了系统的动能,不然质点在山底永远不会停下来。

通过交叉验证,mu通常设为[0.5,0.9,0.95,0.99]中的一个。和学习率随着时间退火(下文有讨论)类似,动量随时间变化能略微效果,其中动量在学习过程的后阶段会上升

一个典型的设置是刚开始0.5,多个周期(epoch)中慢慢提升到0.99。

通过动量更新,参数向量会在任何有持续梯度的方向上增加速度。

3. Nesterov动量

与普通动量不同,最近比较流行。在理论上对于凸函数能更好的收敛,在实践中也表现更好。

核心思路 :

当参数向量位于某个位置 x 时,观察上面的动量更新公式,动量部分(momentum step)会通过mu * v改变参数向量。

因此,如要计算梯度,那么可以将未来的近似位置 x+mu*v看做是“向前看”,这个点在我们一会儿要停止的位置附近。因此,计算 x+mu*v的梯度而不是“旧”位置 x 的梯度就有意义了。

Nesterov动量

既然动量会把参数带到绿色箭头指向的点,那就不要在原点(红色点)那里计算梯度了。

使用Nesterov动量,我们就在这个“向前看”的地方计算梯度。

也就是说,添加一些注释后,实现代码如下:

x_ahead = x + mu * v
#   计算dx_ahead(在x_ahead处的梯度,而不是在x处的梯度)
v = mu * v - learning_rate * dx_ahead
x += v  

上面的程序还得写 dx_ahead,就很麻烦。

但通过对 x_ahead = x + mu * v 使用变量变换进行改写是可以做到的,然后用x_ahead而不是x来表示上面的更新。

也就是说,实际存储的参数向量总是向前一步版本。x_ahead 的公式(将其重新命名为x)就变成了:

v_prev = v # 存储备份
v = mu * v - learning_rate * dx # 速度更新保持不变
x += -mu * v_prev + (1 + mu) * v # 位置更新变了形式

3. RMSprop

非常高效,但没发表的适应性学习率方法。有趣的是,使用这个方法的人论文中都引用自Geoff Hinton的Coursera课程的第六课的第29页PPT。他修改了Adagrad方法,让方法不那么激进。

具体说来,就是它使用了一个梯度平方的滑动平均:

cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)

在上面的代码中,decay_rate是一个超参数常用[0.9,0.99,0.999]

x+=和Adagrad中是一样的,但是cache变量是不同的。因此,RMSProp仍然是基于梯度的大小来对每个权重的学习率进行修改,这同样效果不错。但其更新不会让学习率单调变小。

以上就是所有需要的前置知识,接下来就是正题了。

三、Adam

AdamRMSProp的动量版。简化的代码是下面这样:

    m = beta1*m + (1-beta1)*dx
    v = beta2*v + (1-beta2)*(dx**2)
    x += - learning_rate * m / (np.sqrt(v) + eps)

注意,这方法和RMSProp很像,除了使用的是平滑版的梯度m,而不是原始梯度dx。

推荐参数值eps=1e-8, beta1=0.9, beta2=0.999。

在实际操作中,推荐Adam作为默认算法,一般比RMSProp要好一点。

但是也可以试试SGD+Nesterov动量。

完整的Adam更新算法也包含了一个偏置(bias)矫正机制,因为m,v两个矩阵初始为0,在没有完全热身之前存在偏差,需要采取一些补偿措施。

不同最优化方法效果

注意基于动量的方法射偏了的情况,使得最优化过程看起来像是一个球滚下山的样子。

上图展示了一个马鞍状的最优化地形,其中对于不同维度它的曲率不同(一个维度下降另一个维度上升)。注意SGD很难突破对称性,一直卡在顶部。而RMSProp之类的方法能够看到马鞍方向有很低的梯度。

因为在RMSProp更新方法中的分母项,算法提高了在该方向的有效学习率,使得RMSProp能够继续前进。

参考文献:

http://cs231n.github.io/neural-networks-3/

转载于:

https://www.zhihu.com/question/323747423/answer/790457991

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值