基于Pytorch实现深度学习优化算法(Adagrad/RmsProp/Momentum/Adam)

本文介绍了深度学习中常用的优化算法,包括Adagrad、RMSProp、Momentum和Adam,并通过Pytorch实现这些算法在MNIST数据集上的应用。Adagrad适合稀疏数据,但学习率会随训练递减。RMSProp通过指数衰减平均解决了Adagrad学习率过早衰减的问题。Momentum引入动量概念加速收敛,而Adam综合了RMSProp和Momentum的优点,具有更好的稳定性。文章提供了Pytorch内置优化器的使用示例,并对比了不同算法的训练效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下介绍深度学习的主要几种参数更新的优化方法
1.Adagrad
通过引入二阶动量vt=∑i=0t(gi2)v_t=\sqrt{\sum\limits_{i=0}^t(g_i^2)}vt=i=0t(gi2) 使得学习率ηvt\frac{\eta} {v_t}vtη的更新可以自适应的进行,对于出现频率较低(vt较小v_t较小vt)参数采用较大的α更新;相反,对于出现频率较高的参数采用较小的α更新。因此,Adagrad非常适合处理稀疏数据。
wt+1←wt−η∑i=0t(gi2)+εgtw_{t+1} \leftarrow w_t - \frac{\eta}{\sqrt{\sum_{i=0}^t(g_i^2)+\varepsilon}}g_twt+1wti=0t(gi2)+ε ηgt
这里的 ε\varepsilonε 是为了数值稳定性而加上的,因为初始时有可能 vtv_tvt 的值为 0,那么 0 出现在分母就会出现无穷大的情况,通常 ε\varepsilonε10−1010^{-10}1010 ,这样不同的参数由于梯度不同,得到的学习率也就不同,从而实现了自适应的学习率。但Adagrad有个缺点,其引入了二阶动量vt=∑i=0t(gi2)v_t=\sqrt{\sum\limits_{i=0}^t(g_i^2)}vt=i=0t(gi2) 的概念,由于vtv_tvt是单调递增的,所以学习率单调递减,而当学习率递减速度过快的时候可能就会导致模型没有完全收敛的情况下提前终止。

核心代码:

def sgd_adagrad(parameters, sqrs, lr):
    eps = 1e-10
    for param, sqr in zip(parameters, sqrs):
        sqr[:] = sqr + param.grad.data ** 2
        div = lr / torch.sqrt(sqr + eps) * param.grad.data
        param.data = param.data - div

以下栗子为采用Adagrad参数更新方法,利用pytorch实现简单的三层神经网络进行MNIST手写数据集的识别

import numpy as np
import torch
from torchvision.datasets import MNIST # 导入 pytorch 内置的 mnist 数据
from torch.utils.data import DataLoader
from torch import nn
from torch.autograd import Variable
import time
import matplotlib.pyplot as plt
%matplotlib inline

def data_tf(x):
    x = np.array(x, dtype='float32') / 255
    x = (x - 0.5) / 0.5 # 标准化,这个技巧之后会讲到
    x = x.reshape((-1,)) # 拉平
    x = torch.from_numpy(x)
    return x

train_set = MNIST('./data', train=True, transform=data_tf, download=True) # 载入数据集,申明定义的数据变换
test_set = MNIST('./data', train=False, transform=data_tf, download=True)

# 定义 loss 函数
criterion = nn.CrossEntropyLoss()
train_data = DataLoader(train_set, batch_size=64, shuffle=True)
# 使用 Sequential 定义 3 层神经网络
net = nn.Sequential(
    nn.Linear(784, 200),
    nn.ReLU(),
    nn.Linear(200, 10),
)

# 初始化梯度平方项
sqrs = []
for param in net.parameters():
    sqrs.append(torch.zeros_like(param.data))
    
