欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch学习笔记 2.6 Optimizer 优化器

程序员文章站 2022-07-06 10:17:41
...

一、优化器Optimizer 加速神经网络训练(Speed Up Training)

  越复杂的神经网络 , 越多的数据 , 使得在训练神经网络时花费的时间也就越多。 原因很简单, 是因为计算量太大了,所以我们需要寻找一些方法, 让神经网络的训练快起来。

1、Stochastic Gradient Descent (SGD)

  把数据分成小批小批的,然后再分批进行计算。每次使用批数据,虽然不能反映整体数据的情况,但是也可以很大的程度的加速训练过程,并且不会丢失过多的准确率。

2、Momentum 更新方法
  • 传统的参数更新:原始的 W 累加【一个负的学习率 × 校正值(dx)】。这种方法会让学习过程曲折无比。好比一个喝醉的人回家时,摇摇晃晃走了很多弯路。
    pytorch学习笔记 2.6 Optimizer 优化器
  • Momentum参数更新:把这个人从平地上放到了一个斜坡上, 只要他往下坡的方向走一点点, 由于向下的惯性, 他不自觉地就一直往下走, 走的弯路也变少了。
    pytorch学习笔记 2.6 Optimizer 优化器
3、AdaGrad 更新方法
  • 在学习率上进行优化, 使得每一个参数更新都会得到不同的学习率。好比给他一双不好走路的鞋子, 使得他一摇晃着走路就脚疼, 鞋子成为了走弯路的阻力, 逼着他往前直着走。
    pytorch学习笔记 2.6 Optimizer 优化器
4、RMSProp 更新方法

合并【部分的 Momentum 的惯性原则】以及 【AdaGrad 的对错误方向的阻力】,让其同时具备两种方法的优势。
pytorch学习笔记 2.6 Optimizer 优化器

5、Adam 更新方法

计算m 时有 momentum 下坡的属性, 计算 v 时有 adagrad 阻力的属性, 然后再更新参数时 把 m 和 V 都考虑进去。实验证明, 大多数使用 Adam 都能又快又好的达到目标, 迅速收敛。
pytorch学习笔记 2.6 Optimizer 优化器

二、Optimizer 优化器

上面已经介绍了几种优化器,那么我们现在编写代码来看一下各种优化器的效果图

1、准备伪数据
import torch
import matplotlib.pyplot as plt

# 定义的部分超参数
LR = 0.01       # 学习率
BATCH_SIZE = 32 # 批处理数
EPOCH = 12      # 轮数

# 伪数据
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))

# 画图
plt.scatter(x.numpy(), y.numpy())
plt.show()

输出结果:
pytorch学习笔记 2.6 Optimizer 优化器

2、创建神经网络

为了更好的对比出每一种优化器,需要给他们各自创建一个神经网络。

# 使用上节内容提到的 data loader
torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2,)

# 默认的 network 形式
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
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]	# 把创建的网络放在一个列表里面,便于训练
3、优化器 Optimizer

创建不同的优化器,用来训练不同的网络。

# 创建不同的优化器
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()	# 计算误差
losses_his = [[], [], [], []]   # 记录 training 时不同神经网络的 loss
4、训练
for epoch in range(EPOCH):
    print('Epoch: ', epoch)
    for step, (b_x, b_y) in enumerate(loader):

        # 对每个优化器, 优化属于他的神经网络
        for net, opt, l_his in zip(nets, optimizers, losses_his):
            output = net(b_x)              # 在net中训练数据 x, 输出预测值
            loss = loss_func(output, b_y)  # 计算预测值与实际y的误差,(预测值写在前面)
            opt.zero_grad()                # 把net中参数的梯度都将为0,为了下面的优化神经网络
            loss.backward()                # 误差反向传播, 计算参数更新值
            opt.step()                     # 将参数更新值施加到 net 的 parameters 上,优化梯度
            l_his.append(loss.data.numpy())     # 误差记录
5、代码整合
import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt

# 定义的部分超参数
LR = 0.01       # 学习率
BATCH_SIZE = 32 # 批处理数
EPOCH = 12      # 轮数

# 伪数据
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))

# 使用上节内容提到的 data loader
torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2, )

# default network
# 默认的 network 形式
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

if __name__ == '__main__':
    # 为每个优化器创建一个 net
    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()
    losses_his = [[], [], [], []]  # 记录 training 时不同神经网络的 loss

    # training
    for epoch in range(EPOCH):
        print('Epoch: ', epoch)
        for step, (b_x, b_y) in enumerate(loader):

            # 对每个优化器, 优化属于他的神经网络
            for net, opt, l_his in zip(nets, optimizers, losses_his):
                output = net(b_x)  # 在net中训练数据 x, 输出预测值
                loss = loss_func(output, b_y)  # 计算预测值与实际y的误差,(预测值写在前面)
                opt.zero_grad()  # 把net中参数的梯度都将为0,为了下面的优化神经网络
                loss.backward()  # 误差反向传播, 计算参数更新值
                opt.step()  # 将参数更新值施加到 net 的 parameters 上,优化梯度
                l_his.append(loss.data.numpy())  # 误差记录

    # 画图
    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()

输出结果:
1)会输出轮数0-11。

Epoch:  0
Epoch:  1
Epoch:  2
Epoch:  3
Epoch:  4
Epoch:  5
Epoch:  6
Epoch:  7
Epoch:  8
Epoch:  9
Epoch:  10
Epoch:  11

Process finished with exit code -1

2)图示,四种优化器的对比图
pytorch学习笔记 2.6 Optimizer 优化器

相关标签: pytorch