PyTorch不同优化器比较

打印 上一主题 下一主题

主题 1092|帖子 1092|积分 3276

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 
常见优化器介绍
 
- SGD(随机梯度降落):是最基本的优化器之一,通过在每次迭代中沿着损失函数的负梯度方向更新模型参数。在大规模数据集上计算服从高,对于凸问题和简单模型效果较好。但收敛速度慢,容易陷入局部最小值,对学习率的选择较为敏感,不合适的学习率可能导致训练无法收敛或收敛到较差的解。
- Adagrad:为每个参数自适应地调整学习率,根据参数的汗青梯度平方和来调整当前的学习率,使得在训练过程中,频繁更新的参数学习率逐渐减小,而不常更新的参数学习率相对较大,适合处置惩罚希奇数据。但学习率会逐渐低沉,导致训练后期学习非常慢,可能须要很长时间才能收敛。
- Adadelta:解决了Adagrad学习率逐渐低沉的问题,通过使用梯度平方的指数加权平均来代替全部梯度的平方和,动态地调整每个参数的学习率,不须要手动设置学习率。与Adam相比,在某些情况下收敛速度稍慢,但在一些特定场景中体现较好。
- RMSprop:与Adadelta类似,通过将学习率除以梯度平方的指数加权平均来调整学习率,计算上更为简洁,收敛速度较快,在处置惩罚非安稳目标时体现较好,常用于循环神经网络等。但与Adam类似,在某些情况下可能须要更精致的超参数调整。
- Adam:同时使用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率,一阶矩用来控制模型更新的方向,二阶矩控制步长,计算服从高,收敛速度快,自动调整学习率的特性使得它适用于大多数情况。但在某些情况下可能不如SGD及其变体具有好的泛化能力,须要调整超参数,如β1、β2、ε等。
- AdamW(带权重衰减的Adam):在Adam的底子上增加了权重衰减项,有助于正则化模型,防止过拟合,对于大型模型训练和容易过拟合的任务效果较好。与Adam类似,须要调整超参数。
- Adamax:是Adam的一种变体,将Adam的二范数(二阶矩估计)推广到无穷范数,具有更大的学习率范围和更好的稳固性。在某些情况下可能不如Adam或SGD体现得好,但在学习率选择较为困难时是一个不错的选择。
 
优化器比较实验
 
以下使用一个简单的线性回归模型在一个合成数据集上举行实验,对比不同优化器的收敛速度和性能。
 
import torch
import torch.optim as optim
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
 
# 天生合成数据集
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
y = x.pow(2) + 0.1 * torch.normal(torch.zeros(*x.size()))
 
# 定义线性回归模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.linear = nn.Linear(1, 1)
 
    def forward(self, x):
        return self.linear(x)
 
# 定义不同的优化器
net_SGD = Net()
net_Adagrad = Net()
net_Adadelta = Net()
net_RMSprop = Net()
net_Adam = Net()
net_AdamW = Net()
net_Adamax = Net()
 
opt_SGD = optim.SGD(net_SGD.parameters(), lr=0.01)
opt_Adagrad = optim.Adagrad(net_Adagrad.parameters(), lr=0.01)
opt_Adadelta = optim.Adadelta(net_Adadelta.parameters(), lr=0.01)
opt_RMSprop = optim.RMSprop(net_RMSprop.parameters(), lr=0.01, alpha=0.9)
opt_Adam = optim.Adam(net_Adam.parameters(), lr=0.001, betas=(0.9, 0.99))
opt_AdamW = optim.AdamW(net_AdamW.parameters(), lr=0.001, betas=(0.9, 0.99))
opt_Adamax = optim.Adamax(net_Adamax.parameters(), lr=0.001, betas=(0.9, 0.99))
 
# 训练模型并记录损失
losses_SGD = []
losses_Adagrad = []
losses_Adadelta = []
losses_RMSprop = []
losses_Adam = []
losses_AdamW = []
losses_Adamax = []
 
