写点什么

了解学习率及其如何提高深度学习的性能

  • 2018-03-18
  • 本文字数:4152 字

    阅读完需:约 14 分钟

这篇文章记录了我对以下主题的理解:

  • 什么是学习率?它的意义是什么?
  • 如何系统地达到良好的学习率?
  • 为什么要在训练期间改变学习率?
  • 在使用预训练的模型时,如何处理学习率?

这篇文章的大部分内容,是基于过去 fast.ai 的研究员所写的 [1]、[2]、[5] 和 [4] 的内容的简洁版,以一种快速的方式,获得其精髓。要了解更多细节,请仔细参阅文末所列的参考资料。

AI 前线: fast.ai 是一个致力于为所有人提供学习深度学习机会的平台。他们认为深度学习将是一个转型的技术,正在研究综合利用人类与计算机各自优势的混合“人机”解决方案,建立一个随时可用的应用程序和模型库,开发完整的教育框架,并为开发人员和用户编写能够快速上手和易于使用的软件。

首先,什么是学习率?

学习率(Learning Rate,LR。常用η表示。)是一个超参数,考虑到损失梯度,它控制着我们在多大程度上调整网络的权重。值越低,沿着向下的斜率就越慢。虽然这可能是一个好主意(使用低学习率),以确保我们不会错过任何局部最小值;但也有可能意味着我们将耗费很久的时间来收敛——特别是当我们陷入平坦区(plateau region)的时候。

AI 前线:如果使用很高的学习率,训练可能根本不会收敛,甚至会发散。权重的该变量可能会非常大,使得优化越过最小值,导致损失函数变得更糟。

下面的公式显示了这种关系:

复制代码
new_weight = existing_weight — learning_rate * gradient

复制代码
学习率很小(上图)与学习率很大(下图)的梯度下降。(来源:Coursera 机器学习课程,Andrew Ng)

通常,学习率是由用户随机配置的。在最好的情况下,用户可以利用过去的经验(或者其他类型的学习材料)来获得关于设置学习率最佳值的直觉。

因此,很难做到这一点。下图演示了配置学习率时可能会遇到的不同场景。

复制代码
不同学习率对收敛的影响:(图片来源:csn231n)

此外,学习率会影响模型收敛到局部最小值的速度(也就是达到最佳的精度)。因此,在正确的方向做出正确的选择,意味着我们只需更少的时间来训练模型。

训练时间越少,则花在 GPU 云计算上的钱就越少。:)

AI 前线:目前深度学习使用的都是一阶收敛算法:梯度下降法。不管有多少自适应的优化算法,本质上都是对梯度下降法的各种变形。故初始学习率对深层网络的收敛起着决定性的作用。

有没有更好的方法来确定学习率?

在“训练神经网络的循环学习率(Cyclical Learning Rates (CLR)for Training Neural Networks)”[4] 的第 3.3 节中。Leslie N. Smith 认为,通过在每次迭代中以非常低的学习率来增加(线性或指数)的方式训练模型,可以估计好的学习率。

AI 前线:周期性学习率(Cyclical Learning Rates,CLR),即学习率退火与热重启,最初由 Smith 于 2015 年首次提出。这是一种新的学习率方法,和以前的不同,或者固定(fixed)或者单调递减。要使用 CLR,需指定这三个参数:max_lr、base_lr、stepsize。

复制代码
学习率在每个小批量之后增加

如果我们在每次迭代中记录学习率和训练损失,然后据此绘出曲线图;我们将会看到,随着学习率的提高,将会有一个损失停止下降并开始增加的点。在实践中,理想情况下,学习率应该是在左图的最低点(如下图所示)。在该例中为 0.001 到 0.01 之间。

以上看起来很有用。我该如何开始使用它?

目前,它被作为 fast.ai 深度学习库的一个函数来支持。由 Jeremy Howard 开发,是用来抽象 PyTorch 深度学习框架的一种方式,就像 Keras 是对 TensorFlow 框架的抽象。

AI 前线: fast.ai 深度学习库是 fast.ai 基于 PyTorch 的基础上创建的自有软件库,并且他们认为,这将有助于更加清晰地展示深度学习的概念,同时有助于实现最佳编码。采用 Apache 2.0 许可证,可免费使用。

只需输入以下命令,就可以在训练神经网络之前找到最佳学习率。

复制代码
# learn is an instance of Learner class or one of derived classes like ConvLearner
learn.lr_find()
learn.sched.plot_lr()

精益求精

在这个关键时刻,我们已经讨论了学习率的全部内容和它的重要性,以及我们如何在开始训练模型时系统地达到最佳的使用价值。

接下来,我们将讨论如何使用学习率来提高模型的性能。

一般看法

通常情况下,当一个人设定学习率并训练模型时,只有等待学习率随着时间的推移而降低,并且模型最终会收敛。

