理解学习率(Learning Rate)以及如何提高深度学习的性能
本文章翻译自towards data science中的《Understanding Learning Rates and How It Improves Performance in Deep Learning》
作者:Hafidz Zulkifli
原文日期:2018 年 1 月 22 日
这篇文章(尝试)记录了我对以下几个主题的理解:
- 什么是学习率?它的意义何在?
- 如何系统地得出一个适合的学习率?
- 为什么我们在训练过程中改变学习率?
- 使用预训练模型时我们如何处理学习率?
这篇文章的大部分内容都是基于过去fast.ai研究院(的研究)[1]、[2]、[5]和[3]文章。这是一个简明扼要的版本,整理(这份文档)是为让人们快速的进入(文章)的核心部分。仔细阅读参考文献以了解更多细节。
1. 首先,什么是学习率?
学习率是一个超参(hyper-parameter),它能控制我们在损失梯度中对网络权重的调整程度。学习率越低,我们沿着”下坡“的速度越慢。虽然这是一个好的想法(使用低的学习率),以确保我们不会错过任何的局部最小值,但这也意味着我们将花费很长的时间来收敛——尤其是当我们陷入一个plateau region区域。以下的公式展示了这种关系:
new_weight = existing_weight — learning_rate * gradient
通常情况下,学习率是由用户随机的选择并配置的。较好的情况是,用户会利用以往的经验(或其他类型的学习资料)来了解如何设置最佳得学习率。
因此,通常很难做到正确(设置学习率)。下图转世了配置学习率时可能陷入得不容场景。
此外,学习率影响着我们得模型能多快地收敛到全局[1]最小值(也就是达到最佳精度)。因此,从一开始就设置良好的学习率,意味着我们将花费更少的时间训练模型。
Less training time, lesser money spent on GPU cloud compute. :)
2. 有没有更好的方法来确定学习率?
在"训练神经网络的循环学习率"的第3.3节[4]。Leslie N. Smith认为,你可以通过最初用很低的学习率来训练模型,并在每次迭代中增加它(线性或指数)来估计一个好的学习率。
如果我们记录每次迭代的学习情况,并将学习率(对数)与损失值做对照;我们将看到,随着学习率的增加会有一个点,即损失停止减少并开始增加。在实践中,我们的学习率的最佳值实在同种最低点的左边某处(如下图所示)。早这种情况下为0.001到0.01。
3. 以上的方法似乎有用,我们怎样才能开始运用呢?
目前,它作为fast.ai包中的一个函数被支持,改包由Jeremy Howard开发,是对pytorch包的一种抽象方式(就像Keras是Tensoflow的一种抽象)。我们只需要键入以下指令,就可以在训练神经网络之前开始寻找最理想的学习率。
# learn is an instance of Learner class or one of derived classes like ConvLearner
learn.lr_find()
learn.sched.plot_lr()
3.1 让它变得更好
现在,我们已经基本全面的学习了学习率是怎样一回事,以及它的重要性,和当我们开始训练模型时,我们如何能够系统地得出一个最佳值来使用。
接下来,我们将讨论如何利用学习率来提高我们模型的性能。
3.2 传统的智慧
通常情况下,当人们设置他们的学习率并训练模型时,指挥等待学习率随着时间推移而减少,并等待模型的最终收敛。
然而,当梯度达到一个稳定期(plateau)时,训练过程中的损失函数可能难以改善,在[3]中,Dauphin等人认为,损失最小化的困难来自于鞍点(saddle points),而不是可怜的局部最小值。
3.3 如何摆脱这种情况?
我们有几个方面可以考虑。一般来说,引用[1]中的一句话。
......而不是使用一个固定的学习率值并随着时间的推移而减少,如果训练不再改善我们的损失,我们将根据一些循环函数f来改变每一次迭代的学习率,每个循环在迭代次数上有一个固定的长度。这种方法让学习率在合理的边界值之间循环变化。这有帮助,因为如果我们卡在鞍点上,增加学习率可以更快地穿越鞍点高原。
在[2]中,Leslie提出了一种“三角”方法,其中学习率在每几次迭代后都会重新启动。
另一种也很流行的方法是Loshchilov & Hutter[6]提出的 "暖重启的随机梯度下降"。这种方法基本上使用余弦函数作为循环函数,并在每个循环中以最大值重新启动学习率。暖 "的意思是,当学习率被重新启动时,它不是从头开始;而是从模型在最后一步收敛的参数开始[7]。
因此,我们现在有了一种减少训练时间的方法,基本上是周期性的绕过"山"(如下图)。
除了节省时间之外,研究还表明,使用这些方法往往可以在不调整和更少迭代的情况下提高分类精度。
4. 迁移学习中的学习率
在 fast.ai 课程中,非常强调在解决 AI 问题时利用预训练模型。例如,在解决图像分类问题时,学生将学习如何使用 VGG 或 Resnet50 等预训练模型并将其连接到您想要预测的任何图像数据集。
总结一下如何在 fast.ai(该程序,不要与 fast.ai 包混淆)中完成模型构建,以下是我们通常采取的几个步骤 [8]:
- 开启数据增强,precompute=True
- lr_find()用于寻找损失仍明显改善的最高学习率
- 从预计算的激活值训练最后一层 1-2 个 epochs
- 用数据增强(即 precompute=False)训练最后一层 2-3 个 epoch,cycle_len=1
- 解冻所有图层
- 将较早的层设置为比下一个更高层低 3 到 10 倍的学习率
- 再次使用lr_find()
- 用cycle_mult=2训练全网络直到过拟合
从上面的步骤中,我们注意到步骤 2、5 和 7 关注的是学习率。在这篇文章的前面部分,我们基本上已经介绍了提到的步骤的第 2 项——我们在那里谈到了如何在训练模型之前获得最佳学习率。
在接下来的部分中,我们讨论了如何通过使用 SGDR 来减少训练时间并通过不时重新启动学习率来避免梯度接近零的区域来提高准确性。
在最后一节中,我们将讨论差分学习,以及在训练模型与预训练模型相连时如何使用差分学习来确定学习率。
4.1 什么是差分学习?
这是一种在训练期间为网络中的不同层设置不同学习率的方法。这与人们通常配置学习率的方式不同,后者是在训练期间对整个网络使用相同的学习率。
在写这篇文章的时候,Jeremy和Sebastian Ruder一起发表了一篇论文[9],对这个话题进行了更深入的探讨。因此,我想差分学习率现在有了一个新的名字--判别性微调。😃
为了更清楚地说明这个概念,我们可以参考下图,一个预训练的模型被分成3个组,每个组的学习率值都在增加。
这种配置方法背后的直觉是,前几层通常包含数据的非常细微的细节,比如线条和边缘--我们通常不希望对其进行太多的改变,希望保留它的信息。因此,没有太大的必要对它们的权重进行大量的改变。
相反,在后面的图层中,比如上面的绿色图层--我们得到了数据的详细特征,比如眼球、嘴巴或鼻子;我们可能不一定需要保留它们。
4.2 这与其他微调方法相比如何?
在[9]中,有人认为对整个模型进行微调的成本太高,因为有些模型可能有超过100层。因此,人们通常每次只对模型中的一层进行微调。
然而,这引入了一个顺序的要求,阻碍了并行性,并且需要多次通过数据集,导致小数据集的过度拟合。
事实也证明,在各种NLP分类任务中,[9]中介绍的方法能够提高准确率并降低错误率(如下图所示)
参考文献
[1]: Improving the way we work with learning rate.
[2]: The Cyclical Learning Rate technique
[3]: Transfer Learning using differential learning rates.
[4]: Leslie N. Smith. Cyclical Learning Rates for Training Neural Networks.
[5]: Estimating an Optimal Learning Rate for a Deep Neural Network
[6]: Stochastic Gradient Descent with Warm Restarts
[7]: Optimization for Deep Learning Highlights in 2017
[8]: Lesson 1 Notebook, fast.ai Part 1 V2
[9]: Fine-tuned Language Models for Text Classification
在原文中的描述为"local minima"局部最小值,但根据后文aka arrive at the best accuracy达到最佳的准确度,推测可能是作者的误写。 ↩︎