深度学习中的优化方法(Momentum,AdaGrad,RMSProp,Adam)详解及调用

深度学习中常用的优化方法包括啦momentum(动量法),Adagrad(adaptive gradient自适应梯度法),RMSProp(root mean square propagation均方根传播算法),Adam(adaptive moment estimation自适应矩估计法)

指数加权平均算法

所谓指数加权平均算法是上述优化算法的基础,其作用是对历史数据和当前数据进行加权求和,具体公式如下

if t==0:

v_0 = x_0

if t > 0

v_t = \beta v_{t-1} + (1 - \beta) x_t

其中

  • v_t为时间步t的加权平均值
  • v_{t-1}为为时间步t-1的加权平均值
  • x_t为时间步t的观测值
  • \beta为平滑因子,0 < \beta < 1

可以较为明显地看出,所谓指数加权平均算法的关键就在于\beta的大小,其越大,当前时间步的值就会越偏向过去的值,换句话说,整体数值序列就会更加平滑

指数加权平均算法的可视化

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
from numpy.array_api import linspace

torch.manual_seed(0)


def exponential_wma(data,beta=0.9):
    list1 = []
    for n,i in enumerate(data):
        if n ==0:
            list1.append(i)
        else:
            list1.append(beta * list1[n-1] + (1-beta) * i)
    return list1

if __name__ == '__main__':


    data = torch.randn(50)*10

    x = torch.linspace(1,50,50)

    fig = plt.figure()
    axes1 = plt.subplot(1,2,1)
    axes1.scatter(x,data)
    axes1.plot(x,data)
    axes1.set_xlabel('x')
    axes1.set_ylabel('y')
    axes1.set_title('original data')
    print(data)

    axes2 = plt.subplot(1,2,2)
    axes2.scatter(x,data,label='original_data')
    axes2.plot(x,exponential_wma(data),  label='ewma_curve')
    axes2.set_xlabel('x')
    axes2.set_ylabel('y')
    axes2.set_title('ewma')
    print(exponential_wma(data))
    axes2.legend()
    plt.subplots_adjust(wspace=0.4)
    fig.savefig('ewma.png')
    plt.show()

# tensor([-11.2584, -11.5236,  -2.5058,  -4.3388,   8.4871,   6.9201,  -3.1601,
#         -21.1522,   3.2227, -12.6333,   3.4998,   3.0813,   1.1984,  12.3766,
#          11.1678,  -2.4728, -13.5265, -16.9593,   5.6665,   7.9351,   5.9884,
#         -15.5510,  -3.4136,  18.5301,   7.5019,  -5.8550,  -1.7340,   1.8348,
#          13.8937,  15.8633,   9.4630,  -8.4368,  -6.1358,   0.3159,  10.5536,
#           1.7784,  -2.3034,  -3.9175,   5.4329,  -3.9516,   2.0553,  -4.5033,
#          15.2098,  34.1050, -15.3118, -12.3414,  18.1973,  -5.5153, -13.2533,
#           1.8855])
# [tensor(-11.2584), tensor(-11.2849), tensor(-10.4070), tensor(-9.8002), tensor(-7.9715), tensor(-6.4823), tensor(-6.1501), tensor(-7.6503), tensor(-6.5630), tensor(-7.1700), tensor(-6.1030), tensor(-5.1846), tensor(-4.5463), tensor(-2.8540), tensor(-1.4518), tensor(-1.5539), tensor(-2.7512), tensor(-4.1720), tensor(-3.1881), tensor(-2.0758), tensor(-1.2694), tensor(-2.6976), tensor(-2.7692), tensor(-0.6392), tensor(0.1749), tensor(-0.4281), tensor(-0.5587), tensor(-0.3193), tensor(1.1020), tensor(2.5781), tensor(3.2666), tensor(2.0962), tensor(1.2730), tensor(1.1773), tensor(2.1150), tensor(2.0813), tensor(1.6428), tensor(1.0868), tensor(1.5214), tensor(0.9741), tensor(1.0822), tensor(0.5237), tensor(1.9923), tensor(5.2036), tensor(3.1520), tensor(1.6027), tensor(3.2621), tensor(2.3844), tensor(0.8206), tensor(0.9271)]

这里设置的平滑因子为0.9,通常情况下使用动量法的时候平滑因子也会设置为0.9

平滑因子越大,理论上曲线就会越平滑

Momentum动量法