然而,随着梯度逐渐趋于稳定时,训练损失也变得难以改善。在 [3] 中,Dauphin 等人认为,最大限度地减少损失的难度来自于鞍点,而非局部极小值。

AI 前线:鞍点是梯度接近于 0 的点,在误差曲面中既不是最大值也不是最小值的平滑曲面,则一般结果表现为性能比较差;如果该驻点是局部极小值,那么表现为性能较好,但不是全局最优值。

复制代码
误差曲面中的鞍点。鞍点是函数的导数变为零但点不是所有轴上的局部极值的点。(图片来源:safaribooksonline)

那么我们该如何摆脱呢?

有几个选项我们可以考虑。一般来说,从 [1] 引用一句:

……而不是使用一个固定值的学习率,并随着时间的推移而降低,如果训练不会改善我们的损失,我们将根据一些循环函数 _f_ 来改变每次迭代的学习率。每个周期的迭代次数都是固定的。这种方法让学习率在合理的边界值之间循环变化。这有助于解决问题,因为如果我们被困在鞍点上,提高学习率可以更快速地穿越鞍点。

在 [2] 中,Leslie 提出了一种“Triangular”的方法,在每次迭代之后,学习率都会重新开始。

复制代码
Leslie N. Smith 提出的“Triangular”和“Triangular2”循环学习率的方法。在左边的图上,minmax lr 保持不变。在右边,每个周期之后的差异减半。

另一种同样受欢迎的方法是由 Loshchilov 和 Hutter 提出的热重启的随机梯度下降法(Stochastic Gradient Descent with Warm Restarts,SGDR)[6]。这种方法主要利用余弦函数作为循环函数,并在每个周期的最大值重新开始学习率。“热重启”一词源于这样的一个事实:当学习率重新开始的时候,并不是从头开始,而是来自模型在上一步收敛的参数开始 [7]。

AI 前线:热重启后的初始高学习率用于基本上将参数从它们先前收敛的最小值弹射到不同的损失表面。根据经验,热重启的随机梯度下降法需要的时间比学习率退火要少 2~4 倍,且能达到相当或更好的性能。

虽然有这种变化,下面的图表展示了它的一个实现,其中每个周期都被设置为同一时间周期。

复制代码
SGDR 图,学习率与迭代。

因此,我们现在有一种减少训练时间的方法,基本上就是周期性地在“山脉”周围跳跃(下图)。

复制代码
比较固定学习率和循环学习率(图片来源:ruder.io

除了节省时间外,研究还表明,使用这些方法往往可以提高分类准确性,而无需进行调优,而且可以在更少的迭代次数内完成。


迁移学习(Transfer Learning)中的学习率

在 fast.ai 课程中,在解决 AI 问题时,非常重视利用预先训练的模型。例如,在解决图像分类问题时,教授学生如何使用预先训练好的模型,如 VGG 或 Resnet50,并将其连接到想要预测的任何图像数据集。

总结如何在 fast.ai 中完成模型构建(注意该程序不要与 fast.ai 深度学习库混淆),下面是我们通常采取的几个步骤 [8]:

1. 启用数据增强,precompute=True。
2. 使用 lr_find()查找最高的学习率,在此情况下,损失仍在明显改善。
3. 训练最后一层从预计算激活 1~2 个轮数。
4. 在 cycle_len=1 的情况下训练最后一层数据增加(即 precompute=False)2~3 个轮数。
5. 解除所有层的冻结。
6. 将较早的层设置为比下一个较高层低 3~10 倍的学习率。
7. 再次使用lr_find()
8. 使用 cycle_mult=2 训练完整网络,直到过度拟合。

从上面的步骤中,我们注意到第 2 步、第 5 步和第 7 步关注了学习率。在这篇文章的前半部分,我们已经基本讨论了涵盖了上述步骤中的第 2 项——我们在这里讨论了如何在训练模型之前得出最佳学习率。

AI 前线:轮数,epoch,即对所有训练数据的一轮遍历。

在接下来的部分中,我们通过使用 SGDR 来了解如何通过重新开始学习速率来减少训练时间和提高准确性,以避免梯度接近于 0 的区域。

在最后一节中,我们将重点讨论差分学习,以及它是如何被用来在训练模型与预先训练的模型相结合时确定学习率的。

什么是差分学习?

这是一种在训练期间为网络中的不同层设置不同的学习率的方法。这与人们通常如何配置学习率相反,即在训练期间在整个网络中使用相同的速率。

这是我为什么喜欢 Twitter 的原因之一——可以直接从作者本人得到答案。

在写这篇文章的时候,Jeremy 和 Sebastian Ruder 发表了一篇论文,深入探讨了这个话题。所以我估计差分学习率现在有一个新的名字:判别式微调(discriminative fine-tuning)。 :)

