鱼的深度学习

深度学习(六)损失函数和优化器

2020-07-31  本文已影响0人  升不上三段的大鱼

思考一下,神经网络是靠什么来判断得到的结果是好还是坏呢?

答案是通过比较神经网络自己预测的输出与真实标签的差距,也就是Loss函数。从数学上推导loss函数可以看这里

为了找到最小的loss,通常采用的是梯度下降(Gradient Descent)的方法。

记loss为 L(w) = \frac{1}{M}\sum_{m=1}^{M} L(w,x_m,y_m), M 是样本的数量。

一、梯度下降 Gradient Descent

梯度下降的思想是计算loss的梯度, 并取当前点的梯度值的负数,由梯度的定义可以直到,负的梯度指向区域最小值,如果是正值就是区域最大值。步长由学习率\eta决定,k+1次的权重值就是第k次的权重减去学习率乘梯度:
w^{k+1} = w^k - \eta\nabla L(w^{k},x,y)

By Gradient_descent.png: The original uploader was Olegalexandrov at English Wikipedia.derivative work: Zerodamage - This file was derived from: Gradient descent.png:, Public Domain, https://commons.wikimedia.org/w/index.php?curid=20569355

1. 批梯度下降 Batch gradient descent

上面的公式使用了数据集里的所有的样本来计算梯度,这种方法被称为批梯度下降(Batch gradient descent)。
如果我们每次迭代只计算一次梯度,那整体梯度下降的就太慢了,并且可能因为数据量太大,内存放不下。不过对于凸误差面,批梯度下降可以保证收敛到全局最小值,对于非凸面,可以保证收敛到局部最小值。
w = w- \eta\nabla_w L(w)

2. 随机梯度下降 Stochastic gradient descent

随机梯度下降每次只用一个样本更新参数,因此梯度下降的非常快,但不是很稳定。SGD不会像批梯度下降一样向最优点逼近,可能会在最优点附近震荡。不过也有人说如果逐渐降低学习率,SGD也会想BGD一样收敛到全局最小值或者局部最小值。
w = w- \eta\nabla_w L(w;x_i, y_i)

3. Mini-batch gradient descent

Mini-batch gradient descent是每次用B个样本来更新参数,B=1的时候是SGD,B=M的时候就是BGD。这样做可以得到一个更加稳定的梯度下降,同时也减少了需要计算的参数,提高了优化效率。一般来说B会取2的幂,比如2,4,8,16,32,64,128等,有利于GPU的加速。
w = w- \eta (\frac{1}{B}\nabla_w \sum_{b=1}^B L(w;x_b, y_b))
Mini-batch gradient descent 是现在最常用的方法,通常说的SGD指的也就是Mini-batch gradient descent。SGD 的缺点是选择合适的学习率可能很困难。学习率太小会导致收敛缓慢,而学习率太大会阻碍收敛,并导致损失函数在最小值附近波动甚至发散。

二、 动量 Gradient Descent With Momentum

1. 动量 Momentum

上面提到了SGD的一个缺点,就是在每个更新参数的时候,不一定是朝着梯度下降的方向,比如下面左边的图,我们更希望在水平方向上下降的快一点,而在垂直方向上的变化量小一点。Momentum的作用就是在相关方向上加速SGD并且抑制震荡。
如果我们增加一个变量来储存上一步的更新向量:
v^{(k)} = \mu v^{k-1} - \eta \nabla L(w^{k})
w^{k+1}=w^{k}+v^{k}
通常取\mu={0.9,0.95,0.99}

SGD with &without momentum
接下来详细讲一下momentum的作用:




梯度向量
从图上可以看到蓝色的箭头是不加动量时参数要指向的方向, 红色箭头是上一次的梯度下降指向的方向,如果是区域最小值在水平方向的右边,那么绿色箭头会比蓝色箭头更快到达区域最小值。
Momentum的优点在于可以抑制震荡,加速收敛,缺点是需要调整学习率。

