深度学习调参手册
这份文件为谁准备?
这份文件是为深度学习模型性能极为感兴趣的工程师和研究人员(包括个人和团队)准备的。我们假设其有一定机器学习和深度学习概念及基本知识。
我们的重点是超参数调整过程。同时也触及了深度学习训练的其他方面,如管道实现和优化,但对这些方面的讲述并不完整。
我们假设机器学习问题是一个监督学习问题或看起来很像一个问题的东西(如自监督)。也就是说,本文中的一些建议可能适用于其他类型的问题。
为什么需要调参手册?
目前,要想让深度神经网络在实践中运行良好,需要付出惊人的努力和猜想。更糟糕的是,人们很少记录获得良好结果的设置 。论文掩盖了导致其最终结果的过程,以呈现一个更干净的故事,而从事商业问题的机器学习工程师很少有时间概括他们的调参过程。教科书倾向于回避实践指导,优先考虑基本原则,即使其作者有必要应用工作经验来提供有效的建议。在准备创建这份文件时,我们找不到任何全面的说明来实际解释如何用深度学习获得好的结果。相反,我们在博客文章和社交媒体上发现了一些建议的片段,从研究论文的附录中窥见了一些技巧,偶尔有关于某个特定项目或管道的案例研究,还有很多困惑。 深度学习专家和不太熟练的从业者使用表面上类似的方法,但取得的结果间存在着巨大的差距。同时,这些专家也欣然承认他们所做的一些事情可能没有充分的理由。随着深度学习的成熟并对世界产生更大影响,社区需要更多资源,涵盖有用的设置,包括所有的实际细节,这对获得良好的结果至关重要。
我们是由5名研究人员和工程师组成的团队,他们已经在深度学习领域工作了很多年,其中一些人早在2006年就开始工作了。我们已经将深度学习应用于语音识别、天文学等各种问题,并在这一过程中学到了很多。这份文件是从我们自己训练神经网络、教导新的机器学习工程师以及为我们的同事提供深度学习实践建议的经验中发展出来的。 尽管看到深度学习从少数学术实验室实践的机器学习方法变成了为数十亿人使用的产品提供动力已经令人欣慰,但作为一门工程学科,深度学习仍然处于起步阶段,我们希望这份文件能鼓励其他人帮助该领域实现实验协议系统化。
这份文件是我们试图清理我们自己的深度学习方法时产生的,因此它代表了作者在写作时的观点,而不是任何形式的客观真理。我们自己在超参数调整方面的挣扎使其成为我们指导的一个重点,但我们也涵盖了在工作中遇到的其他重要问题(或看到的错误)。我们的意图是让这项工作成为一份活的文件,随着我们信仰的改变而不断成长和发展。例如,关于调试和减轻训练失败的材料,我们两年前是不能写的,因为它是基于最近的结果和正在进行的调查。不可避免地,我们的一些建议将需要更新,以考虑到新的结果和改进的工作流程。我们不知道最佳的深度学习配方,但在社区开始写下和辩论不同的过程之前,我们无法找到它。 为此,我们鼓励发现我们的建议有问题的读者提出代替意见,并提供令人信服的证据,以便我们能够更新手册。我们也希望看大可能有不同建议的指南和手册,以便我们能够作为一个社区努力实现最佳过程。 最后,任何标有🤖 的部分都是我们想做更多研究的地方。只有在尝试写完这本手册后,才完全明白在深度学习从业者的工作流程中可以找到多少有趣的和被忽视的研究问题
新项目指南
我们在调参过程中做出的许多决定可以在项目开始时做一次,只有在情况发生变化时才会偶尔重新审核。
我们的指导意见做出以下假设:
- 问题制定、数据清理等基本工作已经完成,在模型架构和训练配置上花时间是有意义的。
- 已经有一个管道设置好了,可以做训练和评估,而且很容易为各种感兴趣的模型执行训练和预测工作
- 适当的衡量标准已经被选择和实施。这些指标应尽可能地代表在部署环境中所测量的内容。
选择模型架构
概述: 当开始一个新项目时,尽量重用一个已经工作的模型。
- 选择一个成熟的、常用的模型架构,先让它工作起来。以后可以建立一个自定义模型
- 模型架构通常有各种超参数,决定模型的大小和其他细节(如层数、层宽、激活函数的类型)
- 因此,选择模型架构实际上意味着选择一个不同的模型系列(每个模型超参数的设置都只有一个)
- 我们将在选择初始配置和提高模型性能的科学方法中考虑选择模型超参数的问题。
- 在可能的情况下,尽量找到一篇解决手头问题的论文,并以该模型为起点进行复制。
选择优化器
概述: 从当前问题中最流行的优化器开始
- 在所有类型的机器学习问题和模型架构中,没有哪个优化器是“最好”的。即使只是comparing the performance of optimizers is a difficult task.🤖
- 我们建议使用成熟的、受欢迎的优化器,特别是在开始一个新项目时。
- 理想情况下,选择用于同类型问题最流行的优化器
- 对所选优化器的所有超参数给予关注。
- 具有更多超参数的优化器可能需要更多的调整努力来找到最佳配置。
- 这在项目的开始阶段尤其重要,因为我们正试图找到其他各种超参数(如架构超参数)的最佳值,同时将优化器超参数 视为nuisance parameters.
- 在项目的最初阶段,可能最好从一个比较简单的优化器开始(如带动量的SGD或者Adam带 , 和 ) 以后再换成一个更通用的优化器
- 我们喜欢的成熟的优化器包括(但不限于 ):
- SGD with momentum(我们更喜欢Nesterov变体)
- Adam and NAdam,比带动量的SGD更普遍。请注意,Adam有4个可调整的超参数,他们可能都是重要的and they can all matter!
- 参考 How should Adam's hyperparameters be tuned?
选择batch size
概述: batch size控制着训练速度,不应该被用来直接调整验证集的性能。通常情况下,理想的batch size是可用硬件所支持的最大batch size
- batch size是决定训练时间和计算资源消耗的一个关键因素
- 增加batch size往往会减少训练时间。这可能是非常有益的,因为:
- 可以在一个固定的时间内对超参数进行更彻底的调整,可能会产生一个更好的最终模型
- 减少开发周期,可以更频繁的测试新想法
- 增加batch size可能会减少、增加或不改变资源消耗
- batch size不应该被当作验证集性能的课调整超参数
- 只要所有的超参数都调的很好(尤其是学习率和正则化超参数),并且训练step的数量足够多,使用任何batch size都应该可以达到相同的最终性能(参考Shallue et al. 2018)
- 参考 Why shouldn't the batch size be tuned to directly improve validation set performance?
确定可行的batch size并估计训练工作量
[Click to expand]
- 对于一个给定的模型和优化器,通常会有一个可用硬件支持的batch size范围。限制性因素通常是加速器内存。
- 不幸的是,如果不允许或至少不编译完整的训练程序,就很难计算出多大的batch size适合于内存。
- 最简单的解决方案通常是以不同的批量大小(例如增加2的幂)运行训练程序,进行少量的steps,直到其中一个程序超过了可用的内存。
- 对于每个batch size,我们应该训练足够长的时间,以获得对训练吞吐量的可靠估计。
- 当加速器还没有饱和时,如果批处理量增加一倍,训练吞吐量也应该增加一倍(或者至少接近一倍)。等价地,随着批处理量的增加,每步的时间应该是恒定的(或者至少是接近恒定的)。
- 如果不是这样,那么训练管道就有一个瓶颈,如I/O或计算节点之间的同步。这可能值得在继续进行之前进行诊断和纠正。
- 如果训练吞吐量只增加到某个最大batch size,那么我们应该只考虑到该最大吞吐量,即使硬件支持更大的batch size。
- 使用较大的batch size的所有好处都是假设训练的吞吐量增加。如果没有,那就解决瓶颈问题或使用较小的batch size。
- **梯度累积(Gradient accumulation)**模拟的batch size比硬件所能支持的要大,因此不能提供任何吞吐量的好处,一般来说,在应用工作中应避免使用它。
- 这些steps可能需要在每次改变模型或优化器时重复进行(例如,不同的模型架构可能允许更大的批处理量以适应内存)
选择batch size尽可能减少训练时间
[Click to expand]
训练时间 = (每steps时间) x (总steps)
- 我们通常可以认为当没有并行计算开销,并且所有的训练瓶颈都已被诊断和纠正时,每一步的时间对于所有可行的batch size来说都是近似恒定的。(参考上一节for how to identify training bottlenecks )在实践中,通常至少有一些增加batch size大小的开销。
- 随着batch size的增加,达到固定性能目标所需的总steps通常会减少(前提是当batch size大小改变时,所有相关的超参数都被重新调整,参考Shallue et al. 2018)。
- 例如,增加一倍的批处理量可能使所需的总步骤数减半。这就是所谓的 完美缩放。
- 完美的缩放性对所有的batch size都是成立的,直到一个临界batch size,超过这个临界batch size,就会取得递减的回报
- 最终,增加batch size不再减少训练steps(但也不会增加)。
- 因此,使训练时间最小化的batch size通常是仍能减少所需训练steps的最大batch size。
- 这个batch size取决于数据集、模型和优化器,除了对每一个新问题进行实验发现之外,如何计算它是一个问题。 🤖
- 在比较batch size时,要注意示例预算/epoch预算(在固定训练例子展示数量的情况下运行所有试验)和steps预算(在固定训练steps数量的情况下运行所有试验)之间的区别
- 用一个历时预算来比较batch size,只能探测到完美的缩放尺度,即使更大的batch size可能仍然通过减少所需的训练steps来提供加速。
- 通常情况下,可用硬件支持的最大batch size将小于临界batch size。因此,一个好的经验法则(没有进行任何实验)是使用尽可能大的批处理量。
- 如果最终增加了训练时间,那么使用更大的batch size是没有意义的。
选择batch size以尽量减少资源消耗
[Click to expand]
- 有两种类型的资源成本与增加batch size有关:
- 前期成本,如购买新硬件或重写训练管道以实现多GPU/多TPU训练
- 使用成本,例如,根据团队的资源预算计费,从云供应商处计费,电力/维护成本
- 如果增加batch size有很大的前期成本,那么推迟增加batch size可能更好,直到项目成熟,更容易评估成本效益的权衡。实施多主机并行训练可能会引入错误和微小问题,因此,无论如何,一开始就用一个比较简单的管道可能会更好。(另一方面,当需要进行大量的调整实验时,训练时间的大幅加速可能 会在早期非常有利)
- 我们把总的使用成本(可能包括多种不同类型的成本)称为“资源消耗”。我们可以将资源消耗分解为以下几个部分。
资源消耗 = (setp资源消耗) x (总steps)
-
增加batch size通常可以减少总steps。资源消耗是增加还是减少,将取决于每个step的消耗如何变化。
- 增加batch size可能会减少资源消耗。例如,如果大batch size每个step都可以在与小batch size相同的硬件上运行(每一步只增加少量时间),那么每个step资源消耗的增加可能被step数的减少所抵消。
- 增加batch size可能不会改变资源消耗。例如,如果将batch size增加一倍,所需steps减少一半,所使用的GPU数量增加一倍,总消耗量(以GPU小时计)将不会改变。
- 增加batch size可能会增加资源消耗。例如,如果增加batch size需要升级硬件,每step消耗的增加可能超过steps的减少
改变batch size需要重新调整大多数超参数
[Click to expand]
- 大多数超参数的最优值都对batch size很敏感。因此,改变batch size通常需要重新开始调整过程
- 与batch size相互作用最强的超参数是优化器超参数(如学习率、动量)和正则化超参数,因此对每个batch size进行单独调整最为重要
- 在项目开始时选择批量大小时要记住 这一点。如果你以后需要切换到不同的批量大小,为新的批量大小重新调整一切,可能会很困难,浪费时间,也很昂贵。
batch norm如何与batch size相互作用
[Click to expand]
- batch norm很复杂,一般来说,应该使用与梯度计算不同的batch size来计算统计数据。详细讨论参考batch norm部分
选择初始配置
- 在开始超参数调整之前,我们必须确定起点。这包括指定(1)模型配置(如层数),(2)优化器超参数(如学习率),(3)训练steps数量
- 确定初始配置将需要一些手动配置以及训练运行和试错
- 我们的指导原则是找到一个简单、相对快速、相对低资源消耗的配置,获得“合理”的结果
- “简单”意味着尽可能的避免使用“华丽的搭配”,这些可以在以后添加。即使这些”华丽的搭配“被证明是有帮助的,在最初的配置中加入它们也有可能浪费时间来调整无用的功能和/或加入不必要的复杂因素。
- 例如在增加花哨的衰减时间表之前,先从一个恒定的学习率开始
- 选择一个快速的、消耗最少资源的初始配置,将使超参数调节的效率大大提升。
- 例如,从一个较小的模型开始。
- "合理的"性能取决于问题,但至少意味着训练好的模型在验证集上的表现比随机选择好得多(尽管它可能差到不值得部署)。
- “简单”意味着尽可能的避免使用“华丽的搭配”,这些可以在以后添加。即使这些”华丽的搭配“被证明是有帮助的,在最初的配置中加入它们也有可能浪费时间来调整无用的功能和/或加入不必要的复杂因素。
- 选择训练steps的数量涉及平衡以下紧张关系:
- 一方面, 更多steps的训练可以提高性能,并使超参数的调整更容易 (参考Shallue et al. 2018).
- 另一方面,较少steps的训练意味着每次训练运行的速度更快,使用的资源更少,通过减少周期之间的时间来提高调参效率,并允许更多的实验被并行运行。此外,如果最初选择了一个不必要的大steps预算,那么接下来可能就很难改变了,例如,一旦学习率计划被调整为该步数。
提高模型性能的科学方法
就本文而言,机器学习开发的最终目标是最大化所部署模型的效用。即使开发过程的许多方面在不同的应用中有所不同(如时间长度、可用的计算资源、模型的类型),我们通常可以在任何问题上使用相同的基本步骤和原则。
我们下面的指导意见做出了以下假设:
- 已经有一个完全运行的训练管道,以及一个获得合理结果的配置。
- 有足够的计算资源可用于进行有意义的调参实验,并至少并行运行几个训练作业。
渐进式调整策略
概述: 从简单的配置开始,逐步进行改进,同时建立对问题的洞察力。确保任何改进都是基于强有力的证据,以避免增加不必要的复杂性。