Momentum、Adagrad、RMSprop、Adadelta、Adam【详细公式总结对比、pytorch实现】

先放一张公式汇总图:
在这里插入图片描述

1 Momentum动量优化算法

1.1 梯度下降的问题

    SGD方法的一个缺点是其更新方向完全依赖于当前batch计算出的梯度,因而十分不稳定。下图显示了在优化过程中x2方向的变化量远大于x1方向上的。

%matplotlib inline
import sys
sys.path.append("..") 
import d2lzh_pytorch as d2l
import torch

eta = 0.4 # 学习率

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

def gd_2d(x1, x2, s1, s2):
    return (x1 - eta * 0.2 * x1, x2 - eta * 4 * x2, 0, 0)

d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
epoch 20, x1 -0.943467, x2 -0.000073

在这里插入图片描述

# 略微增大学习率,x2方向已发散
eta=0.6
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
epoch 20, x1 -0.387814, x2 -1673.365109

在这里插入图片描述

1.2 动量法

    Momentum算法借用了物理中的动量概念,使得参数更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向。

在这里插入图片描述
其中,动量超参数γ满足0≤γ<1。当γ=0时,动量法等价于小批量随机梯度下降。

def momentum_2d(x1, x2, v1, v2):
    v1 = gamma * v1 +eta * 0.2*x1
    v2 = gamma * v2 +eta * 4*x2
    return x1-v1, x2-v2, v1, v2

eta, gamma = 0.4, 0.5
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
epoch 20, x1 -0.062843, x2 0.001202

在这里插入图片描述

# 可以看到,在lr = 0.6时,使用动量法后x2方向不再发散
eta=0.6
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
epoch 20, x1 0.007188, x2 0.002553

在这里插入图片描述

features, labels = d2l.get_data_ch7()
def init_momentum_states():
    v_w = torch.zeros((features.shape[-1],1 ),dtype = torch.float32)
    v_b = torch.zeros(1,dtype = torch.float32)
    return (v_w, v_b)

def sgd_momentum(params, states, hyperparams):
    for p, v in zip(params, states):
        v.data = hyperparams['momentum'] * v.data+hyperparams['lr']*p.grad.data
        p.data -= v.data
d2l.train_ch7(sgd_momentum,init_momentum_states(), {'lr':0.02, 'momentum': 0.5 }, features, labels )
loss: 0.243766, 0.113696 sec per epoch

在这里插入图片描述

d2l.train_ch7(sgd_momentum,init_momentum_states(), {'lr':0.02, 'momentum': 0.9 }, features, labels )
loss: 0.257525, 0.084765 sec per epoch

在这里插入图片描述

d2l.train_ch7(sgd_momentum,init_momentum_states(), {'lr':0.004, 'momentum': 0.9 }, features, labels )
loss: 0.246566, 0.081785 sec per epoch

在这里插入图片描述

1.3 动量法的简洁实现

# 在PyTorch中,只需要通过参数momentum来指定动量超参数即可使用动量法。
d2l.train_pytorch_ch7(torch.optim.SGD, {'lr':0.004, 'momentum': 0.9 }, features, labels )
loss: 0.242601, 0.087179 sec per epoch

在这里插入图片描述

2 ADAGRA算法

2.1 算法简介

    AdaGrad算法根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。
    Adagrad算法能够在训练中自动的对learning rate进行调整,对于出现频率较低参数采用较大的α更新;相反,对于出现频率较高的参数采用较小的α更新。因此,Adagrad非常适合处理稀疏数据。

在这里插入图片描述在这里插入图片描述     AdaGrad算法在迭代过程中不断调整学习率,并让目标函数自变量中每个元素都分别拥有自己的学习率。使用AdaGrad算法时,自变量中每个元素的学习率在迭代过程中一直在降低。

%matplotlib inline
import math
import torch
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l

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

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

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

在这里插入图片描述

# 将学习率增大到2, 自变量更为迅速地逼近了最优解
eta = 2
d2l.show_trace_2d(f_2d, d2l.train_2d(adagrad_2d))
epoch 20, x1 -0.002295, x2 -0.000000

