Adam那么棒,为什么还对SGD念念不忘 (1) —— 一个框架看懂优化算法

机器学习界有一群炼丹师,他们每天的日常是:

拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着丹药出炉了。

不过,当过厨子的都知道,同样的食材,同样的菜谱,但火候不一样了,这出来的口味可是千差万别。火小了夹生,火大了易糊,火不匀则半生半糊。

机器学习也是一样,模型优化算法的选择直接关系到最终模型的性能。有时候效果不好,未必是特征的问题或者模型设计的问题,很可能就是优化算法的问题。

说到优化算法,入门级必从SGD学起,老司机则会告诉你更好的还有AdaGrad/AdaDelta,或者直接无脑用Adam。可是看看学术界的最新paper,却发现一众大神还在用着入门级的SGD,最多加个Moment或者Nesterov ,还经常会黑一下Adam。比如 UC Berkeley的一篇论文就在Conclusion中写道:

Despite the fact that our experimental evidence demonstrates that adaptive methods are not advantageous for machine learning, the Adam algorithm remains incredibly popular. We are not sure exactly as to why ……

无奈与酸楚之情溢于言表。

这是为什么呢?难道平平淡淡才是真?


一个框架回顾优化算法

首先我们来回顾一下各类优化算法。

深度学习优化算法经历了 SGD -> SGDM -> NAG ->AdaGrad -> AdaDelta -> Adam -> Nadam 这样的发展历程。Google一下就可以看到很多的教程文章,详细告诉你这些算法是如何一步一步演变而来的。在这里,我们换一个思路,用一个框架来梳理所有的优化算法,做一个更加高屋建瓴的对比。

首先定义:待优化参数:  ,目标函数:  ,初始学习率 

而后,开始进行迭代优化。在每个epoch  :

  1. 计算目标函数关于当前参数的梯度: 
  2. 根据历史梯度计算一阶动量和二阶动量:
  3. 计算当前时刻的下降梯度: 
  4. 根据下降梯度进行更新: 

掌握了这个框架,你可以轻轻松松设计自己的优化算法。

我们拿着这个框架,来照一照各种玄乎其玄的优化算法的真身。步骤3、4对于各个算法都是一致的,主要的差别就体现在1和2上。

SGD

先来看SGD。SGD没有动量的概念,也就是说:

代入步骤3,可以看到下降梯度就是最简单的

SGD最大的缺点是下降速度慢,而且可能会在沟壑的两边持续震荡,停留在一个局部最优点。

SGD with Momentum

为了抑制SGD的震荡,SGDM认为梯度下降过程可以加入惯性。下坡的时候,如果发现是陡坡,那就利用惯性跑的快一些。SGDM全称是SGD with momentum,在SGD基础上引入了一阶动量:

一阶动量是各个时刻梯度方向的指数移动平均值,约等于最近  个时刻的梯度向量和的平均值。

也就是说,t时刻的下降方向,不仅由当前点的梯度方向决定,而且由此前累积的下降方向决定。  的经验值为0.9,这就意味着下降方向主要是此前累积的下降方向,并略微偏向当前时刻的下降方向。想象高速公路上汽车转弯,在高速向前的同时略微偏向,急转弯可是要出事的。

SGD with Nesterov Acceleration

SGD 还有一个问题是困在局部最优的沟壑里面震荡。想象一下你走到一个盆地,四周都是略高的小山,你觉得没有下坡的方向,那就只能待在这里了。可是如果你爬上高地,就会发现外面的世界还很广阔。因此,我们不能停留在当前位置去观察未来的方向,而要向前一步、多看一步、看远一些。

NAG全称Nesterov Accelerated Gradient,是在SGD、SGD-M的基础上的进一步改进,改进点在于步骤1。我们知道在时刻t的主要下降方向是由累积动量决定的,自己的梯度方向说了也不算,那与其看当前梯度方向,不如先看看如果跟着累积动量走了一步,那个时候再怎么走。因此,NAG在步骤1,不计算当前位置的梯度方向,而是计算如果按照累积动量走了一步,那个时候的下降方向:

然后用下一个点的梯度方向,与历史累积动量相结合,计算步骤2中当前时刻的累积动量。

AdaGrad

