作者:京东零售 彭馨
谷歌大脑的五位深度学习大佬在 “Chinese New Year” 期间合作推出了《深度学习调参手册》,来为各位深度学习爱好者恭贺新年(我猜的),一时间好评如潮,获星过万,看来大家都是苦调参久已。难道依靠经验的调参变得“可解释”了?显然不是,而是大佬们分享自己的调参经验,内容还是挺多的,下面咱们去粗取精,希望能够获得飞升。
一、新项目指南
调参并不是开始项目的第一步,在此之前,我们要完成一些必要的基本工作,如 问题制定、数据清洗、pipeline 设置、评估指标 等确定后,花时间在模型架构和训练配置上才有意义。
1.选择模型架构
• 在进行一个新项目时,首先要尝试重用已经经过验证并有效的模型。如果要新开发,也应该选择一个完善、常用的模型架构先来开展工作,之后再去慢慢构建自己的自定义模型。
• 模型架构具有一系列的超参数,如 层数、层宽度、激活函数 等,选择架构实际上是选择具有不同超参数的模型,后面的 选择初始配置 和 提高模型性能的科学方法 主要是讲选择模型超参数的问题。
• 如果能找到一篇接近解决手头问题的论文,并将其中模型进行复现,是个很好的选择。
2.选择优化器(optimizer)
• 没有哪个优化器能说是“最好的”,优化器性能的比较也是任务艰巨,所以 建议使用成熟、流行的优化器,尤其是在进行新项目时。理想情况下,对于同一类型的问题最好选择最流行的优化器。
• 优化器的每个参数都是很重要的,超参数多的优化器可能要调参更久。
• 项目开始阶段,先从简单的开始,如固定动量的 SGD 或固定ϵ、_β_1和_β_2的 Adam,之后再切换到更通用的优化器。
• 作者喜欢的比较完善的优化器有:动量 SGD(Nesterov 变体)、Adam 和 NAdam(比动量SGD更通用,Adam有4个很重要的可调超参数)
3.选择批量大小(batch_size)
• batch_size 决定训练速度,而不是为了直接提高验证集的效果。通常,硬件能够支持的最大 batch_size 就是理想值。增大 batch_size 通常会减少训练时间,这样就有更多的时间调参,发现更好的模型,还可以尝试更多新思路。
• 增加 batch_size 在资源消耗上时不固定的,可能会减少、增加或不改变。
• 只要调整好所有超参数(尤其是学习率和正则化超参数)并且训练步数足够,使用任何批量大小都应该可以获得相同的最终性能。
3.1 确定可行的 batch_size 并估计训练吞吐量
• batch_size 受到加速器内存的限制,所以最合适的 batch_size 需要训练代码去试出来😂,最简单的方案是按2的幂增加 batch_size 去训练几步,看哪个会超出内存。
• batch_size 和训练吞吐量(每秒处理样本数)是成正比的,增大 batch_size 是为了增大吞吐量,这样才能减少训练时间,如果 batch_size 增加而训练吞吐量没啥变化,则说明 pipeline 存在瓶颈,例如 I/O 或计算节点之间的同步,此时需要进行诊断和纠正或者使用吞吐量最大的 batch_size。
• 每次更改模型或优化器时,都需要重新选择 batch_size,毕竟不同的模型架构对内存消耗是不同的。
3.2 选择 batch_size 以最小化训练时间
• 理论上,对于可行的 batch_size,每步的时间应该近似恒定。实际是,增加 batch_size 通常至少会产生一些开销。
• batch_size 的增加,会使达到目标的总步数减少(前提是 batch_size 更改时,其他相关参数要重新调整)。将 batch_size 加倍可能会使所需的总步数减半。这称为 完美缩放。完美缩放在临界 batch_size 内一直适用,超过了将会收益递减,最终,增加 batch_size 不再减少训练步数(但永远不会增加)。
◦ 在不进行实验的情况下,一个好的经验法则是使用尽可能大的 batch_size。
3.3 选择 batch_size 以最小化资源消耗
• batch_size 的增加要权衡前期成本(硬件)与收益。
• 实施多主机并行训练程序可能会引入错误或其他问题,因此最好从更简单的 pipeline 开始。在需要大量调整实验过程的早期阶段,加速训练时间大有好处。
3.4 更改 batch_size 需要重新调整大多数超参数
• 大多数超参数的最优值对 batch_size 是敏感的。因此,更改 batch_size 通常需要重新调参。
• 相互作用最强的超参数是优化器超(例如学习率、动量)和正则化超参数,因此对于每个 batch_size 都分别进行调参非常重要。
• batch_size 最好能尽快确定,不要频繁切换,因为,新的 batch_size 需要重新调整所有内容,可能会很困难、耗时且成本高昂。
4 选择初始配置
• 在开始超参数调整之前,有一些参数需要先确定: (1) 模型配置(例如层数),(2) 优化器超参数(例如 learning_rate),(3) 训练步数等,这些初始配置也是需要手动运行和反复试验的😂,指导原则是找到一个简单、相对快速、资源消耗相对较低的配置,以获得“合理”的结果。
◦ 花里花哨的配置前期最好不用(尽管可能有用),因为不仅耗时,甚至会影响其他超参数的调整。
◦ 选择快速且消耗最少资源的初始配置将使超参数调整更加高效,例如,开始先用一个小模型。
• 选择步数要考虑两方面的平衡:一方面,训练更多的步骤可以提高性能并使超参数调整更容易;另一方面,更少步骤的训练意味着每次训练运行得更快并且使用更少的资源。此外,如果开始步数过高,之后可能很难更改(涉及其他相关超参数)。
二、提高模型性能的科学方法
机器学习开发的最终目标是最大化已部署模型的效用,对任何问题使用的基本步骤和原则是相同的。
1.增量调整策略
• 增量其实就是从简单的开始,逐步进行改进,但要保证每次改进都是有理有据的,随机的幸运配置可能会给 pipeline 增加不必要的复杂性。
• 为了找到使模型效果最大化的配置,可以使用算法自动搜索配置,但搜索空间较大,需要手动涉及搜索空间,该空间定义了要搜索的配置集,非常重要。
• 在每一轮调整中都使用自动搜索算法,并随着我们理解、经验的增长,需要不断更新搜索空间。
本章节之后的内容则主要是介绍增量调优策略的四个步骤:
为下一轮实验确定范围适当的目标。
设计并运行一组实验,朝着这个目标取得进展。
从结果中了解我们能做什么。
考虑是否推出新的最佳配置。
2.探索与开发
深入了解问题(对问题的洞察力)相较于提升验证集效果的短期收益来说更重要。
• 避免仅通过历史事件就在表现良好的运行中进行不必要的更改。
• 确定验证错误对哪些超参数最敏感,哪些超参数交互最多,因此需要一起重新调整,以及哪些超参数对其他变化相对不敏感,因此可以在未来的实验中修复。
• 建议尝试使用潜在的新功能,例如在出现过拟合问题时使用新的正则化器。
• 确定无用的功能,可以将其删除,从而降低未来实验的复杂性。
• 识别调参的改进可能已经饱和。
• 围绕最佳值缩小我们的搜索空间,以提高调整效率。
如果最终准备贪婪搜索整个配置空间,那么我们可以完全关注验证集效果。
3.选择下一轮实验的目标
每一轮实验都应该有一个明确的、窄范围的目标,这样实验才能真正朝着目标进展:如果我们试图一次添加多个特征或回答多个问题,可能无法理清各自对结果的的影响。
示例目标:1.尝试对管道进行潜在的改进(如,新的正则化器、预处理选择等);2.了解特定模型超参数(例如激活函数)的影响;3.贪婪地最大化验证错误。
4.设计下一轮实验
• 超参数被定义为以下三种:
◦ 科学超参数:对衡量模型性能有影响的参数。
◦ 讨厌超参数(类似于统计学中的有害超参数):需要优化的超参数(顾名思义😂),以便公平地比较科学超参数的不同值。
◦ 固定超参数:在当前轮次实验中固定值的参数。在比较科学超参数的不同值时,这些超参数的值不需要(或者我们不希望它们)改变。
◦ 例如:如果目标是“确定具有更多隐藏层的模型是否会减少验证错误”,那么隐藏层数就是科学的超参数,学习率需要跟着模型架构调整,那它就是有害超参数,而已被验证对模型深度不敏感的激活函数的选择,就是固定超参数。
◦ 这三者不是固定的,而是根据实验目标转变,之前的科学超参也会成为有害超参。三者之间某些情况下也是相互影响的。
◦ 在设计下一轮实验时,要确定实验目标的科学超参数。实际中我们需要频繁调参的,其实主要是讨厌超参数,包括学习率、优化器参数、正则化参数等,但是否用正则化则是科学超参数或固定超参数。
5.加强对实验结果的洞察力
在实验取得进展之前,可以思考以下额外的问题:
- 搜索空间是否足够大?
◦ 如果从中采样的最佳点靠近其边界,则搜索空间是可疑的。朝其方向扩大搜索范围,可能会找到更好的点。
◦ 为了检查搜索边界,可以将模型错误率与超参关联分析,绘图比较明显。
- 是否从搜索空间采样了足够多的点?
◦ 是否足够这个问题很难评估,建议在资源允许的情况下,尽可能多的采样。
- 可以从最佳训练曲线中学到什么?
◦ 检查训练曲线是识别常见故障模式的一种简单方法,可以帮助确定下一步要采取行动的优先级。
▪ 是否表现出过拟合?
▪ 当验证错误在训练期间的某个时刻开始增加时,就会出现过拟合。用正则化技术解决过拟合很简单。
▪ 如果科学超参数是“隐藏层数”,并表现出过拟合,那么通常使用额外的正则化进行尝试更好,而不是立即选择较小数量的隐藏层。
▪ 训练后期的训练错误或验证错误是否存在高阶跃方差?
▪ 是的话,可能会干扰比较科学超参数不同值的能力(每个试验的结束过程是随机的),以及生产中重现最佳试验结果的能力(因为生产模型可能不会以与研究中相同的“幸运”步骤结束)。
▪ 高阶跃方差的最可能原因是批次方差、小验证集以及在训练后期使用过高的学习率。
▪ 可能的补救措施包括增加批量大小、获取更多验证数据、使用学习率衰减或使用 Polyak 平均。
▪ 训练结束时指标是否仍在改进?
▪ 是的话,表明处于“计算限制”,可以增加训练步数或改变学习率。
▪ 训练集和验证集的性能在最后的训练步骤之前很久就饱和了吗?
▪ 是的话,表明处于“不受计算限制”,可以减少训练步数。
▪ 训练期间训练损失增加通常表明 pipeline 中存在错误。
- 尽可能自动绘制不同超参数的轴图
6.判断超参数是否要调整
在更改模型、pipeline或超参数之前,需要知道导致结果不同的原因,因为即使配置都相同的两次试验,也会因为随机数、数据清洗、mask等的不同而导致结果差异,这部分的方差可以通过多次试验进行识别。
7.探索结束后
完成了搜索空间的探索并决定了要调整哪些超参数,可以用这些超参数构建搜索空间,准随机搜索的许多优势就没有了,而贝叶斯优化工具 对自动找到最佳超参数配置来说是一个很好的选择。使用 黑盒优化工具 可以处理搜索空间的发散点。
三、确定每次训练运行的步数
1.训练不受计算限制时
• 主要目标是确保训练足够长的时间以使模型达到最佳结果,同时避免在训练步数上过度浪费。
• max_train_steps 最好选择一个值并将其用于所有试验。然后从这些试验中绘制回顾性检查点,来选择最优的 max_train_steps。
• max_train_steps 的初始值可以通过使用恒定学习率来确定:
◦ 如果损失平稳下降直到满足精度要求,则说明初始值是适合的。
◦ 如果训练过程中梯度噪声增加(如引入了数据增强或dropout等正则项),则可能需要增大 max_train_steps.
◦ 如果训练过程有所改进,则可以减小 max_train_steps。
• 在不使用数据增强和正则项的情况下,可以网格搜索不同的学习率,来选择则合适的 max_train_steps,但要保证最佳学习率不在搜索空间边界。
2.训练受计算限制时
某些情况下,训练损失会一直改善,但耐心和计算资源会成为限制。
• 损失一直在改善,我们也没必要一直训练下去,可以通过训练很多较短的试验来调参。
• 训练多轮也是明智的做法,通常1-3轮最实用。
• 此处建议进行2轮调整:
◦ 第 1 轮:较短的运行时间以找到好的模型和优化器超参数。
▪ 不能确保短的、不完整训练的超参数一直是好的超参,是否可以迁移到最终模型的超参,可以排个序:
▪ 极有可能迁移:Warmup length、初始化
▪ 可能迁移:模型架构
▪ 有可能迁移:数据增强、正则化
▪ 不太可能迁移:学习率
◦ 第 2 轮:在良好的超参数点上避免长时间运行来获得最终模型。
▪ 运行第一轮最佳超参数配置
▪ 第i轮-->第i+1轮,最大问题是如何调整学习率衰减时间表。在轮次之间调整学习率计划时,常见的陷阱是使用额外的训练步数但学习率太小。
四、FAQs
- 最好的学习率衰减时间表是什么?
◦ 目前还不知道如何构建试验来找到最佳的 LR 衰减时间表。
- 我应该使用哪种学习率衰减作为默认值?
◦ 作者偏好是 线性衰减 或 余弦衰减,当然也存在其他的可能也不错。
- 为什么有些论文有复杂的学习率表?
◦ 很多论文中复杂的分段学习率 (LR) 衰减时间表是根据验证集效果临时调整得到的:先使用简单的 LR 衰减(或恒定学习率)开始单次训练运行,如果表现不好,则停止训练,使用更陡的 LR,重复此过程。
◦ 随意复制不是一个好主意,因为最佳的 LR 将对许多其他超参数选择敏感。
- Adam 的超参数应该如何调整?
◦ 搜索空间的设置以及应该从搜索空间中采样多少点是很难描述的。Adam 中的所有超参数并不是都同等重要。以下提供了几条经验:
▪ 如果一项研究中有 < 10 次试验,则只调整(基础)学习率。
▪ 如果 10-25 次试验,调整学习率和β1
▪ 如果超过 25 次试验,调整学习率,β_1和_ϵ
▪ 如果可以运行超过 25 次试验,另外调整β2
- 为什么在优化的探索阶段使用准随机搜索而不是更复杂的黑盒优化算法?
◦ 准随机搜索(基于低差异序列)在迭代调优过程中旨在最大限度地洞察调优问题(称为“探索阶段”) . 更复杂的黑盒优化算法(贝叶斯优化、进化算法等)更适合开发阶段。
◦ 基于随机移动的低差异序列的准随机搜索是“抖动的、打乱的网格搜索”,它统一但随机,比随机搜索更分散搜索点。
◦ 与黑盒优化工具相比,准随机搜索的优势包括:
▪ 准随机搜索的非自适应特性使得无需重新运行任何实验即可根据最终验证误差、训练误差或某些替代评估指标找到最佳试验成为可能。
▪ 可以实现回滚。
▪ 自适应黑盒优化算法可能会忽略搜索空间的中间部分。
▪ 并行运行与顺序运行不同数量的试验不会产生统计上不同的结果。
▪ 复杂的搜索算法可能并不总能正确处理不可行的点,特别是如果它们在设计时未考虑神经网络超参数调整。
▪ 准随机搜索很简单,并且在许多调整试验将并行运行时特别有效。自适应算法对使用者要求比较高。
◦ 当然,如果计算资源只允许少量试验并行运行,而我们有能力按顺序运行许多试验,那么贝叶斯优化就会变得更有吸引力,尽管这会使调整结果更难解释。
- 在哪里可以找到准随机搜索的实现?
◦ 我们可以为给定的搜索空间生成 Halton 序列。
◦ 如果基于低差异序列的准随机搜索算法不可用,则可以替代伪随机均匀搜索,尽管可能效率稍低。
- 为什么不应该调整 batch_size 来直接提高验证集性能?
◦ 在不改变 pipeline 的情况下改变 batch_size 通常会影响验证集的性能。
◦ 如果针对不同的 batch_size 独立优化吧pipeline,则两个 batch_size 之间的验证集效果差异通常会消失。
◦ 与 batch_size 交互最强烈且最应该调整的是优化器超参数(如学习率、动量)和正则化超参数。
▪ 由于样本方差,较小的 batch_size 会在训练算法中引入更多噪声,并且这种噪声可能具有正则化效果。因此,较大的 batch_size 更容易过拟合,并且可能需要更强的正则化和/或额外的正则化技术。
◦ 更改 batch_size 时可能需要调整训练步数。
◦ 目前还没有证据表明 batch_size 会影响最大可实现的验证效果。
五、总结
通读之后,感觉更多的是一种调参的思想、原则,属于内功心法,而我们可能更需要快、准、狠的实战技能,看一眼就知道攻它哪三路(比如多分类等问题的损失函数比较)😂。当然,调参毕竟是个重经验的活,这也能让我们以后少走一些弯路。