点击上方,选择星标置顶,不定期资源大放送

阅读大概需要15分钟

Follow小博主,每天更新前沿干货

作者丨永远在你身后@知乎

来源丨https://zhuanlan.zhihu.com/p/81020717

编辑丨极市平台

本文仅用于学术分享,若侵权,请联系后台作删文处理。

导读

本文总结了SGD、MomentumNesterov、Momentum、AdaGrad...等十种优化算法,每一种算法的讲解都附有详细的公式过程以及代码实现。

无论是什么优化算法,最后都可以用一个简单的公式抽象:

 是参数,而  是参数的增量,而各种优化算法的主要区别在于对  的计算不同,本文总结了下面十个优化算法的公式,以及简单的Python实现:

  1. SGD

  2. Momentum

  3. Nesterov Momentum

  4. AdaGrad

  5. RMSProp

  6. AdaDelta

  7. Adam

  8. AdaMax

  9. Nadam

  10. NadaMax

SGD

虽然有凑数的嫌疑,不过还是把SGD也顺带说一下,就算做一个符号说明了。常规的随机梯度下降公式如下:

其中  是学习率,  是损失关于参数的梯度(有的资料中会写成  等形式),不过相比SGD,用的更多的还是小批量梯度下降(mBGD)算法,不同之处在于一次训练使用多个样本,然后取所有参与训练样本梯度的平均来更新参数,公式如下:

其中  是第  次训练中  个样本损失关于参数梯度的均值,如无特别声明,下文所出现  也遵循该定义

另外  或者  在下面的优化算法中,只是作为一个传入的变量,其具体的计算是由其他模块负责,可以参考下面两个链接:

Numpy实现神经网络框架(3)——线性层反向传播推导及实现

https://zhuanlan.zhihu.com/p/67854272

卷积核梯度计算的推导及实现

https://zhuanlan.zhihu.com/p/64248652

Momentum

Momentum,也就是动量的意思。该算法将梯度下降的过程视为一个物理系统,下图是在百度图片中找的(侵删)

图片来自网络

如上图所示,在该物理系统中有一个小球(质点),它所处的水平方向的位置对应为  的值,而垂直方向对应为损失。设其质量  ,在第  时刻,在单位时间内,该质点受外力而造成的动量改变为:

(1.1)到(1.2)是因为  ,所以约去了。另外受到的外力可以分为两个分量:重力沿斜面向下的力  和粘性阻尼力 

代入(1.2)式中:

然后对“位置”进行更新:

所以这里  ,另外  的方向与损失的梯度方向相反,并取系数为  ,得到:

代入(1.4),得到速度的更新公式:

进一步的,将(1.6)式展开,可以得到:

可以看出来是一个变相的等比数列之和,且公比小于1,所以存在极限,当  足够大时,  趋近于 

实现代码

import numpy as npclass Momentum(object):def __init__(self, alpha=0.9, lr=1e-3):self.alpha = alpha  # 动量系数self.lr = lr        # 学习率self.v = 0          # 初始速度为0def update(self, g: np.ndarray):    # g = J'(w) 为本轮训练参数的梯度self.v = self.alpha * self.v - self.lr * g  # 公式return self.v    # 返回的是参数的增量,下同

以上是基于指数衰减的实现方式,另外有的Momentum算法中会使用指数加权平均来实现,主要公式如下:

不过该方式因为  ,刚开始时  会比期望值要小,需要进行修正,下面的Adam等算法会使用该方式

Nesterov Momentum

Nesterov Momentum是Momentum的改进版本,与Momentum唯一区别就是,Nesterov先用当前的速度  更新一遍参数,得到一个临时参数  ,然后使用这个临时参数计算本轮训练的梯度。相当于是小球预判了自己下一时刻的位置,并提前使用该位置的梯度更新 :

为了更加直观,还是上几个图吧,以下是Momentum算法  的更新过程:

假设下一个位置的梯度如下:

那么Nesterov Momentum就提前使用这个梯度进行更新:

整体来看Nesterov的表现要好于Momentum,至于代码实现的话因为主要变化的是  ,所以可以之前使用Momentum的代码

AdaGrad

AdaGrad全称为Adaptive Subgradient,其主要特点在于不断累加每次训练中梯度的平方,公式如下:

其中  是一个极小的正数,用来防止除0,而  ,  是矩阵的哈达玛积运算符,另外,本文中矩阵的平方或者两矩阵相乘都是计算哈达玛积,而不是计算矩阵乘法

