机器学习6 -- 深度学习训练优化

1 训练遇到的问题

深度学习中,我们在训练集上进行训练,结束后利用模型在测试集上进行predict。一般来说可能遇到两大类问题

  1. 训练集上训练的不够好,模型指标本身就不高。一般称为欠拟合
  2. 训练集上表现很好,但测试集上表现不好。一般称为过拟合。

如下图所示
在这里插入图片描述
我们分别来看这两种情况怎么来优化模型

2 训练集降低误差

训练过程中我们经常碰到,不停迭代也无法收敛到一个不错的结果。碰到这种情况,肯定是先考虑是否模型过于简单,导致bias过大,导致整体误差过大。如果对模型加宽加深后,还是无法收敛,那就要考虑别的原因了。之前在讲为什么深度模型需要加深的时候,我们也提到过加深可能带来梯度弥散问题。为什么会出现梯度弥散呢

  1. 反向传播过程中,我们从后向前传递梯度。离输出近的layer,其gradient比较大。经过wx+b的反向传播后,由于w一般比较小,特别是加了正则项后,导致反向传播的梯度越来越小。最终传递到前几层的时候,几乎为0,无法指导参数更新了。
  2. 由于sigmoid函数取值在(0,1),较大的值也会被压缩在0到1之间,故无形中会加剧梯度的衰减。

在这里插入图片描述
由上图可见,神经网络中的深层梯度大,参数更新快,收敛也快。但由于梯度弥散效应,浅层梯度小,参数更新慢,几乎仍然处于随机状态。故即使设计很复杂的模型,由于参数得不到充分训练,也就无法收敛到一个比较好的点了。

那怎么解决这个问题呢

2.1 激活函数采用relu

我们先来解决sigmoid激活函数导致的梯度弥散问题。sigmoid如下图
在这里插入图片描述
输入会被压缩在(0,1)之间,故对于较大的input,最终输出可能会较小。

为了优化这个问题,人们提出了relu来替代它
在这里插入图片描述
relu分为两段,输入大于0时,输出等于输入。输入小于0时,输出为0。Relu的优点有

  1. 前向计算起来比较简单。相比sigmoid还要计算exp,relu简单很多很多
  2. 反向求梯度也很简单
  3. 输入大于0,梯度为1,不会导致梯度弥散
  4. 符合仿生学。对于生物视觉,光线达到一定程度,眼睛才能够看到物体。relu比较符合这一概念。

对于relu,人们也提出了很多变种,比如Leaky Relu,Parametric Relu等。其实激活函数可以利用MaxOut网络来进行自动学习,relu是一种特殊的MaxOut。MaxOut对神经元的输出进行分组,每组取最大值作为输出。依次进行下去,如下图。
在这里插入图片描述

2.2 优化optimizer

学习率调整不到位也会影响训练过程。学习率太小导致收敛过慢,无法在相同时间内探索更多的最优解。学习率太大可能会错过最优解。另外陷入局部最优、鞍点等梯度很小的点,导致无法更新参数也是比较头疼的。这些都需要优化optimizer。

常用的optimizer主要分为两大类。

  1. SGD和SGDM。随机梯度下降和带动量的随机梯度下降。SGD通过随机选取mini-batch的方式,计算梯度,并更新参数。SGDM的改进是,参数更新时,加入了动量。这个动量是由之前迭代的梯度,通过weight decay后得到的。加入momentum动量的目的,就是为了避免陷入梯度很小的点,导致无法更新参数。比如局部最优、鞍点、平坦高原等。SGD和SGDM没有实现学习率自适应调整,因此初始学习率的选择还是挺关键的。
  2. Adagrad、RMSProp、Adam,以及各种变种,如AdaBound、AdamW等。它们和SGD的区别在于,实现了学习率的自适应更新。当梯度大时,学习率尽量小一点,避免一下子越过了最优点。当梯度小时,学习率可以调大一点,加快收敛速度。它们同时考虑了迭代轮次和不同参数梯度,可以实现因材施教。

详见机器学习2 – 优化器(SGD、SGDM、Adagrad、RMSProp、Adam等)

3 测试集降低误差

我们也会经常遇到另一类问题,训练集上可以收敛到比较好的点,但放到训练集上时,效果就不尽人意了。也就是我们常说的过拟合。在实际情况中,训练集的分布和测试集一般会有些区别,毕竟训练集只能通过历史数据获取,而测试集则要面向未来。故模型还是需要比较强的泛化能力的。模型参数过多,模型太过复杂,导致参数可能还没有充分训练到位,就可以充分拟合训练集了,从而在不同分布的测试集上表现不好。因此我们要增加模型学习的难度,让参数可以充分训练。

3.1 early stop

我们可以切分一部分训练数据作为验证集。采用剩下的数据来进行训练。训练一定iteration后,在验证集上进行验证。如果随着iteration的增加,验证集上效果反而变差了,此时我们可以直接停止迭代了。这就叫做early stop。
在这里插入图片描述
如果能够拿到测试集来做early stop就完美了。但绝大多数情况下,我们是没法拿到测试集的。故只能利用验证集来做这个事情了。

3.2 正则

正则可以惩罚模型的复杂度,一般分为L1正则和L2正则。它在正常的Loss函数后面,加入了正则项。如下
在这里插入图片描述
对于L2正则,其正则项为所有参数的平方和。故称L2
在这里插入图片描述
对于L1正则,其正则项为所有参数绝对值的和,故称L1
在这里插入图片描述

L2正则

来看加入L2正则后,梯度和参数更新的改变。
在这里插入图片描述
由上可见,加入正则项后,梯度增加了λw这一项。代入到参数更新的表达式中,则相当于在原先的w基础上,乘以了一个系数(1-ηλ)。由于正则系数λ和学习率η,一般都比较小,故此系数小于但接近1。由于每次迭代更新参数,都需要乘上这个小于1的系数,故最终迭代很多次后,w会更新到一个比较小的数值。整个神经网络中,w接近0的参数会增加,也就是增加了模型的稀疏性。

正则的加入,会增加模型稀疏性,让模型在不下降指标的情况下,尽量简单点。可以使得其他参数得到充分的学习,提升模型泛化能力,减少过拟合问题。

L1正则

现在来看加入L1正则后,梯度和参数更新的改变。
在这里插入图片描述
同样的,加入L1正则后,梯度会增加一项。其中sgn(w)为符号函数,w小于0时为-1,大于0时为1。对于参数更新,则表现为在原始的基础上,增加了-ηλsgn(w)这一项。与L2不同的是,这一项不论w绝对值多大,都是相同的。相比L2,这会带来一个问题,就是当w本身就很大,和w本身很小时,L1正则作用在w更新上的效果是差不多的,这个肯定是有问题的。

所以L1虽然也能增加模型稀疏性,但相比L2,不够平滑。因此一般我们使用L2更多一些。

3.3 dropout

dropout是在模型训练过程中,随机将某些参数w强制为0,然后训练另外参数。如下图
在这里插入图片描述
在test中时,则不会加入dropout,采用所有的参数进行predict。但参数w需要乘以(1-p%),其中p为dropout去掉的比例。现在pytorch等工具已经帮我们处理了这个过程,我们实操中不用care。
在这里插入图片描述
dropout为什么这么有用了,个人认为主要原因有

  1. 增加了模型稀疏性,可以逼迫其他没有设置为0的参数,学习的更好
  2. 增加了变化,带来了很多随机性和可能性,提升了模型泛化能力。
  3. dropout可以理解为是多模型ensemble融合。如下

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u013510838/article/details/108306983