当前位置: 首页 > news >正文

深度学习梯度下降优化算法(AdaGrad、RMSProp、AdaDelta、Adam)(MXNet)

在深度学习优化算法之动量法[公式推导](MXNet)中,动量法因为使用了指数加权移动平均,解决了自变量更新方向不一致的问题。动量法由于每个元素都使用了相同的学习率来做迭代,这也导致另外一个问题:如果x1和x2的梯度值有较大差别,那就会选择一个比较小的学习率,确保自变量在梯度值较大的维度不被发散,但是这造成了自变量在梯度值较小的维度上迭代过慢,下面的几个优化算法就是针对这个问题做的改进。

AdaGrad算法

动量法使用同一学习率带来的问题,我们采用AdaGrad算法,可以根据自变量在不同维度使用不同的学习率,避免用同样的学习率而难以适应所有维度的问题。x_{1}\leftarrow x_{1}-\eta \frac{\alpha f}{\alpha x_{1}}\: \:\, \, \, \, x_{2}\leftarrow x_{2}-\eta \frac{\alpha f}{\alpha x_{2}} 可以看出以前的每个元素都使用相同的学习率。现在我们把学习率在不同维度根据梯度来做调整,数学公式:

 s_{t}\leftarrow s_{t-1}+g_{t}^{2} (将小批量梯度g按元素平方累加到变量s)

x_{t}\leftarrow x_{t-1}-\frac{\eta }{\sqrt{s_{t}+\varepsilon }}\otimes g_{t} (这个学习率η就会根据上面s的变量的改变而改变)
从公式来看,各维度多出了一个s_{t}的累加变量(梯度的平方的累加),学习率相当于是除以了这个累加变量的开方的一个值,换句话说就是每个维度的学习率不同且不断变化着的。

代码: 

import d2lzh as d2l
from mxnet import nd
import math

def f_2d(x1,x2):
    return 0.1*x1**2 + 2*x2**2

def  adagrad_2d(x1,x2,s1,s2):
    g1,g2,eps=0.2*x1,4*x2,1e-6
    s1+=g1**2
    s2+=g2**2
    x1-=eta/math.sqrt(s1+eps)*g1
    x2-=eta/math.sqrt(s2+eps)*g2
    return x1,x2,s1,s2

eta=0.4
d2l.show_trace_2d(f_2d,d2l.train_2d(adagrad_2d))
#epoch 20, x1 -2.382563, x2 -0.158591

 

我们发现没有到达这个最优解的附近,原因是,这个累加的自变量作为分母,使得这个学习率是一直在下降(或不变),也就是说迭代到了后期如果没有找到最优解,那就比较难以找到了,这个时候我们调大学习率eta=2看下:

 

 我们发现可以很快的逼近到最优解。

飞机机翼噪音测试

#https://download.csdn.net/download/weixin_41896770/86513479
import d2lzh as d2l
from mxnet import nd
import math

features,labels=d2l.get_data_ch7()

def init_adagrad_states():
    s_w=nd.zeros((features.shape[1],1))
    s_b=nd.zeros(1)
    return s_w,s_b

def adagrad(params,states,hyperparams):
    eps=1e-6
    for p,s in zip(params,states):
        s[:]+=p.grad.square()
        p[:]-=hyperparams['lr']/(s+eps).sqrt() * p.grad

d2l.train_ch7(adagrad,init_adagrad_states(),{'lr':0.1},features,labels)
#loss: 0.243906, 0.197325 sec per epoch

#简洁实现
d2l.train_gluon_ch7('adagrad',{'learning_rate':0.1},features,labels)

RMSProp算法

上面的AdaGrad存在自变量每个元素的学习率在迭代过程中会一直降低(或不变),如果没有及时找到最优解,后面就比较难以找到的问题,RMSProp做了一点修改,使用了指数加权移动平均的做法。

数学公式:

s_{t}\leftarrow \gamma s_{t-1} +(1-\gamma )g_{t}^{2}\, \, \, \, \, \, \, \, \, x_{t}\leftarrow x_{t-1}-\frac{\eta }{\sqrt{s_{t}+\varepsilon }}\otimes g_{t}

s这个累加自变量,是对梯度的平方做指数加权移动平均,这样一来,自变量的每个元素的学习率在迭代过程中就不再一直降低(或不变)

代码: 

import d2lzh as d2l
from mxnet import nd
import math

def f_2d(x1,x2):
    return 0.1*x1**2 +2*x2**2

def rmsprop_2d(x1,x2,s1,s2):
    g1,g2,eps=0.2*x1,4*x2,1e-6
    s1=gamma*s1 + (1-gamma)*g1**2
    s2=gamma*s2 + (1-gamma)*g2**2
    x1-=eta/math.sqrt(s1+eps)*g1
    x2-=eta/math.sqrt(s2+eps)*g2
    return x1,x2,s1,s2

