PyTorch理解更多的神经网络优化方法

SGD
此处的SGD指mini-batch gradient descent,关于batch gradient descent, stochastic gradient descent, 以及 mini-batch gradient descent的具体区别就不细说了。现在的SGD一般都指mini-batch gradient descent。

SGD就是每一次迭代计算mini-batch的梯度,然后对参数进行更新,是最常见的优化方法了。即:
在这里插入图片描述
其中,η是学习率,gt是梯度
SGD完全依赖于当前batch的梯度,所以η可理解为允许当前batch的梯度多大程度影响参数更新。
缺点:
选择合适的learning rate比较困难
对所有的参数更新使用同样的learning rate。对于稀疏数据或者特征,有时我们可能想更新快一些对于不经常出现的特征,对于常出现的特征更新慢一些,这时候SGD就不太能满足要求了
SGD容易收敛到局部最优,在某些情况下可能被困在鞍点【但是在合适的初始化和学习率设置下,鞍点的影响其实没这么大】
Momentum
momentum是模拟物理里动量的概念,积累之前的动量来替代真正的梯度。公式如下: PyTorch理解更多的神经网络优化方法_第1张图片
其中,μ是动量因子
特点:

下降初期时,使用上一次参数更新,下降方向一致,乘上较大的μμ能够进行很好的加速
下降中后期时,在局部最小值来回震荡的时候,gradient→0gradient→0,μμ使得更新幅度增大,跳出陷阱
在梯度改变方向的时候,μμ能够减少更新
总而言之,momentum项能够在相关方向加速SGD,抑制振荡,从而加快收敛
RMSprop
RMSprop可以算作Adadelta的一个特例:
PyTorch理解更多的神经网络优化方法_第2张图片
特点:
其实RMSprop依然依赖于全局学习率
RMSprop适合处理非平稳目标
对于RNN效果很好
Adam
Adam(Adaptive Moment Estimation)本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。公式如下: PyTorch理解更多的神经网络优化方法_第3张图片
其中,mtmt,ntnt分别是对梯度的一阶矩估计和二阶矩估计,可以看作对期望E|gt|E|gt|,E|g2t|E|gt2|的估计;mtmt,ntnt是对mtmt,ntnt的校正,这样可以近似为对期望的无偏估计。
可以看出,直接对梯度的矩估计对内存没有额外的要求,而且可以根据梯度进行动态调整,而−mtnt√+ϵ−mtnt+ϵ对学习率形成一个动态约束,而且有明确的范围。
特点:

结合了Adagrad善于处理稀疏梯度和RMSprop善于处理非平稳目标的优点
对内存需求较小
为不同的参数计算不同的自适应学习率
也适用于大多非凸优化
适用于大数据集和高维空间

PyTorch 各种优化器选择
神经网络优化器,主要是为了优化我们的神经网络,使他在我们的训练过程中快起来,节省社交网络训练的时间。在pytorch中提供了torch.optim方法优化我们的神经网络,torch.optim是实现各种优化算法的包。最常用的方法都已经支持,接口很常规,所以以后也可以很容易地集成更复杂的方法
例如:

optimizer =  torch.optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)
optimizer =  torch.optim.Adam([var1, var2], lr = 0.0001)
# SGD 就是随机梯度下降
opt_SGD  = torch.optim.SGD(net_SGD.parameters(), lr=LR)
# momentum 动量加速,在SGD函数里指定momentum的值即可
opt_Momentum  = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
# RMSprop 指定参数alpha
opt_RMSprop     = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
# Adam 参数betas=(0.9, 0.99)
opt_Adam        = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))

采用SGD、Momentum、AdaGrad、RMSProp、Adam等来加快神经网络的训练过程

import torch
import torch.utils.data as Data
import torch.nn.functional as F
from torch.autograd import Variable
import matplotlib.pyplot as plt
 
# 超参数
LR = 0.01
BATCH_SIZE = 32
EPOCH = 12
 
# 生成假数据
# torch.unsqueeze() 的作用是将一维变二维,torch只能处理二维的数据
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)  # x data (tensor), shape(100, 1)
# 0.2 * torch.rand(x.size())增加噪点
y = x.pow(2) + 0.1 * torch.normal(torch.zeros(*x.size()))
 
# 输出数据图
plt.scatter(x.numpy(), y.numpy())
plt.show()

PyTorch理解更多的神经网络优化方法_第4张图片

torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)
class Net(torch.nn.Module):
    # 初始化
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(1, 20)
        self.predict = torch.nn.Linear(20, 1)
 
    # 前向传递
    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x
 
net_SGD = Net()
net_Momentum = Net()
net_RMSProp = Net()
net_Adam = Net()
 
nets = [net_SGD, net_Momentum, net_RMSProp, net_Adam]
 
opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
opt_RMSProp = torch.optim.RMSprop(net_RMSProp.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSProp, opt_Adam]
 
loss_func = torch.nn.MSELoss()
 
loss_his = [[], [], [], []]  # 记录损失
 
for epoch in range(EPOCH):
    print(epoch)
    for step, (batch_x, batch_y) in enumerate(loader):
        b_x = Variable(batch_x)
        b_y = Variable(batch_y)
 
        for net, opt,l_his in zip(nets, optimizers, loss_his):
            output = net(b_x)  # get output for every net
            loss = loss_func(output, b_y)  # compute loss for every net
            opt.zero_grad()  # clear gradients for next train
            loss.backward()  # backpropagation, compute gradients
            opt.step()  # apply gradients
            l_his.append(loss.data.numpy())  # loss recoder
labels = ['SGD', 'Momentum', 'RMSprop', 'Adam']
for i, l_his in enumerate(loss_his):
    plt.plot(l_his, label=labels[i])
plt.legend(loc='best')
plt.xlabel('Steps')
plt.ylabel('Loss')
plt.ylim((0, 0.2))
plt.show()

PyTorch理解更多的神经网络优化方法_第5张图片
参考:https://blog.csdn.net/u012759136/article/details/52302426
https://ptorch.com/news/54.html

你可能感兴趣的:(PyTorch理解更多的神经网络优化方法)