AI 前线:判别式微调对较底层进行微调以调到一个相较于较高层较低的程度,从而保留通过语言建模所获得的的知识。它可以避免微调过程中产生严重的遗忘。

为了更清楚地说明这个概念,我们可以参考下图,其中一个预训练模型被分成 3 个组,每个组都配置了一个递增的学习率值。

复制代码
差分学习率的 CNN 样本。图片来自 [3]

这种配置方法背后的直觉是,最初的几层通常包含数据的非常细粒度的细节,如线条和边缘——我们通常不希望改变太多,并且保留它的信息。因此,没有太多的需要去大量改变它们的权重。

相比之下,在后面的层中,比如上面绿色的层——我们可以获得眼球或嘴巴或鼻子等数据的详细特征;我们可能不一定要保留它们。

与其他微调方法相比,它表现如何?

在 [9] 中,有人认为,对整个模型进行微调的代价太大,因为有些模型可能有 100 多个层。因此,人们通常做的是一次对模型进行微调。

但是,这就引入了顺序的要求,妨碍了并行性,并且需要多次通过数据集,从而导致对小数据集的过度拟合。

也已经证明 [9] 中引入的方法能够在不同的 NLP 分类任务中提高精度和降低错误率(如下图所示):

复制代码
取自 [9] 的结果

参考资料

[0] Understanding Learning Rates and How It Improves Performance in Deep Learning

[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

感谢陈利鑫对本文的审校。

2018-03-18 18:085697
用户头像

发布了 375 篇内容, 共 185.1 次阅读, 收获喜欢 944 次。

关注

评论

发布
暂无评论
发现更多内容

Flutter技术在会展云中大显身手

京东科技开发者

flutter 跨平台 移动开发

架构作业--大数据

Nick~毓

小熊派开发实践丨小熊派+合宙Cat.1接入云服务器

华为云开发者联盟

IoT 小熊派 实践

中国SaaS的病与痛?

ToB行业头条

C++typename的由来和用法

良知犹存

c++

Mock | 拦截ajax的两种实现方式

梁龙先森

Java 大前端

只谈链不谈币,区块链会发展成什么样的方向?

CECBC

区块链

LeetCode题解:45. 跳跃游戏 II,贪心从后向前,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

摄像机不智能,基本等于不讲武德

脑极体

话题讨论 | 说说那些"Oh my god"的时刻

Kurtis Moxley

话题讨论

卧槽,牛皮了!某程序员苦刷这两份算法PDF47天,四面字节斩获心仪大厂offer!

Java架构之路

Java 程序员 架构 面试 编程语言

测试右移之日志收集与监控

BY林子

敏捷 软件测试

Norns.Urd 中的一些设计

八苦-瞿昙

C# 随笔 随笔杂谈 aop

最值得Deepin的思维模型“组合创新” | 技术人应知的创新思维模型 (3)

Alan

创新 思维模型 28天写作

区块链打破数字医疗桎梏,赢数据未来新生

CECBC

区块链 医疗

生产环境全链路压测建设历程第四篇 技术体系的发力

数列科技杨德华

华为工程师:扔掉你手里的其他Netty资料吧,有这份足以

小Q

Java 学习 面试 Netty 网络

LeetCode题解:102. 二叉树的层序遍历,BFS,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

密码学系列之:明文攻击和Bletchley Park

程序那些事

加密解密 密码学 程序那些事 明文攻击

GO 训练营第 3 周总结

Glowry

某Javva程序员金秋9月靠这份文档涨薪10K,你把这份Java进阶文档吃透涨薪超简单!

Java架构之路

Java 程序员 架构 面试 编程语言

话题讨论 | 对于懂得编程的人来说,编程对你来说有什么乐趣?编程大概是什么感觉?

xcbeyond

话题讨论

Java并发编程:进程、线程、并行与并发

码农架构

Java并发

区块链技术生态持续优化,五大趋势不容忽视

CECBC

区块链 场景应用

学习笔记3

Qx

Alibaba Java面试题大揭秘,把这些知识点吃透去面试成功率高达100%

Java架构之路

Java 程序员 架构 面试 编程语言

4项探索+4项实践,带你了解华为云视觉预训练研发技术

华为云开发者联盟

AI 华为云 modelarts

话题讨论 | 聊聊那些年你重构过的代码?

xcbeyond

话题讨论

为什么删除数据后,Redis内存占用依然很高?

Java架构师迁哥

如何使用 JuiceFS 在云上优化 Kylin 4.0 的存储性能?

苏锐

大数据 kylin 性能优化 JuiceFS

Spock单元测试框架实战指南五 - void方法测试

Java老k

Java 单元测试 spock

了解学习率及其如何提高深度学习的性能_语言 & 开发_刘志勇_InfoQ精选文章