eta,gamma=0.4,0.9
d2l.show_trace_2d(f_2d,d2l.train_2d(rmsprop_2d))
#epoch 20, x1 -0.010599, x2 0.000000

 

 

图中可以看出这个算法能够快速的逼近最优解,解决了AdaGrad学习率不断减小,使得后期找不到最优解的问题。

飞机机翼噪音测试

import d2lzh as d2l
from mxnet import nd
import math

#如果想知道某个函数的源码,比如:print(d2l.get_data_ch7.__code__)
#将显示这个函数所在文件的目录地址,打开查看即可
features,labels=d2l.get_data_ch7()

def init_rmsprop_states():
    s_w=nd.zeros((features.shape[1],1))
    s_b=nd.zeros(1)
    return (s_w,s_b)
    
def rmsprop(params,states,hyperparams):
    gamma,eps=hyperparams['gamma'],1e-6
    for p,s in zip(params,states):
        s[:]=gamma*s + (1-gamma)*p.grad.square()
        p[:]-=hyperparams['lr']/(s+eps).sqrt() * p.grad

d2l.train_ch7(rmsprop,init_rmsprop_states(),{'lr':0.01,'gamma':0.9},features,labels)
#loss: 0.242604, 0.246025 sec per epoch

#简洁实现
d2l.train_gluon_ch7('rmsprop',{'learning_rate':0.01,'gamma1':0.9},features,labels)

AdaDelta算法

AdaDelta算法也是针对AdaGrad算法在迭代后期很难找最优解的问题做的改进,我们来看下数学公式:

s_{t}\leftarrow \rho s_{t-1} + (1-\rho)g_{t}^{2} (这个s自变量跟RMSProp算法一样)

{g_{t}}'\leftarrow \sqrt{\frac{\Delta x_{t-1}+\varepsilon }{s_{t}+\varepsilon }}\otimes g_{t}\, \, \, \, \, \,\, \, \, \, \, x_{t}\leftarrow x_{t-1}-{g_{t}}'\, \, \, \, \, \, \, \, \, \, \, \, \, \, \Delta x_{t}\leftarrow \rho\Delta x_{t-1}+(1-\rho){g_{t}}'^{2}

可以看到跟RMSProp算法比较,没有了η学习率,多出一个\Delta x_{t}的状态变量,其中这个\Delta x_{t}是对自变量{g_{t}}'的平方做指数加权移动平均,可以将\sqrt{\Delta x_{t-1}+\varepsilon }看做是η学习率。 

代码:

import d2lzh as d2l
from mxnet import nd
import math

#如果想知道某个函数的源码,比如:print(d2l.get_data_ch7.__code__)
#将显示这个函数所在文件的目录地址,打开查看即可
features,labels=d2l.get_data_ch7()

def init_adadelta_states():
    s_w,s_b=nd.zeros((features.shape[1],1)),nd.zeros(1)
    delta_w,delta_b=nd.zeros((features.shape[1],1)),nd.zeros(1)
    return ((s_w,delta_w),(s_b,delta_b))

def adadelta(params,states,hyperparams):
    rho,eps=hyperparams['rho'],1e-5
    for p,(s,delta) in zip(params,states):
        s[:]=rho*s + (1-rho)*p.grad.square()
        g=(((delta+eps)/(s+eps)).sqrt()) * p.grad
        p[:]-=g
        delta[:]=rho*delta + (1-rho)*(g**2)

rho=0.9

d2l.train_ch7(adadelta,init_adadelta_states(),{'rho':0.9},features,labels)
#loss: 0.243291, 0.279038 sec per epoch

#简洁实现
d2l.train_gluon_ch7('adadelta',{'rho':0.9},features,labels)

Adam算法(动量法+RMSProp)

Adam是一个用途很广泛很有用处的优化算法,有兴趣的可以看原论文:ADAM: A METHOD FOR STOCHASTIC OPTIMIZATION
论文中说明这个算法是结合了AdaGrad和RMSProp的优点,AdaGrad在稀疏梯度上表现很好,RMSProp在在线(on-line)和非平稳(non-stationary)目标函数上表现很好,上述的这两种算法也是很流行的。
另外也可以看作是在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均,结合了动量法的一种变体。
Adam算法有如下一些优点:

1、占用内存小
2、参数更新的幅度不会随着梯度的重缩放(rescaling)改变
3、对目标函数要求不高,可以是非稳定的
4、同AdaGrad一样可以处理稀疏梯度(sparse gradient)\beta_{1}
5、可以自然地执行步长退火的形式(a form of step size annealing),了解退火算法的伙伴们知道这可能可以得到全局最优解而不仅是局部最优解。
6、能很好的适配非凸优化问题(non convex optimization)