Momentum动量法的原理就是在梯度下降的时候使用指数加权平均法计算下降的梯度

动量更新方法如下

v_{t+1} = \beta v_t + (1 - \beta) \nabla_{\theta} J(\theta_t)

其中

  • v_{t+1}是动量项(累积的梯度),用于更新参数。
  • \beta 是动量系数(通常 0 < \beta < 1 ,例如  0.9 ),它决定了之前梯度对当前更新的影响程度。
  • v_t 是前一步的动量值。
  • \nabla_{\theta} J(\theta_t) 是当前时间步  t  计算得到的梯度。
  • \theta_t 是当前模型参数。

参数更新方法如下

\theta_{t+1} = \theta_t - \eta v_{t+1}

其中

  • \theta_{t+1}是更新后的参数。
  • \theta_t 是当前的参数。
  • \eta 是学习率。
  • v_{t+1} 是当前的动量项(累积梯度)。

动量法的调用

动量法的调用一般集成在SGD优化器中,通过设置SGD优化器中的momentum参数来配置,momentum参数的值就是动量系数(平滑因子)

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torch.optim as optim

model = nn.Linear(5, 1)
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
print(model)
print(optimizer)

# Linear(in_features=5, out_features=1, bias=True)
# SGD (
# Parameter Group 0
#     dampening: 0
#     differentiable: False
#     foreach: None
#     fused: None
#     lr: 0.001
#     maximize: False
#     momentum: 0.9
#     nesterov: False
#     weight_decay: 0
# )

AdaGrad自适应梯度

AdaGrad(自适应梯度法)的作用是随着训练的进行,对学习率进行逐步衰减

累计梯度平方和

G_t = G_{t-1} + g_t^2

其中

  • G_t 是参数梯度平方的累积和(是一个对角矩阵,表示每个参数的梯度平方和)。
  • g_t  是当前时间步  t  的梯度
  •  G_{t-1}  是前面所有时间步的梯度平方和

参数更新方式

\theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{G_t} + \epsilon} \cdot g_t

其中

  • \theta_t 是当前的参数
  • \eta  是全局的学习率
  • G_t 是梯度平方的累积和
  • \epsilon  是一个小常数,用于防止除以零,通常取值为  10^{-8}

自适应梯度法的调用

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(10, 100)
        self.fc2 = nn.Linear(100, 5)
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

if __name__ == '__main__':
    my_net = SimpleNet()
    optimizer = optim.Adagrad(my_net.parameters(), lr=0.01)
    print(my_net)
    print(optimizer)

# SimpleNet(
#   (fc1): Linear(in_features=10, out_features=100, bias=True)
#   (fc2): Linear(in_features=100, out_features=5, bias=True)
# )
# Adagrad (
# Parameter Group 0
#     differentiable: False
#     eps: 1e-10
#     foreach: None
#     fused: None
#     initial_accumulator_value: 0
#     lr: 0.01
#     lr_decay: 0
#     maximize: False
#     weight_decay: 0
# )

RMSProp均方根传播法

RMSProp均方根传播法是在Adagrad的基础上做了优化,由于Adagrad中的累计平方和,会导致学习率快速下降导致模型收敛变慢

所以RMSProp对累计平方和进行了优化,转为了加权平均算法

梯度平方的指数加权平均算法

E[g^2]t = \beta E[g^2]{t-1} + (1 - \beta) g_t^2

其中

  • E[g^2]_t  是梯度平方的指数加权移动平均值(即该参数梯度的平滑历史平方值)
  • \beta  是衰减系数(通常取值接近 1,例如 0.9 或 0.99)
  • g_t  是当前时刻  t  的梯度
  • E[g^2]_{t-1}  是前一时刻的梯度平方的指数加权移动平均

参数更新

\theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{E[g^2]_t + \epsilon}} \cdot g_t

其中

  • \theta_t  是当前的参数
  • \eta 是当前的学习率
  • E[g^2]_t 是梯度平方的指数加权移动平均
  • \epsilon  是一个小常数(通常取  10^{-8} ),用于防止除以零的情况

同时RMSProp也支持动量法用于记录历史梯度,但是与SGD中国的动量法有所不同

动量项 v_t 的更新

v_t = \beta v_{t-1} + \frac{\eta}{\sqrt{E[g^2]_t + \epsilon}} g_t