此前我们都没有用到二阶动量。二阶动量的出现,才意味着“自适应学习率”优化算法时代的到来。SGD及其变种以同样的学习率更新每个参数,但深度神经网络往往包含大量的参数,这些参数并不是总会用得到(想想大规模的embedding)。对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。

怎么样去度量历史更新频率呢?那就是二阶动量——该维度上,迄今为止所有梯度值的平方和:

我们再回顾一下步骤3中的下降梯度:

可以看出,此时实质上的学习率由  变成了  。 一般为了避免分母为0,会在分母上加一个小的平滑项。因此 是恒大于0的,而且参数更新越频繁,二阶动量越大,学习率就越小。

这一方法在稀疏数据场景下表现非常好。但也存在一些问题:因为 是单调递增的,会使得学习率单调递减至0,可能会使得训练过程提前结束,即便后续还有数据也无法学到必要的知识。

AdaDelta / RMSProp

由于AdaGrad单调递减的学习率变化过于激进,我们考虑一个改变二阶动量计算方法的策略:不累积全部历史梯度,而只关注过去一段时间窗口的下降梯度。这也就是AdaDelta名称中Delta的来历。

修改的思路很简单。前面我们讲到,指数移动平均值大约就是过去一段时间的平均值,因此我们用这一方法来计算二阶累积动量:

这就避免了二阶动量持续累积、导致训练过程提前结束的问题了。

Adam

谈到这里,Adam和Nadam的出现就很自然而然了——它们是前述方法的集大成者。我们看到,SGD-M在SGD基础上增加了一阶动量,AdaGrad和AdaDelta在SGD基础上增加了二阶动量。把一阶动量和二阶动量都用起来,就是Adam了——Adaptive + Momentum。

SGD的一阶动量:

加上AdaDelta的二阶动量:

优化算法里最常见的两个超参数  就都在这里了,前者控制一阶动量,后者控制二阶动量。

Nadam

最后是Nadam。我们说Adam是集大成者,但它居然遗漏了Nesterov,这还能忍?必须给它加上,按照NAG的步骤1:

这就是Nesterov + Adam = Nadam了。

说到这里,大概可以理解为什么j经常有人说 Adam / Nadam 目前最主流、最好用的优化算法了。新手上路,先拿来一试,收敛速度嗖嗖滴,效果也是杠杠滴。

那为什么Adam还老招人黑,被学术界一顿鄙夷?难道只是为了发paper灌水吗?

请继续阅读:

Adam那么棒,为什么还对SGD念念不忘 (2)—— Adam的两宗罪

Adam那么棒,为什么还对SGD念念不忘 (3)—— 优化算法的选择与使用策略

————————————————————

补充:指数移动平均值的偏差修正

前面我们讲到,一阶动量和二阶动量都是按照指数移动平均值进行计算的:

实际使用过程中,参数的经验值是

初始化:

这个时候我们看到,在初期,  都会接近于0,这个估计是有问题的。因此我们常常根据下式进行误差修正:

————————————————————

行有所思,学有所得,陋鄙之言,请多指教。

欢迎关注我的微信公众号 Julius-AI

