要点

几种优化器的讲解,请看莫烦的讲解(SGD,Momentum,RMSprop,Adam) 这一篇主要讲解 SGD,Momentum,RMSprop,Adam的实战

下图就是这节内容对比各种优化器的效果:

pytorch adamw优化器参数设置_机器学习

伪数据

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 #训练集中的全部样本都在训练模型中走了一遍,并返回一次(有去有回),为一个epoch。

# torch.unsqueeze 对数据维度进行扩充。dim=1给第2个位置加上维数为一的维度
x = torch.unsqueeze(torch.linspace(-1,1,1000),dim=1)
y = x.pow(2) + 0.1*torch.normal(torch.zeros(x.size()))

# 创建数据集
# batch_size设置为5
# shuffle=True每一次epoch打乱数据顺序,False代表每次epoch的数据顺序是一样的
# num_workers= 2使用2个子进程
# batchsize:简单点说,就是我们一次要将多少个数据扔进模型去训练,这个值介于1和训练样本总个数之间。
torch_dataset = Data.TensorDataset(x,y)
loader = Data.DataLoader(
    dataset=torch_dataset,
    batch_size=BATCH_SIZE,
    shuffle=True,
    num_workers=2
)

最开始需要定义3个参数
LR = 0.01 学习率定为0.01
BATCH_SIZE = 32 这是批处理的数量,表示一次要将32个数据扔进模型去训练
EPOCH = 12 这里表示全部样本都在训练模型中走了12遍,并返回12次(有去有回)

x = torch.unsqueeze(torch.linspace(-1,1,1000),dim=1)
torch.linspace这个表示从-1到1被分为1000个等距离的数据torch.unsqueeze 对数据维度进行扩充。dim=1给第2个位置加上维数为一的维度

y = x.pow(2) + 0.1torch.normal(torch.zeros(x.size()))*
torch.normal表示里离散正态分布,目的是产生干扰数据

torch_dataset = Data.TensorDataset(x,y)
这里表示创建tensor的数据集

loader = Data.DataLoader(
dataset=torch_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=2
)
这里的信息量稍微大了一点
DataLoader 是一个迭代器,方便我们去多线程地读取数据
batch_size 设置为5
shuffle=True 每一次epoch打乱数据顺序,False代表每次epoch的数据顺序是一样的
num_workers= 2 使用2个子进程

每个优化器优化一个神经网络

为了对比每一种优化器, 我们给他们各自创建一个神经网络, 但这个神经网络都来自同一个 Net 形式.

#定义4个不同的神经网络,这四个神经网络使用不同的优化器优化
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()

# 将四个不同的神经网络放在一起,使用for循环将其提取出来
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]

上面的代码定义了四个神经网络,然后把这四个神经网络放在一个nets中

优化器 Optimizer

接下来在创建不同的优化器, 用来训练不同的网络. 并创建一个 loss_func 用来计算误差. 我们用几种常见的优化器, SGD, Momentum, RMSprop, 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_Adam.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()
# 误差记录
losses_his = [[],[],[],[]]

训练/出图

接下来训练和 loss 画图.

#训练集中的全部样本都在训练模型中走了一遍,并返回一次(有去有回),为一个epoch。
for epoch in range(EPOCH):
    print(epoch)
    for step, (batch_x,batch_y) in enumerate(loader):
        #要把传入的数据从tensor的形式转化为variavle
        b_x = Variable(batch_x)
        b_y = Variable(batch_y)
        
        #把不同的神经网络一个个拿出来训练
        for net, opt, l_his in zip(nets, optimizers, losses_his):
            output = net(b_x) #得到每一个网络的输出
            loss = loss_func(output, b_y) #计算每一个网络的误差
            
            opt.zero_grad() #为下一次训练清空梯度
            loss.backward() #反向传播,计算梯度
            opt.step() #更新权重参数
            

            l_his.append(loss.item()) #记录误差

解释以下 zip() 函数
zip用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

a = [1,2,3]
b = [4,5,6]
zip(a,b)

zip的输出值:

[(1, 4), (2, 5), (3, 6)]

另外,在莫烦的代码里有这一行,

l_his.append(loss.data[0])

这里会报错
IndexError: invalid index of a 0-dim tensor. Use tensor.item() to convert a 0-dim tensor to a Python number
改为:

l_his.append(loss.item())

画图

# 画图
labels = ['SGD', 'Momentum', 'RMSprop', 'Adam']
for i, l_his in enumerate(losses_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 adamw优化器参数设置_pytorch_02


SGD 是最普通的优化器, 也可以说没有加速效果, 而 MomentumSGD 的改良版, 它加入了动量原则. 后面的 RMSprop 又是 Momentum 的升级版. 而 Adam 又是 RMSprop 的升级版. 不过从这个结果中我们看到, Adam 的效果似乎比 RMSprop 要差一点. 所以说并不是越先进的优化器, 结果越佳. 我们在自己的试验中可以尝试不同的优化器, 找到那个最适合你数据/网络的优化器.