2. Nesterov Accelerated Gradient

Nesterov Accelerated Gradient 在momentum上做了一些改变, 计算了下一次参数的loss,计算了梯度的二阶梯度,所以比SGD+momentum收敛地更快[5]。
v^k = \mu v^{k-1}- \eta \nabla L(w^k + \mu v^{k-1})
w^{k+1}=w^k+v^k
这块数学没怎么懂,总之它收敛比momentum更快。

3. AdaGrad

上面的优化方法都用的是固定的学习率,缺点就是需要自己调参数找最适合的学习率,所以我们要想办法,让学习率在优化过程中一起优化了。
AdaGrad 全称Adpative Gradient,方法如下, 这里的*代表的是矩阵元素间的乘法:
g^k = \nabla L(w^k)
r^k =r^{k-1}+g^k * g^k
w^{k+1}=w_{k}- \frac{\eta}{\sqrt{r^k}+ \varepsilon} * g^k
可以看到与SGD的更新规则相比,上面公式里与学习率相同作用的,是一个基于梯度和上一次迭代里学习率的值。
Adagrad的主要好处之一是,它无需手动调整学习速度。 大多数实现使用默认值0.01并将其保留为默认值。缺点就是学习率下降的太快了。

4. RMSprop

g^k = \nabla L(w^k)
r^k = \rho r^{k-1}+(1- \rho)g^k * g^k
w^{k+1}=w_{k}- \frac{\eta}{\sqrt{r^k}+ \varepsilon} * g^k
通常取\rho = 0.9, \eta=0.001
RMSprop的优点是不会让学习率单调变小。

5. Adam

Adaptive Moment Estimation
g_k = \nabla L(w^k)
v_k=\mu v^{k-1}+(1- \mu)g^k
r^k = \rho r^{k-1} +(1-\rho)g^k * g^k
通常\mu = 0.9, \rho=0.999, \eta=0.001
Adam 看起来是RMSprop和 momentum的结合版, 一般推荐使用Adam来训练。

6. AMSGrad

Adam 有时候被观察到不能收敛到最优解,于是就有人提出了解决方案:
v^{k}=max(v^{k-1}, v^k)
是不是比Adam更好还不确定。

小结

最常用的两种优化方法是SGD+momentum 和Adam,两种方法各有优缺点:

三、Pytorch实现

pytorch实现SGD和Adam

import torch.optim as optim

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# optimizer = optim.Adam(model.parameters(), lr=learning_rate)

for input, target in dataset:
    # set zero gradient
    optimizer.zero_grad()
    output = model(input)
    loss = loss_fn(output, target)
    loss.backward()
    # take optimization step
    optimizer.step()

如果想只优化特定的一些参数:

params_to_update = []
for name, param in self.model.named_parameters():
    if param.requires_grad == True:
        params_to_update.append(param)

为不同参数设置不同的学习率

optimizer = torch.optim.SGD([
            {'params': model.parameters()},
            {'params': model.s, 'lr':1e-3}
        ], lr=learning_rate)

为不同的参数设置不同的优化器:

class MultipleOptimizer(object):
    def __init__(self, *op):
        self.optimizers = op

    def zero_grad(self):
        for op in self.optimizers:
            op.zero_grad()

    def step(self):
        for op in self.optimizers:
            op.step()

 optimizer = MultipleOptimizer(optim.SGD([model.s], lr=0.01),
              optim.Adam(model.parameters(), lr=learning_rate))
optimizer.zero_grad()
loss.backward()
optimizer.step()

如果想要根据训练的表现调节学习率,可以使用torch.optim.lr_scheduler里的函数,可以根据各种条件调节学习率的变化。

Reference

  1. 几种梯度下降方法对比
  2. An overview of gradient descent optimization algorithms
  3. Gradient Descent with Momentum
  4. pytorch文档
  5. 比Momentum更快:揭开Nesterov Accelerated Gradient的真面目
上一篇下一篇

猜你喜欢

热点阅读