一个框架看懂优化算法之异同 SGD/AdaGrad/Adam的更多相关文章

  1. zz:一个框架看懂优化算法之异同 SGD/AdaGrad/Adam

    首先定义:待优化参数:  ,目标函数: ,初始学习率 . 而后,开始进行迭代优化.在每个epoch  : 计算目标函数关于当前参数的梯度:  根据历史梯度计算一阶动量和二阶动量:, 计算当前时刻的下降 ...

  2. Adam那么棒,为什么还对SGD念念不忘 (1) —— 一个框架看懂优化算法

    机器学习界有一群炼丹师,他们每天的日常是: 拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着丹药出炉了. 不过,当过厨子的都知道,同样的食材,同样的菜谱,但火候不一样了, ...

  3. 一个故事看懂HTTPS

    我是一个浏览器,每到夜深人静的时候,主人就打开我开始学习. 为了不让别人看到浏览记录,主人选择了"无痕模式". 但网络中总是有很多坏人,他们通过抓包截获我和服务器的通信,主人干了什 ...

  4. [DeeplearningAI笔记]改善深层神经网络_优化算法2.6_2.9Momentum/RMSprop/Adam优化算法

    Optimization Algorithms优化算法 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.6 动量梯度下降法(Momentum) 另一种成本函数优化算法,优化速度一般快于标准 ...

  5. 从三数之和看如何优化算法,递推-->递推加二分查找-->递推加滑尺

    人类发明了轮子,提高了力的使用效率. 人类发明了自动化机械,将自己从重复的工作中解脱出来. 提高效率的方法好像总是离不开两点:拒绝无效劳动,拒绝重复劳动.人类如此,计算机亦如是. 前面我们说过了四数之 ...

  6. 一个例子看懂所有nodejs的官方网络demo

    今天看群里有人用AI技术写了个五子棋,正好用的socket.io,本身我自己很久没看nodejs了,再加上Tcp/IP的知识一直很弱,我就去官网看了下net.socket 发现之前以为懂的一个官方例子 ...

  7. 一个故事看懂AI神经网络工作原理

    我是一个AI神经元 我是一个AI神经元,刚刚来到这个世界上,一切对我来说都特别新奇. 之所以叫这个名字,是因为我的工作有点像人类身体中的神经元. 人体中的神经元可以传递生物信号,给它输入一个信号,它经 ...

  8. 一个故事看懂CPU的TLB

    Hi,我是CPU一号车间的阿Q,还记得我吗,真是好久不见了- 我所在的CPU是一个八核CPU,就有八个工作车间,那运行起来速度杠杆的- 虚拟地址翻译 一大早,我们一号车间MMU(内存管理单元)部门的小 ...

  9. 一个故事看懂Linux文件权限管理

    前情回顾: 我通过open这个系统调用虫洞来到了内核空间,又在老爷爷的指点下来到了sys_open的地盘,即将开始打开文件的工作. 详情参见:内核地址空间大冒险:系统调用 open系统调用链 我是一个 ...

随机推荐

  1. 五.反馈(Hopfield)神经网络

    前馈网络一般指前馈神经网络或前馈型神经网络.它是一种最简单的神经网络,各神经元分层排列.每个神经元只与前一层的神经元相连.接收前一层的输出,并输出给下一层,数据正想流动,输出仅由当前的输入和网络权值决 ...

  2. laravel-- 在laravel操作redis数据库的数据类型(string、哈希、无序集合、list链表、有序集合)

    安装redis和连接redis数据库 在controller头部引入 一.基本使用 public function RedisdDbOne() { // 清空Redis数据库 Redis::flush ...

  3. 从零起步 系统入门Python爬虫工程师

    从零起步 系统入门Python爬虫工程师 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看的 ...

  4. Python3.7.4入门-5输入输出

    5 输入输出 5.1 格式化字符串字面值 在字符串的开始引号或三引号之前加上一个 f 或 F .在此字符串中,你可以在 { 和 } 字符之间写可以引用的变量或字面值的 Python 表达式. > ...

  5. xcode自动完成代码 Code Snippet Library

    今天发现Xcode里一个好东西:代码片段库 你可以将自己常用的代码放到里面,给它命名,设置快捷键,以后想用这段代码的时候只要按快捷键,就会出现提示,直接将这段代码显示出来,十分高效. 比如我经常会用到 ...

  6. SPARK Day04

    广播变量和累加器 广播变量 广播变量理解图 广播变量使用 val conf = new SparkConf() conf.setMaster("local").setAppName ...

  7. shell脚本批量杀死进程

    使用Ubuntu系统时常会遇到机器卡死的情况(人生最大的痛苦),所有的键都没有用,只好强制关机,我似乎对此已经'乐此不疲了'. 看到又神牛说: 可以在tty里面把相关的进程杀死,之后就正常.(到目前我 ...

  8. Add Binary字符数字相加,字符串合成

    Given two binary strings, return their sum (also a binary string). For example,a = "11"b = ...

  9. 设备 VMnet0 上的网络桥接当前未在运行。

    早上,我打开我的虚拟机,却发现一个问题, 桥接网络怎么都连接不上. 报的是如下的错误 ------------------------------ 设备 VMnet0 上的网络桥接当前未在运行.该虚拟 ...

  10. uva 10739【基础(区间)dp】

    Uva 10739 题意:给定字符串,可以增加.删除.修改任意字符,问最少经过多少次操作使字符串回文. 题解:定义dp[l][r]表示把从l到r的子串Sl...Sr变成回文串需要操作的最少次数.字符可 ...