从公式中可以看出,随着算法不断迭代,  会越来越大,整体的学习率会越来越小。所以,一般来说AdaGrad算法一开始是激励收敛,到了后面就慢慢变成惩罚收敛,速度越来越慢

对于代码实现,首先将  展开得到:

通常  ,所以在第一次训练时(2.2)式为:

因为每次训练  的值是不确定的,所以要防止处0,但是可以令  ,这样就可以在(2.2)式中去掉  

将  代入(2.3)式,可以得到:

可知  恒大于0,因此不必在计算  中额外加入  ,代码如下:

class AdaGrad(object):def __init__(self, eps=1e-8, lr=1e-3):self.r = eps    # r_0 = epsilonself.lr = lrdef update(self, g: np.ndarray):r = r + np.square(g)return -self.lr * g / np.sqrt(r)

RMSProp

RMSProp是AdaGrad的改进算法,其公式和AdaGrad的区别只有  的计算不同,先看公式

可以看出,与AdaGrad不同,RMSProp只会累积近期的梯度信息,对于“遥远的历史”会以指数衰减的形式放弃

并且AdaGrad算法虽然在凸函数(Convex Functions)上表现较好,但是当目标函数非凸时,算法梯度下降的轨迹所经历的结构会复杂的多,早期梯度对当前训练没有太多意义,此时RMSProp往往表现更好

以下是将  展开后的公式:

与AdaGrad一样,令  ,从而去掉计算  时的  ,实现代码:

class RMSProp(object):def __init__(self, lr=1e-3, beta=0.999, eps=1e-8):self.r = epsself.lr = lrself.beta = betadef update(self, g: np.ndarray):r = r * self.beta + (1-self.beta) * np.square(g)return -self.lr * g / np.sqrt(r)

AdaDelta

AdaDelta是与RMSProp相同时间对立发展出来的一个算法,在实现上可以看作是RMSProp的一个变种,先看公式:

可以看到该算法不需要设置学习率  ,这是该算法的一大优势。除了同样以  来累积梯度的信息之外,该算法还多了一个  以指数衰减的形式来累积  的信息

与前面相同,令:

然后去掉(3.1)中的  ,得到:

这样的话可以减少一些计算,代码如下:

class AdaDelta(object):def __init__(self, beta=0.999, eps=1e-8):self.r = epsself.s = epsself.beta = betadef update(self, g: np.ndarray):g_square = (1-self.beta) * np.square(g)     # (1-beta)*g^2r = r * self.beta + g_squarefrac = s / rres = -np.sqrt(frac) * gs = s * self.beta + frac * g_squaretmp      # 少一次乘法。。。return res

关于以上几个算法的对比:

其中NAG是Nesterov Momentum