在这里插入图片描述

2.2 从零开始实现

# 根据AdaGrad算法中的公式实现该算法
features, labels = d2l.get_data_ch7()
def init_adagrad_states():
    s_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    s_b = torch.zeros(1, dtype = torch.float32)
    return (s_w, s_b)

def adagrad(params, states, hyperparams):
    eps = 1e-6
    for p, s in zip(params, states):
        s.data +=(p.grad.data**2)
        p.data -= hyperparams['lr'] * p.grad.data / torch.sqrt(s + eps)
    
d2l.train_ch7(adagrad, init_adagrad_states(), {'lr':0.1}, features, labels)  
loss: 0.243151, 0.089867 sec per epoch

在这里插入图片描述

2.3ADAGRAD简洁实现

# pytorch中提供名为Adagrad的优化器
d2l.train_pytorch_ch7(torch.optim.Adagrad, {'lr': 0.1}, features, labels)
loss: 0.243228, 0.133283 sec per epoch

在这里插入图片描述

3 RMSprop算法

3.1 算法简介

    不同于AdaGrad算法里状态变量st是截至时间步t所有小批量随机梯度gt按元素平方和,RMSProp算法将梯度 按元素平方做指数加权移动平均,因此可缓解Adagrad算法学习率下降较快的问题。

在这里插入图片描述在这里插入图片描述

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

def f_2d(x1, x2):
    return 0.1*x1**2+2*x2**2
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

在这里插入图片描述

3.2 从零开始实现

按照RMSProp算法中的公式实现该算法

features, labels = d2l.get_data_ch7()
def init_rmsprop_states():
    s_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    s_b = torch.zeros(1, dtype = torch.float32)
    return (s_w, s_b)

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

d2l.train_ch7(rmeprop, init_rmsprop_states(), {'lr':0.01, 'gamma':0.9}, features, labels)
loss: 0.242842, 0.127647 sec per epoch

在这里插入图片描述

3.3 RMSprop简洁实现

# pytorch中提供名为RMSprop的优化器
d2l.train_pytorch_ch7(torch.optim.RMSprop, {'lr': 0.01, 'alpha':0.9}, features, labels)
loss: 0.243309, 0.129653 sec per epoch

在这里插入图片描述

4 AdaDelta优化算法

4.1 算法简介

    AdaDelta算法没有学习率这一超参数;
    AdaDelta算法也像RMSProp算法一样,使用了 小批量随机梯度gt按元素平方的指数加权移动平均变量st。在时间步t=0,它的所有元素被初始化为0。给定超参数0≤ρ<1(对应RMSProp算法中的γ),在时间步t>0,同RMSProp算法一样计算
在这里插入图片描述
    与RMSProp算法不同的是,AdaDelta算法还维护一个额外的状态变量Δxt,其元素同样在时间步0时被初始化为0。我们使用Δxt−1来计算自变量的变化量:
在这里插入图片描述
    其中ϵ是为了维持数值稳定性而添加的常数,如10−5。接着更新自变量:
在这里插入图片描述
    最后,我们使用Δxt来记录自变量变化量g′t按元素平方的指数加权移动平均
在这里插入图片描述
    可以看到,如不考虑ϵ的影响,AdaDelta算法跟RMSProp算法的不同之处在于 使用√ Δx t−1来替代学习率η

4.2 从零开始实现

# 按AdaDelta算法中的公式实现该算法。
features, labels = d2l.get_data_ch7()
def init_adadelta_states():
    s_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    s_b = torch.zeros(1, dtype = torch.float32)    
    delta_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    delta_b = torch.zeros(1, dtype = torch.float32)
    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.data + (1-rho) * (p.grad.data**2)
        g = p.grad.data * torch.sqrt((delta+eps)/(s+eps))
        p.data -= g
        delta[:] = rho*delta + (1-rho) * g**2  
        
d2l.train_ch7(adadelta, init_adadelta_states(), {'rho':0.9}, features, labels)
loss: 0.242433, 0.185503 sec per epoch

在这里插入图片描述

4.3 AdaDelta的简洁实现

