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

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

1、Stochastic Gradient Descent (SGD)

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

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

合并【部分的 Momentum 的惯性原则】以及 【AdaGrad 的对错误方向的阻力】,让其同时具备两种方法的优势。

pytorch有哪些优化器 pytorch优化器选择_Data

5、Adam 更新方法

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

pytorch有哪些优化器 pytorch优化器选择_Data_02

二、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有哪些优化器 pytorch优化器选择_Data_03

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有哪些优化器 pytorch优化器选择_数据_04