更多关于AdaDelta的信息,可以参考这篇文章:自适应学习率调整:AdaDelta(https://www.cnblogs.com/neopenx/p/4768388.html)

Adam

Adam的名称来自Adaptive Momentum,可以看作是Momentum与RMSProp的一个结合体,该算法通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应性学习率,公式如下:

(4.1)和(4.2)在Momentum和RMSProp中已经介绍过了,而不直接使用  计算  却先经过(4.3)和(4.4)式是因为通常会设  ,所以此时梯度的一阶矩估计和二阶矩估是有偏的,需要进行修正

虽然没办法避免修正计算,但是还是可以省去一些计算过程,初始化时令:

然后(4.5)式变为:

因为  ,可知当  足够大时修正将不起作用(也不需要修正了):

代码如下:

class Adam(object):def __init__(self, lr=1e-3, alpha=0.9, beta=0.999, eps=1e-8):self.s = 0self.r = epsself.lr = lrself.alpha = alphaself.beta = betaself.alpha_i = 1self.beta_i = 1def update(self, g: np.ndarray):self.s = self.s * self.alpha + (1-self.alpha) * gself.r = self.r * self.beta + (1-self.beta) * np.square(g)self.alpha_i *= self.alphaself.beta_i *= self.beta_ilr = -self.lr * (1-self.beta_i)**0.5 / (1-self.alpha_i)return lr * self.s / np.sqrt(self.r)

AdaMax

首先回顾RSMSProp中  的展开式并且令  ,得到:

可以看到这相当于是一个  的  范数,也就是说  的各维度的增量是根据该维度上梯度的  范数的累积量进行缩放的。如果用  范数替代就得到了Adam的不同变种,不过其中  范数对应的变种算法简单且稳定

对于  范数,第  轮训练时梯度的累积为:

然后求无穷范数:

由此再来递推  :

需要注意,这个max比较的是梯度各个维度上的当前值和历史最大值,具体可以结合代码来看,最后其公式总结如下:

另外,因为  是累积的梯度各个分量的绝对值最大值,所以直接用做分母且不需要修正,代码如下:

class AdaMax(object):def __init__(self, lr=1e-3, alpha=0.9, beta=0.999):self.s = 0self.r = 0self.lr = lrself.alpha = alphaself.alpha_i = 1self.beta = betadef update(self, g: np.ndarray):self.s = self.s * self.alpha + (1-self.alpha) * gself.r = np.maximum(self.r*self.beta, np.abs(g))self.alpha_i *= self.alphalr = -self.lr / (1-self.alpha_i)return lr * self.s / self.r

Nadam

Adam可以看作是Momentum与RMSProp的结合,既然Nesterov的表现较Momentum更优,那么自然也就可以把Nesterov Momentum与RMSProp组合到一起了,首先来看Nesterov的主要公式:

为了令其更加接近Momentum,将(5.1)和(5.2)修改为:

然后列出Adam中Momentum的部分:

将(5.5)和(5.6)式代入到(5.7)式中:

将上式中标红部分进行近似:

代入原式,得到:

接着,按照(5.4)式的套路,将  替换成  ,得到:

整理一下公式:

同样令  ,消去(5.8)式种的  :

代码

class Nadam(object):def __init__(self, lr=1e-3, alpha=0.9, beta=0.999, eps=1e-8):self.s = 0self.r = epsself.lr = lrself.alpha = alphaself.beta = betaself.alpha_i = 1self.beta_i = 1def update(self, g: np.ndarray):self.s = self.s * self.alpha + (1-self.alpha) * gself.r = self.r * self.beta + (1-self.beta) * np.square(g)self.alpha_i *= self.alphaself.beta_i *= self.beta_ilr = -self.lr * (1-self.beta_i)**0.5 / (1-self.alpha_i)return lr * (self.s * self.alpha + (1-self.alpha) * g) / np.sqrt(self.r)

NadaMax

按照同样的思路,可以将Nesterov与AdaMax结合变成NadaMax,回顾以下(5.8)式:

然后是AdaMax的二阶矩估计部分:

用(6.2)式替换掉(6.1)式中标红部分,得到:

最后,整理公式:

代码实现:

class NadaMax(object):def __init__(self, lr=1e-3, alpha=0.9, beta=0.999):self.s = 0self.r = 0self.lr = lrself.alpha = alphaself.alpha_i = 1self.beta = betadef update(self, g: np.ndarray):self.s = self.s * self.alpha + (1-self.alpha) * gself.r = np.maximum(self.r*self.beta, np.abs(g))self.alpha_i *= self.alphalr = -self.lr / (1-self.alpha_i)return lr * (self.s * self.alpha + (1-self.alpha) * g) / self.r

参考资料:

[1]: 《机器学习算法背后的理论与优化》 ISBN 978-7-302-51718-4

[2]: Adam: A Method for Stochastic Optimization(https://arxiv.org/abs/1412.6980)

[3]: Incorporating Nesterov Momentum into Adam(https://openreview.net/forum?id=OM0jvwB8jIp57ZJjtNEZ&noteId=OM0jvwB8jIp57ZJjtNEZ)

[4]: An overview of gradient descent optimization algorithms(https://ruder.io/optimizing-gradient-descent/index.html)

重磅!DLer-计算机视觉交流2群已成立!

大家好,这是DLer-计算机视觉微信交流2群欢迎各位Cver加入DLer-计算机视觉微信交流大家庭 。

本群旨在学习交流图像分类、目标检测、目标跟踪、点云与语义分割、GAN、超分辨率、人脸检测与识别、动作行为与时空运动、模型压缩和量化剪枝、迁移学习、人体姿态估计等内容。希望能给大家提供一个更精准的研讨交流平台!!!

进群请备注:研究方向+学校/公司+昵称(如图像分类+上交+小明)

???? 长按识别添加,即可进群!

【最全干货】从SGD到NadaMax,十种机器学习优化算法原理及实现相关推荐

  1. 收藏 | 从SGD到NadaMax,深度学习十种优化算法原理及实现

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者丨永远在你身后@知乎 来源丨https://zhuanl ...

  2. 从 SGD 到 Adam —— 深度学习优化算法概览 各种优化器 重点

    20210701 https://blog.51cto.com/u_15064630/2571266 [机器学习基础]优化算法详解 详细 https://blog.csdn.net/u01338501 ...

  3. 深度学习中常用的优化算法(SGD, Nesterov,Adagrad,RMSProp,Adam)总结

    深度学习中常用的优化算法(SGD, Nesterov,Adagrad,RMSProp,Adam)总结 1. 引言 在深度学习中我们定义了损失函数以后,会采取各种各样的方法来降低损失函数的数值,从而使模 ...

  4. 想要专升本你不得不看的全干货_吐血整理_专升本_计算机文化基础(一)

    你好,我是阿ken 2021/6/26 第一次优化排版和内容 之后会持续优化修改 ---------------- 版权声明:本文为CSDN博主「请叫我阿ken」的原创文章,遵循CC 4.0 BY-S ...

  5. 量子计算机芯片的制造过程,全干货!一文读懂芯片制造及量子芯片!

    原标题:全干货!一文读懂芯片制造及量子芯片! 最近两个月,因为一系列事情,大家对国内芯片产业的关注度日益增加. 那么,什么是芯片?如何制造芯片?涉及到多少高科技?目前的芯片产业将会有哪些挑战? 在这里 ...

  6. 全干货之Python3快速入门(五)——Python3函数

    全干货之Python3快速入门(五)--Python3函数 什么是函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段 函数能提高应用的模块性,和代码的重复利用率. 在Python中 ...

  7. 想要专升本你不得不看的全干货_吐血整理_专升本_计算机文化基础( 十 四 )

    大家好,我是阿Ken.很快就要整理完第三章了~ 对于专升本_计算机文化基础我已经在博客里整理了已经一半多了,希望能够在我整理后能够帮助其他的小伙伴,会一直整理完所有的专升本_计算机文化基础的笔记,感兴 ...

  8. 想要专升本你不得不看的全干货_吐血整理_专升本_计算机文化基础( 十 五 )

    大家好,我是阿Ken.很快就要整理完第三章了~ 对于专升本_计算机文化基础我已经在博客里整理了已经一半多了,希望能够在我整理后能够帮助其他的小伙伴,这月底整理完所有的专升本_计算机文化基础的笔记,感兴 ...

  9. 想要专升本你不得不看的全干货_吐血整理_专升本_计算机文化基础(十 一)

    大家好,我是阿Ken.很快就已经整理到了第三章~ 对于专升本_计算机文化基础我已经在博客里整理了已经一半多了,希望能够在我整理后能够帮助其他的小伙伴,这月底整理完所有的专升本_计算机文化基础的笔记,感 ...

最新文章

  1. CIO时代学院院长姚乐:传统行业遇上大数据 拥抱智能化未来
  2. 通过设置Ionic-Cli代理解决ionic serve跨域调试问题
  3. Veeam Backup Replication试用(四):配置同步(Replication Job)与恢复(Restore)
  4. vue,一路走来(14)--短信验证码框的实现(类似支付密码框)
  5. 操作系统实验报告2:Linux 下 x86 汇编语言1
  6. Web内核微信小程序框架实践
  7. ReviewForJob(1)数据结构与算法分析引论
  8. todolist作业效果
  9. 定义软件定义的存储市场
  10. [置顶] Android仿人人客户端(v5.7.1)——应用主界面之左侧面板UI实现
  11. CAD看图软件中如何将CAD图纸由天正T20版本转换为T3版本?
  12. 傲梅分区助手 linux,傲梅分区助手(详解磁盘操作)
  13. 最前线|库克:苹果正在考虑调整iPhone定价策略
  14. python3 把类似这样的 '\xe5\xae\x9d\xe9\xb8\xa1\xe5\xb8\x82' 转换成汉字
  15. Win7系统重装账户被禁用的解决方法
  16. Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)
  17. sql字符串和数字转换
  18. conda安装GPU版pytorch,结果却是cpu版本[找到问题根源,从容解决]
  19. 时间序列模型SCINet(代码解析)
  20. 结缘OpenStack:运营商NFV部署加速 要开源也要保障

热门文章

  1. Oracle 存储过程之通用分页查询
  2. 大失所望:第一次去苹果店“享受”维修服务的经历
  3. SpringOSGINoDM项目的插件说明
  4. python主辅线程_python主线程捕获子线程的方法
  5. tomcat环境变量参数catalina.home和catalina.base的设置位置
  6. 2021-01-24过去十年十大AI研究热点,分别为深度神经网络、特征抽取、图像分类、目标检测、语义分割、表示学习、生成对抗网络、语义网络、协同过滤和机器翻译。
  7. LSTM预测MNIST手写数字张量流图分析
  8. ECLIPSE 如何导入文件?
  9. 将jar deploy到私服nexus常见问题
  10. 社会工程学到底有多可怕