前言:

本文主要根据几个大佬的文章整理为适合自己学习的方式,希望对您也有所帮助,在此对各位大佬表示感谢!特附原文链接如下:
1. 目标检测之人眼状态检测
2. 深度学习 warmup 策略
3. Resnet-18-训练实验-warm up操作

正文

1. 背景

学习率是最影响性能的超参数之一,如果我们只能调整一个超参数,那么最好的选择就是它。 其实在我们的大多数情况下,遇到 loss 变成 NaN 的情况大多数是由于学习率选择不当引起的

2. 学习率的设置 — “不同阶段不同值:上升 -> 平稳 -> 下降”

由于神经网络在刚开始训练的时候是非常不稳定的,因此刚开始的学习率应当设置得很低很低,这样可以保证网络能够具有良好的收敛性。但是较低的学习率会使得训练过程变得非常缓慢,因此这里会采用以较低学习率逐渐增大至较高学习率的方式实现网络训练的“热身”阶段,称为 warmup stage。但是如果我们使得网络训练的 loss 最小,那么一直使用较高学习率是不合适的,因为它会使得权重的梯度一直来回震荡,很难使训练的损失值达到全局最低谷。这个代码采用了 cosine 的衰减方式,这个阶段可以称为 consine decay stage。

3. tf-yolov3作者的相关源码
with tf.name_scope('learn_rate'):
    self.global_step = tf.Variable(1.0, dtype=tf.float64, trainable=False, name='global_step')
    warmup_steps = tf.constant(self.warmup_periods * self.steps_per_period,
                               dtype=tf.float64, name='warmup_steps') # warmup_periods epochs
    train_steps = tf.constant((self.first_stage_epochs + self.second_stage_epochs) * self.steps_per_period,
                              dtype=tf.float64, name='train_steps')
    self.learn_rate = tf.cond(
        pred=self.global_step < warmup_steps,
        true_fn=lambda: self.global_step / warmup_steps * self.learn_rate_init,
        false_fn=lambda: self.learn_rate_end + 0.5 * (self.learn_rate_init - self.learn_rate_end) * (
                    1 + tf.cos((self.global_step - warmup_steps) / (train_steps - warmup_steps) * np.pi)))
    global_step_update = tf.assign_add(self.global_step, 1.0)
    """
    训练分为两个阶段,第一阶段里前面又划分出一段作为“热身阶段”:
    热身阶段:learn_rate = (global_step / warmup_steps) * learn_rate_init
    其他阶段:learn_rate_end + 0.5 * (learn_rate_init - learn_rate_end) * (
             1 + tf.cos((global_step - warmup_steps) / (train_steps - warmup_steps) * np.pi))
	"""

学习率变化曲线:
学习率变化

4. 应用场景

(1)训练出现NaN:当网络非常容易nan时候,采用warm up进行训练,可使得网络正常训练;

(2)过拟合:训练集损失很低,准确率高,但测试集损失大,准确率低,可用warm up;具体可看: Resnet-18-训练实验-warm up操作

5. 应用原理/优势来源

这个问题目前还没有被充分证明,目前效果有:
(1)有助于减缓模型在初始阶段对mini-batch的提前过拟合现象,保持分布的平稳;
(2)有助于保持模型深层的稳定性。

在训练期间有如下情况:
(1)在训练的开始阶段,模型权重迅速改变;
(2)mini-batch size较小,样本方差较大。
分析:
(1)因为刚刚开始的时候,模型对数据的“分布”理解为零,或者是说“均匀分布”(初始化一般都是以均匀分布来初始化);在第一轮训练的时候,每个数据对模型来说都是新的,随着训练模型会很快地进行数据分布修正,这时候学习率就很大,很有可能在刚刚开始就会导致过拟合,后期需要要通过多轮训练才能拉回来。当训练了一段时间(比如两轮、三轮)后,模型已经对每个数据过几遍了,或者说对当前的batch而言有了一些正确的先验,较大的学习率就不那么容易会使模型学偏,所以可以适当调大学习率。这个过程就也就是warmup。
那后期为什么学习率又要减小呢?这就是我们正常训练时候,学习率降低有助于更好的收敛,当模型学习到一定的程度,模型的分布就学习的比较稳定了。如果还用较大的学习率,就会破坏这种稳定性,导致网络波动比较大,现在已经十分接近了最优了,为了靠近这个最优点,就要用很小的学习率了。
(2)如果有mini-batch内的数据分布方差特别大,这就会导致模型学习剧烈波动,使其学得的权重很不稳定,这在训练初期最为明显,最后期较为缓解。
所以由于上面这两个原因,我们不能随便成倍减少学习率
在resnet文章中,有说到如果一开始就用大的学习率,虽然最终会收敛,但之后测试准确率还是不会提高;如果用了warmup,在收敛后还能有所提高。也就是说,用warm up和不用warm up达到的收敛点,对之后模型能够达到最优点有影响。这说明不用warm up收敛到的点比用warm up收敛到的点更差。这也说明,如果刚刚开始学偏了的权重后面都拉不回来。

那么为什么以前神经网络没用warm up技巧呢?
主要原因是:
(1)以前的网络不够大、不够深;
(2)数据集普遍较小。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