# 开始训练
losses = []
idx = 0
start = time.time() # 记时开始
for e in range(5):
    train_loss = 0
    for im, label in train_data:
        im = Variable(im)
        label = Variable(label)
        # 前向传播
        out = net(im)
        loss = criterion(out, label)
        # 反向传播
        net.zero_grad()
        loss.backward()
        sgd_adagrad(net.parameters(), sqrs, 1e-2) # 学习率设为 0.01
        # 记录误差
        train_loss += loss.data[0]
        if idx % 30 == 0:
            losses.append(loss.data[0])
        idx += 1
    print('epoch: {}, Train Loss: {:.6f}'
          .format(e, train_loss / len(train_data)))
end = time.time() # 计时结束
print('使用时间: {:.5f} s'.format(end - start))epoch: 0, Train Loss: 0.406752
epoch: 1, Train Loss: 0.248588
epoch: 2, Train Loss: 0.211789
epoch: 3, Train Loss: 0.188928
epoch: 4, Train Loss: 0.172839
使用时间: 54.70610 s

运行的result如下所示:

epoch: 0, Train Loss: 0.406752
epoch: 1, Train Loss: 0.248588
epoch: 2, Train Loss: 0.211789
epoch: 3, Train Loss: 0.188928
epoch: 4, Train Loss: 0.172839
使用时间: 54.70610 s

以下为训练过程中的loss

x_axis = np.linspace(0, 5, len(losses), endpoint=True)
plt.semilogy(x_axis, losses, label='adagrad')
plt.legend(loc='best')

这里写图片描述
当然 pytorch 也内置了 adagrad 的优化算法,只需要调用 torch.optim.Adagrad() 就可以了,下面是例子

train_data = DataLoader(train_set, batch_size=64, shuffle=True)
# 使用 Sequential 定义 3 层神经网络
net = nn.Sequential(
    nn.Linear(784, 200),
    nn.ReLU(),
    nn.Linear(200, 10),
)
 
optimizer = torch.optim.Adagrad(net.parameters(), lr=1e-2)
# 开始训练

start = time.time() # 记时开始
for e in range(5):
    train_loss = 0
    for im, label in train_data:
        im = Variable(im)
        label = Variable(label)
        # 前向传播
        out = net(im)
        loss = criterion(out, label)
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        # 记录误差
        train_loss += loss.data[0]
    print('epoch: {}, Train Loss: {:.6f}'
          .format(e, train_loss / len(train_data)))
end = time.time() # 计时结束
print('使用时间: {:.5f} s'.format(end - start))

2.RMSProp
Adagrad会累加之前所有的梯度平方,而RMSprop这里 α 是一个移动平均的系数,也是因为这个系数,导致了 RMSProp 和 Adagrad 不同的地方,这个系数使得 RMSProp 更新到后期累加的梯度平方较小,从而保证 σ\sigmaσ 不会太大,也就使得模型后期依然能够找到比较优的结果
w1←w0−ησ0+εg0  ,σ0=g0w2←w1−ησ1+εg1  ,σ1=α(σ0)2+(1−α)(g1)2w3←w2−ησ2+εg2  ,σ2=α(σ1)2+(1−α)(g2)2...wt←wt−1−ησt−1+εgt−1  ,σt−1=α(σt−2)2+(1−α)(gt−1)2 w_1 \leftarrow w_0 - \frac{\eta}{\sqrt{\sigma_0+\varepsilon}}g_0\;,\sigma_0=g_0\\ w_2 \leftarrow w_1 - \frac{\eta}{\sqrt{\sigma_1+\varepsilon}}g_1\;,\sigma_1={\alpha(\sigma_0)^2+(1-\alpha)(g_1)^2}\\ w_3 \leftarrow w_2 - \frac{\eta}{\sqrt{\sigma_2+\varepsilon}}g_2\;,\sigma_2={\alpha(\sigma_1)^2+(1-\alpha)(g_2)^2}\\ ...\\ w_t \leftarrow w_{t-1} - \frac{\eta}{\sqrt{\sigma_{t-1}+\varepsilon}}g_{t-1}\;,\sigma_{t-1}={\alpha(\sigma_{t-2})^2+(1-\alpha)(g_t-1)^2}\\ w1w0σ0+ε ηg0,σ

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值