如何优化深度学习模型
大数据文摘出品
来源:nanonets
编译:刘佳玮、张秋玥、毅航、夏雅薇
看过了各式各样的教程之后,你现在已经了解了神经网络的工作原理,并且也搭建了猫狗识别器。你尝试做了了一个不错的字符级RNN。你离建立终端只差一个pip install tensorflow命令了对吗?大错特错。
深度学习的一个非常重要的步骤是找到正确的超参数,超参数是模型无法学习的。
在本文中,我将向你介绍一些最常见的(也是重要的)超参数,这些参数是你抵达Kaggle排行榜#1的必经之路。此外,我还将向你展示一些强大的算法,可以帮助你明智地选择超参数。
深度学习中的超参数
超参数就像是模型的调节旋钮。
如果您将AV接收机设置为立体声,那么配备低音扬声器的7.1级杜比全景声(Dolby Atmos)家庭影院系统将对你毫无用处,尽管它的超低音扬声器可以产生低于人耳可听范围的声音。
同样,如果你将超参数关闭,带有万亿参数的inception_v3网络甚至不会让你在MNIST数据集上测试通过。
所以现在,让我们然后在学会如何调“旋钮”之前先看看这些“旋钮”。
学习率
学习率可以说是最重要的超参数,粗略地说,它可以控制神经网络“学习”的速度。
那么,为什么我们不把学习率设置得非常大,体验飙车的乐趣呢?
事情不是那么简单。请记住,在深度学习中,我们的目标是尽量最小化损失函数。如果学习率太高,我们的损失函数将开始在某点来回震荡,不会收敛。
如果学习率太小,模型将花费太长时间来收敛,如上所述。
动量
由于本文侧重于超参数优化,我不打算解释动量的概念。但简而言之,动量常数可以被认为是在损失函数表面滚动的球的质量。
球越重,下落越快。但如果它太重,它可能会卡住或超过目标。
丢弃
如果你了解这个概念,我会直接带你去看Amar Budhiraja关于丢弃(dropout)的文章。
但我们做一个快速复习,dropout是Geoff Hinton提出的一种正则化技术,它将神经网络中的激活函数随机地设置为0,概率为p。这有助于防止神经网络过拟合数据而不是学习它。
p是一个超参数。
架构——神经网络的层数,每层神经元的个数等
另一个(最近的)想法是使神经网络的架构本身成为一个超参数。
虽然我们通常不会让机器弄清楚我们模型的架构(否则AI研究人员会丢失他们的工作),但是神经架构搜索(Neural Architecture Search)等一些新技术已经实现了这个想法并取得了不同程度的成功。
如果你听说过AutoML,那么Google基本上就是这样做的:将所有内容都设置为超参数,然后扔大量TPU在这个问题上让它自行解决。
但是对于我们绝大多数只想在黑色星期五销售之后用经济型机器分类猫狗的人来说,现在是时候该弄清楚如何使这些深度学习模型真正起作用了。
超参数优化算法
网格搜索
这是获得良好超参数的最简单方法。它实际上就是暴力解决。
算法:从一组给定的超参数中尝试一堆超参数,看看哪种方法效果最好。
优点:五年级学生都很容易实现,而且可以轻松并行化。
缺点:正如你可能猜到的那样,它的计算成本非常高(因为所有暴力算法都是如此)。
我是否应该使用它:可能不会。网格搜索非常低效。即使你想保持简单,你也最好使用随机搜索。
随机搜索
正如它的本意,随机搜索。完全随机化。
算法:在一些超参数空间上从均匀分布中尝试一堆随机超参数,看看哪种方法效果最好。
优点:可以轻松并行化。就像网格搜索一样简单,但性能稍好一点,如下图所示:
缺点:虽然它提供了比网格搜索更好的性能,但它仍然只是计算密集型。
我是否应该使用它:如果琐碎的并行化和简单性是最重要的,那就去吧。但是,如果你愿意花费时间和精力,那么通过使用贝叶斯优化,你的模型效果将大大提升。
贝叶斯优化
与我们迄今为止看到的其他方法不同,贝叶斯优化使用了算法的先前迭代的知识。使用网格搜索和随机搜索,每个超参数猜测都是独立的。但是,使用贝叶斯方法,每次我们选择并尝试不同的超参数时,表现都在一点点提升。
(如果我告诉了你,深度学习不过是贝叶斯而已)
贝叶斯超参数调整背后的想法历史悠久且细节丰富。所以为了避免太多坑,我会在这里给你一个要点。但如果你感兴趣,一定要仔细阅读高斯过程和贝叶斯优化。
请记住,我们使用这些超参数调整算法的原因是,单独实际评估多个超参数选择是不可行的。例如,假设我们想要手动找到一个好的学习率。这将涉及设置学习率,训练模型,评估它,选择不同的学习率,再次训练你从头开始模型,重新评估它,并继续循环。
问题是,“训练你的模型”可能需要几天时间(取决于问题的复杂性)才能完成。因此,在会议提交截止日期之前,您只能尝试一些学习率。而你知道什么,你甚至没有开始设置动量。糟糕极了。
算法:贝叶斯方法试图建立一个函数(更准确地说,是关于可能函数的概率分布),用于估计模型对于某个超参数选择的好坏程度。通过使用这种近似函数(在文献中称为代理函数),您不必在设置、训练、评估的循环上花费太多时间,因为你可以优化代理函数的超参数。
例如,假设我们想要最小化此函数(将其视为模型损失函数的代理):
代理函数来自于高斯过程(注意:还有其他方法来模拟代理函数,但我将使用高斯过程)。就像我提到的那样,我不会做任何数学上的重要推导,但是所有关于贝叶斯和高斯的讨论归结为:
公式看上去很复杂。但是,让我们试着理解它。
左侧告诉你涉及概率分布(假设存在P)。在括号内看,我们可以看到它是P的概率分布,这是一个任意的函数。为什么?请记住,我们正在定义所有可能函数的概率分布,而不仅仅是特定函数。本质上,左侧表示将超参数映射到模型的度量的真实函数(如验证准确性,对数似然,测试错误率等)的概率为Fn(X),给定一些样本数据Xn等于右侧的式子。
现在我们有了优化函数,就开始进行优化吧。
以下是在开始优化过程之前高斯过程的样子☟
在利用两个数据点迭代之前的高斯过程。
使用你最喜欢的优化器(大佬们一般喜欢最大化预期改善),但其实只需跟着信号(或梯度)引导,你还没有反应过来的时候就已经得到局部最小值。
经过几次迭代后,高斯过程在近似目标函数方面变得更好:
在利用两个数据点迭代三次之后的高斯过程。
无论你使用哪种方法,你现在都找到了代理函数最小化时的参数。那些最小化代理函数的参数居然是最优超参数(的估计)哦!好极了。
最终结果应如下所示:
在利用两个数据点迭代七次之后的高斯过程。
使用这些“最佳”超参数你的神经网络上进行训练,你应该会看到一些改进。但是,你也可以使用这些新信息重新一次又一次地重做整个贝叶斯优化过程。你可以想跑多少次这一贝叶斯循环就跑多少次,但还是要谨慎行事。你实际上在“跑钱”。你不要忘了AWS又不是免费的。
优点:贝叶斯优化比网格搜索和随机搜索提供更好的结果。
缺点:并行化并不容易。
我应该使用它吗:在大多数情况下,是的!唯一的例外是如果:
- 你是一个深度学习专家,你不需要一个微不足道的近似算法帮忙。
- 你拥有庞大的计算资源,并可以大规模并行化网格搜索和随机搜索。
- 如果你是一个频率论者/反贝叶斯统计书呆子。
寻找良好学习率的可选方法
我们到目前为止看到的所有方法有一个隐含主题:自动化机器学习工程师的活儿。这确实很有用很厉害——直到你的老板听说了之后决定用4个RTX Titan卡取代你。呵呵。你本应该坚持用手动搜索的。
不过不要担心啊,还是有些关于让研究者少干点活但是多拿点钱的活跃研究呢。其中一个效果非常好的想法是学习率范围测试,据我所知,这首先出现在Leslie Smith的论文中。
这篇论文实际上是关于一种随时间调度(改变)学习率的方法。LR(Learning Rate,学习率)范围测试只是个作者一不小心遗落在一旁的大宝贝。
当你使用那种学习速率可以从最小值取到最大值的学习速率计划时(例如循环学习速率或具有热重启动的随机梯度下降),作者建议在每次迭代之后将学习速率从小数值线性增加到大数值(例如,1e-7到1e-1),评估每次迭代时的损失,并在对数刻度上绘制损失(或测试误差,或准确度)与学习率的关系。你的图像看起来应该是这样的:
如图所示,你可以设置学习率在最小和最大学习率之间变化,这可以通过在图像上肉眼观察最陡梯度区域来找到。
Colab Notebook上画的LR范围测试图(CIFAR10上训练的DenseNet):
Colab Notebook
https://colab.research.google.com/gist/iyaja/988df5818fd887cc7542074ea2bfb74e/fastai-imagefolder-playground.ipynb
在CIFAR10数据集上训练的DenseNet 201的学习率范围测试
根据经验,如果你没有做任何花哨的学习率安排的话,那么只需将你的恒定学习率设置为低于绘图上最小值的数量级即可。在这种情况下大约就是1e-2。
这种方法最酷地方在于,它很好用很省时省心省计算力,它几乎不需要任何额外的计算。
其他算法——即网格搜索、随机搜索和贝叶斯优化——要求你运行与训练良好神经网络目标相关的整个项目。LR范围测试只是执行简单定期的训练循环,并保持跟踪一些变量。
以下是使用最佳学习速率时大致可以获得的收敛速度(来自Notebook的示例):
Notebook
https://colab.research.google.com/gist/iyaja/ef385db236775f881af0056d1ae8c477/kernel303b922372-2.ipynb
最佳学习率拟合的模型的损失与batch大小图
LR范围测试已经由fast.ai团队实施过了。你一定要看看他们实现LR范围测试的库(他们称之为学习速率查找器)以及许多其他算法。
对于更复杂的深度学习实践者
如果你有兴趣,这儿还有一个纯pytorch编写的notebook实现了上述功能。这可能会帮助你更好地了解幕后训练流程:
https://colab.research.google.com/gist/iyaja/f9fc63ef65b6cc74409dc635c2d80861/hyperparameter-optimization-pytorch.ipynb
帮你省点力气
当然,所有这些算法——尽管它们都很好——并不总是在实践中起作用。在训练神经网络时还有许多其他因素需要考虑,例如你将如何预处理数据,定义模型,你还需要真的搞定足够跑这一整个流程的计算力。
Nanonets提供易于使用的API来训练和部署自定义深度学习模型。它能负责所有的繁重工作,包括数据扩充,转移学习,以及超参数优化!
Nanonets在其庞大的GPU集群上使用贝叶斯搜索来找到正确的超参数集,你压根不用担心得在最新的显卡上再大花一笔钱啦。
一旦找到最佳模型,Nanonets就会把它放在云端,以便你使用其Web界面测试模型,或使用两行代码将其集成到你的程序中。
跟不完美模型说拜拜吧。
结论
在本文中,我们讨论了超参数和一些优化它们的方法。但这一切意味着什么?
随着人们越来越努力地使AI技术民主化,自动超参数调整可能是朝着正确方向迈出的一步。它允许像你我这样的普通人在没有数学博士学位的情况下构建厉害的深度学习应用程序。
虽然你可能会认为,让模型重度依赖于计算立会导致只有那些能够承受如此计算力的人群获得最好的模型,但像AWS和Nanonets这样的云服务有助于实现我们普通民众对强大机器计算力的访问、使深度学习更容易普及。
但更重要的是,我们真正在这里做什么——用数学来解决更多的数学。这很有意思,不仅因为听起来很酷炫啦,还因为它真的很容易被错误解释。
从打孔卡和excel表时代,到我们”优化优化函数的函数以优化函数“的时代,我们已经走过了漫长的道路。但是,我们依然无法建造能够自己“思考”的机器。
这一点都不令人沮丧,因为如果人类用这么少的东西就能够做到这个高度的话,当我们的愿景变成我们实际可以看到的东西时,想象一下未来会怎样吧!
我们坐在一张衬垫网椅上,盯着一个空白的终端屏幕——每个按键都能给我们一个可以擦干净磁盘的sudo指令。
我们会整天坐在那里一动不动——因为下一个重大突破和我们可能只差一条pip install哦。
相关报道:
https://blog.nanonets.com/hyperparameter-optimization/