其中

  • v_t 是当前动量项
  • v_{t-1}  是前一时刻的动量项
  • \beta  是动量系数,通常接近 1(例如 0.9 或 0.99),表示过去动量的影响
  • \eta  是学习率
  • g_t 是当前的梯度
  • E[g^2]_t  是梯度平方的指数加权移动平均,用来动态调整每个参数的学习率

这里动量项的加入会使模型加快熟练

均方根传播法的调用

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(10, 100)
        self.fc2 = nn.Linear(100, 5)
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

if __name__ == '__main__':
    my_net = SimpleNet()
    optimizer = optim.RMSprop(my_net.parameters(), lr=0.01, alpha=0.99,momentum=0.9)
    print(my_net)
    print(optimizer)

# SimpleNet(
#   (fc1): Linear(in_features=10, out_features=100, bias=True)
#   (fc2): Linear(in_features=100, out_features=5, bias=True)
# )
# RMSprop (
# Parameter Group 0
#     alpha: 0.99
#     capturable: False
#     centered: False
#     differentiable: False
#     eps: 1e-08
#     foreach: None
#     lr: 0.01
#     maximize: False
#     momentum: 0.9
#     weight_decay: 0
# )

Adam自适应矩估计法

Adam自适应矩估计法,与RMSProp不同,其完整融合了Momentum和AdaGrad方法

一阶矩估计(动量)

  • m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t
  • m_t 是梯度的一阶矩的指数加权移动平均值(即动量)
  • \beta_1  是控制动量的衰减系数,通常取  0.9 
  • g_t  是当前时刻的梯度

二阶矩估计(梯度平方的指数加权移动平均)

  • v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2
  • v_t 是梯度平方的指数加权移动平均值(相当于 RMSProp 中的累积梯度平方)
  • \beta_2  是控制二阶矩的衰减系数,通常取  0.999 

一阶矩和二阶矩的偏差校正

由于一阶矩和二阶矩在初始化的时候,不具备前一时刻的动量,所以由于(1-衰减系数)的存在,刚开始的梯度下降幅度偏小,所以这里使用了偏差校正去放大一开始的下降幅度

  • \hat{m_t} = \frac{m_t}{1 - \beta_1^t}
  • \hat{v_t} = \frac{v_t}{1 - \beta_2^t}
  • \hat{m_t}  是一阶矩的偏差校正值
  • \hat{v_t}  是二阶矩的偏差校正值

参数更新

  • \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v_t}} + \epsilon} \hat{m_t}
  • \theta_t  是当前的参数
  • \eta  是学习率
  • \epsilon  是一个小常数,通常取  10^{-8} ,用于防止除以零的情况
  • \hat{m_t}  是偏差校正后的一阶矩
  • \hat{v_t}  是偏差校正后的二阶矩

参数设置说明

  • \beta_1  和  \beta_2 :分别控制一阶矩和二阶矩的衰减速率。通常推荐值为 \beta_1  = 0.9  和 \beta_2  = 0.999 
  • \epsilon :用于防止除以零的问题,保证数值稳定性,通常设置为  10^{-8} 
  • 学习率  \eta :这是 Adam 的全局学习率,通常设置为  0.001 
  • \beta_1^t  是  \beta_1  的  t  次方,随着迭代步数  t  的增加,\beta_1^t  趋近于 0,从而消除偏差

自适应矩估计法的调用

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(10, 100)
        self.fc2 = nn.Linear(100, 5)
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

if __name__ == '__main__':
    my_net = SimpleNet()
    optimizer = optim.Adam(my_net.parameters(), lr=0.01, betas=(0.9, 0.999), eps=1e-8)
    print(my_net)
    print(optimizer)

# SimpleNet(
#   (fc1): Linear(in_features=10, out_features=100, bias=True)
#   (fc2): Linear(in_features=100, out_features=5, bias=True)
# )
# Adam (
# Parameter Group 0
#     amsgrad: False
#     betas: (0.9, 0.999)
#     capturable: False
#     differentiable: False
#     eps: 1e-08
#     foreach: None
#     fused: None
#     lr: 0.01
#     maximize: False
#     weight_decay: 0
# )

补充

在以上四个优化器中,都支持配置weight_decay参数,其为正则化系数,添加后可以对模型添加L2正则

深度学习优化方法是指在训练神经网络时,通过更新模型参数来最小化损失函数的过程所采用的算法。常用的优化方法包括:momentum、Nesterov MomentumAdaGradAdadelta、RMSprop、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不仅收敛速度快,还具有较好的性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值