for epoch in range(100):
    # SGD
    optimizer_SGD.zero_grad()
    output_SGD = net_SGD(x)
    loss_SGD = nn.MSELoss()(output_SGD, y)
    loss_SGD.backward()
    optimizer_SGD.step()
    losses_SGD.append(loss_SGD.item())
 
    # Adagrad
    optimizer_Adagrad.zero_grad()
    output_Adagrad = net_Adagrad(x)
    loss_Adagrad = nn.MSELoss()(output_Adagrad, y)
    loss_Adagrad.backward()
    optimizer_Adagrad.step()
    losses_Adagrad.append(loss_Adagrad.item())
 
    # Adadelta
    optimizer_Adadelta.zero_grad()
    output_Adadelta = net_Adadelta(x)
    loss_Adadelta = nn.MSELoss()(output_Adadelta, y)
    loss_Adadelta.backward()
    optimizer_Adadelta.step()
    losses_Adadelta.append(loss_Adadelta.item())
 
    # RMSprop
    optimizer_RMSprop.zero_grad()
    output_RMSprop = net_RMSprop(x)
    loss_RMSprop = nn.MSELoss()(output_RMSprop, y)
    loss_RMSprop.backward()
    optimizer_RMSprop.step()
    losses_RMSprop.append(loss_RMSprop.item())
 
    # Adam
    optimizer_Adam.zero_grad()
    output_Adam = net_Adam(x)
    loss_Adam = nn.MSELoss()(output_Adam, y)
    loss_Adam.backward()
    optimizer_Adam.step()
    losses_Adam.append(loss_Adam.item())
 
    # AdamW
    optimizer_AdamW.zero_grad()
    output_AdamW = net_AdamW(x)
    loss_AdamW = nn.MSELoss()(output_AdamW, y)
    loss_AdamW.backward()
    optimizer_AdamW.step()
    losses_AdamW.append(loss_AdamW.item())
 
    # Adamax
    optimizer_Adamax.zero_grad()
    output_Adamax = net_Adamax(x)
    loss_Adamax = nn.MSELoss()(output_Adamax, y)
    loss_Adamax.backward()
    optimizer_Adamax.step()
    losses_Adamax.append(loss_Adamax.item())
 
# 绘制损失曲线
plt.plot(losses_SGD, label='SGD')
plt.plot(losses_Adagrad, label='Adagrad')
plt.plot(losses_Adadelta, label='Adadelta')
plt.plot(losses_RMSprop, label='RMSprop')
plt.plot(losses_Adam, label='Adam')
plt.plot(losses_AdamW, label='AdamW')
plt.plot(losses_Adamax, label='Adamax')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Comparison of PyTorch Optimizers')
plt.legend()
plt.show()
 
 
实验效果分析
 
- 收敛速度:在这个简单的实验中,Adam、RMSprop和Adamax在初期的收敛速度相对较快,能够在较少的迭代次数内使损失快速降落。而SGD的收敛速度相对较慢,须要更多的迭代次数才能到达类似的损失值。Adagrad在前期降落速度尚可,但由于学习率逐渐低沉,后期收敛速度明显变慢。Adadelta的收敛速度较为稳固,但整体相对Adam等稍慢。
- 稳固性:Adam、RMSprop和Adadelta在训练过程中相对稳固,损失值的颠簸较小。而SGD由于其随机性和对学习率的敏感性,损失值可能会出现较大的颠簸。Adagrad在后期由于学习率过小,可能会导致训练故步自封,出现不稳固的情况。AdamW在稳固性上与Adam类似,但由于参加了权重衰减,在一定程度上可以防止模型在后期过拟合而导致的不稳固。
- 泛化能力:一般来说,SGD及其变体在一些大规模的数据集和复杂模型上,假如调参得当,可能会具有较好的泛化能力。Adam等自适应学习率的优化器在大多数情况下能够快速收敛,但在某些特定的数据集和模型结构上,可能会出现过拟合的情况,导致泛化能力降落。不过,通过调整超参数和参加正则化项等方法,可以在一定程度上提高其泛化能力。
- 超参数调整:SGD通常须要手动调整学习率和其他超参数,如动量等,对超参数的选择较为敏感。Adagrad、Adadelta和RMSprop等虽然在一定程度上自动调整学习率,但也可能须要根据具体情况调整一些超参数。Adam、AdamW和Adamax须要调整的超参数相对较多,如β1、β2、ε等,但通常在默认值附近举行微调就可以取得较好的效果。
 
优化器损失曲线对比
 
根据上述实验和分析,在实际应用中,对于简单模型和大规模数据集,SGD可能是一个不错的选择,假如对收敛速度有要求,可以尝试使用动员量的SGD。对于复杂模型和须要自动调整学习率的情况,Adam、RMSprop等自适应学习率的优化器通常体现较好。假如担心过拟合,可以选择AdamW。在处置惩罚希奇数据时,Adagrad可能会更合适。而Adadelta和Adamax则在特定场景中可以举行尝试和探索。同时,不同的优化器在不同的数据集和模型结构上的体现可能会有所不同,须要根据具体情况举行实验和调整。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

种地

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表