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

以下介绍深度学习的主要几种参数更新的优化方法 1.Adagrad 使得学习率η∑ti=0(g2i)√η∑i=0t(gi2) \frac{\eta}{\sqrt{\sum_{i=0}^t(g_i^2)}}可以自适应,对于出现频率较低参数采用较大的α更新;相反,对于出现频率较高的参数采用较小的α更新。因此,Adagrad非常适合处理稀疏数据。 wt+1←wt−η∑ti=0(g2i)+ε‾‾‾‾‾...
摘要由CSDN通过智能技术生成

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

核心代码:

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 σ 不会太大,也就使得模型后期依然能够找到比较优的结果
w 1 ← w 0 − η σ 0 + ε g 0    , σ 0 = g 0 w 2 ← w 1 − η σ 1 + ε g 1    , σ 1 = α ( σ 0 ) 2 + ( 1 − α ) ( g 1 ) 2 w 3 ← w 2 − η σ 2 + ε g 2    , σ 2 = α ( σ 1 ) 2 + ( 1 − α ) ( g 2 ) 2 . . . w t ← w t − 1 − η σ t − 1 + ε g t − 1    , σ t − 1 = α ( σ t − 2 ) 2 + ( 1 − α ) ( g t − 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

  • 7
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值