d2l.train_pytorch_ch7(torch.optim.Adadelta, { 'rho':0.9}, features, labels)
loss: 0.270904, 0.110704 sec per epoch

在这里插入图片描述

5 ADAM优化算法

5.1 算法简介

   Adam(Adaptive Moment Estimation)是另一种自适应学习率的方法,它在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均,所以Adam算法可以看做是RMSProp算法与动量法的结合。

   Adam算法还使用了偏差修正
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

5.2 从零开始实现

# 按照Adam算法中的公式实现该算法。其中时间步t通过hyperparams参数传入adam函数

features, labels = d2l.get_data_ch7()

def init_adam_states():
    v_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    v_b = torch.zeros(1, dtype = torch.float32)
    s_w = torch.zeros((features.shape[1], 1), dtype = torch.float32)
    s_b = torch.zeros(1, dtype = torch.float32)
    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.data
        s[:] = beta2 * s + (1-beta2) * (p.grad.data**2)
        v_bias_corr = v / (1-beta1**hyperparams['t'])
        s_bias_corr = s / (1-beta2**hyperparams['t'])
        g = hyperparams['lr'] * v_bias_corr / (torch.sqrt(s_bias_corr) + eps)
        p.data -= g
        
    hyperparams['t'] += 1
        
d2l.train_ch7(adam, init_adam_states(), {'lr':0.01, 't':1}, features, labels)
loss: 0.244003, 0.170542 sec per epoch

在这里插入图片描述

5.3 Adam简洁实现

d2l.train_pytorch_ch7(torch.optim.Adam, {'lr':0.01}, features, labels)
loss: 0.244895, 0.135288 sec per epoch

在这里插入图片描述

最后通过两张动图从直观上展现算法的优化过程:

1、下图为不同算法在损失平面等高线上随时间的变化情况:

不同算法在损失平面等高线上随时间的变化情况
2、下图为不同算法在鞍点处的行为比较:
不同算法在鞍点处的行为比较
动图参考来源点击这里
参考原文:《动手学深度学习(pyTorch)》

欢迎关注【OAOA

深度学习中的优化方法是指在训练神经网络时,通过更新模型参数来最小化损失函数的过程中所采用的算法。常用的优化方法包括:momentum、Nesterov MomentumAdaGradAdadeltaRMSprop、Adam等。 1. Momentum Momentum是一种基于梯度下降的优化方法,它通过引入动量来加速收敛。在更新模型参数时,不仅考虑当前的梯度,还考虑之前的梯度对更新方向的影响,通过累积之前的梯度,使得更新方向更加稳定,加速收敛。 2. Nesterov Momentum Nesterov MomentumMomentum的一种变体,它在更新模型参数之前,先向前“看一步”,计算模型参数在当前动量下的移动方向,然后再计算当前位置的梯度,最后根据这两个信息来更新模型参数。相比于Momentum,Nesterov Momentum能够更快地收敛。 3. AdaGrad AdaGrad是一种自适应学习率的优化方法,它通过动态地调整学习率来适应不同参数的更新需求。具体地说,它将学习率分别应用于每个参数的更新量上,使得每个参数的学习率随着训练的进行不断减小,从而减少参数更新的震荡。 4. Adadelta Adadelta也是一种自适应学习率的优化方法,它和AdaGrad不同之处在于,它不仅考虑了过去的梯度信息,还考虑了过去的参数更新信息。具体地说,它通过维护一个累积梯度平方的指数衰减平均值和一个累积参数更新平方的指数衰减平均值,来动态调整学习率和更新量,使得参数更新更加平稳。 5. RMSprop RMSprop也是一种自适应学习率的优化方法,它和Adadelta类似,但只考虑了过去的梯度信息,没有考虑过去的参数更新信息。具体地说,它通过维护一个梯度平方的指数衰减平均值来动态调整学习率,使得参数更新更加平稳。 6. Adam Adam是一种结合了MomentumRMSprop的优化方法,它不仅考虑了梯度的一阶矩和二阶矩信息,还引入了偏置修正,使得参数更新更加准确。相比于其他优化方法,Adam不仅收敛速度快,还具有较好的性能表现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值