数学公式:

 v_{t}\leftarrow \beta _{1}v_{t-1}+(1-\beta_{1})g_{t}\; \; \; \; \; \; \; \; \; \; s_{t}\leftarrow \beta_{2}s_{t-1}+(1-\beta_{2})g_{t}^{2}

\hat{v}_{t}\leftarrow \frac{v_{t}}{1-\beta_{1}^{t}}\; \; \; \; \; \; \; \; \; \; \hat{s}_{t}\leftarrow \frac{s_{t}}{1-\beta_{2}^{t}}  (偏差修正)

x_{t}\leftarrow x_{t-1}-\frac{\eta \hat{v}_{t}}{\sqrt{\hat{s}_{t}}+\varepsilon }

当t较小时,过去各时间步小批量随机梯度权值之和会较小,例如,当\beta_{1}=0.9时,v_{1}=0.1g_{1},为了消除这样的影响,对于任意时间步t,我们可以将v_{t}再除以1-\beta_{1}^{t},从而使过去各时间步小批量随机梯度权值之和为1,这种操作叫做偏差修正。

代码:

import d2lzh as d2l
from mxnet import nd
import math

#如果想知道某个函数的源码,比如:print(d2l.get_data_ch7.__code__)
#将显示这个函数所在文件的目录地址,打开查看即可
features,labels=d2l.get_data_ch7()

def init_adam_states():
    v_w,v_b=nd.zeros((features.shape[1],1)),nd.zeros(1)
    s_w,s_b=nd.zeros((features.shape[1],1)),nd.zeros(1)
    return ((v_w,s_w),(v_b,s_b))

def adam(params,states,hyperparams):
    beta1,beta2,eps=0.9,0.999,1e-6
    for p,(v,s) in zip(params,states):
        v[:]=beta1*v + (1-beta1)*p.grad
        s[:]=beta2*s + (1-beta2)*p.grad.square()
        v_bias_corr=v/(1 - beta1**hyperparams['t'])
        s_bias_corr=s/(1 - beta2**hyperparams['t'])
        p[:]-=hyperparams['lr']*v_bias_corr / (s_bias_corr.sqrt()+eps)
    hyperparams['t']+=1

d2l.train_ch7(adam,init_adam_states(),{'lr':0.01,'t':1},features,labels)
#loss: 0.243235, 0.283553 sec per epoch

#简洁实现
d2l.train_gluon_ch7('adam',{'learning_rate':0.01},features,labels)

相关文章:

  • 2022 最新的 Java 八股文合集来了,彻底解决各大大厂面试难题
  • 【SSM框架】Mybatis详解11(源码自取)之事务,缓存,ORM
  • Maven 基本使用及依赖管理。
  • 数组是内存的实现及栈和队列的数据结构
  • 记录:2022-9-30 打家劫舍 二叉搜索树中第K小的元素 公平锁 磁盘调度
  • 基于html宠物用品商城项目的设计与实现(学生网页设计作业源码)
  • 【Java复习】线程安全的 HashMap --- ConcurrentHashMap
  • 《文化相对论》:危机重重的世界,对话才能产生转机
  • 水溶性CuInS/ZnS 量子点 PL 550 nm--800 nm
  • Vue3和react状态管理之Redux与Pinia的使用比较
  • 新学期如何克服“社恐”,猿辅导老师给高中生三条建议
  • 浅析各种主流区块链共识算法的利与弊
  • [架构之路-16]:目标系统 - 硬件平台 - CPU主要物理性能指标
  • 【JAVASE】JDK8新特性
  • 【0121】建立与postgres后端的连接(2)
  • Android组件 - 收藏集 - 掘金
  • AngularJS指令开发(1)——参数详解
  • HTTP中GET与POST的区别 99%的错误认识
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • js数组之filter
  • MySQL QA
  • pdf文件如何在线转换为jpg图片
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 让你的分享飞起来——极光推出社会化分享组件
  • 我的业余项目总结
  • 系统认识JavaScript正则表达式
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 带你开发类似Pokemon Go的AR游戏
  • ​Spring Boot 分片上传文件
  • #14vue3生成表单并跳转到外部地址的方式
  • $().each和$.each的区别
  • $NOIp2018$劝退记
  • (1)Nginx简介和安装教程
  • (2022 CVPR) Unbiased Teacher v2
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (二)windows配置JDK环境
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (算法)Travel Information Center
  • (五)关系数据库标准语言SQL
  • (学习日记)2024.01.19
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • *1 计算机基础和操作系统基础及几大协议
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .Net 应用中使用dot trace进行性能诊断
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .Net7 环境安装配置
  • .net反编译工具
  • .net访问oracle数据库性能问题
  • .NET连接MongoDB数据库实例教程
  • .net通用权限框架B/S (三)--MODEL层(2)
  • .Net中的设计模式——Factory Method模式
  • .pop ----remove 删除
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • @Transactional 详解