转载:https://github.com/schrodingercatss/tuning_playbook_zh_cn
深度学习调优指南中文版
这不是官方认证的 Google 产品。
Varun Godbole † , George E. Dahl † , Justin Gilmer † , Christopher J. Shallue ‡ , Zachary Nado †
† 谷歌研究,谷歌大脑团队
‡ 哈佛大学
本文档适用于对最大化深度学习的性能感兴趣的工程师和研究人员(包括个人和团队)。我们假定您具备机器学习和深度学习概念的基本知识。
我们的重点是超参数调优的过程,但我们还涉及深度学习学习的其他方面。例如工作流实施和优化,但这些方面并不详尽
我们假设机器学习问题是监督学习或类似的东西(例如自监督学习)。但是,本文档中描述的技术也可能适用于其他类型的问题。
目前,要使深度神经网络在实践中正常运行,需要付出大量的努力和猜测。更糟糕的是,目前很少有人记录下那些深度学习中获得良好结果的实际方法。一方面,通常,论文忽略了导致最终结果的过程,以呈现更清晰的原理。另一方面,处理商业问题的机器学习工程师很少有时间回顾并概括他们的调参过程。教科书也往往回避实用指南,而偏重于基本原理,即使它们的作者具有在应用工作中提供有用建议的经验。在准备创建此文档时,我们找不到任何系统性的资料来解释如何使用深度学习获得良好的结果. 相反,我们看到了博客文章和社交媒体上的建议片段、从研究论文附录中收集的技巧、特定项目或工作流的偶然案例研究,以及很多困惑。在深度学习领域,专家和新手用着表面上类似的方法,但所取得的结果之间存在着巨大的差距。与此同时,这些专家也很乐意承认他们所做的一些事情可能没有充分的理由。随着深度学习的成熟并对世界产生更大的影响,社区需要更多涵盖有用方法的资源,包括对于获得良好结果至关重要的所有实用细节。
我们是一个由五名研究人员和工程师组成的团队,多年来一直致力于深度学习。我们已经将深度学习应用到从语音识别到天文学的方方面面,并在此过程中学到了很多东西。本文档源于我们自己训练神经网络、教授学生以及为我们的同事提供实践建议的经验。虽然深度学习已经从少数学术研究实验室中实践的机器学习方法发展成为为数十亿人使用的产品提供动力的技术,但深度学习在工程领域仍处于起步阶段,我们希望本文档能鼓励其他人也来帮助系统化该领域的实验细节。
这份文件是在我们试图实现我们自己的深度学习方法时产生的,因此它只代表作者在撰写本文时的观点,而不是任何客观事实。它被特别强调是因为我们在调整超参数方面遇到了困难,但它也涵盖了我们在工作中遇到(或看到出错)的其他重要问题。我们希望这项工作成为一份活的文件,能随着我们理解的改变从而成长和演变。例如,一份关于如何调试和如何减少训练失败的文档在两年前是不可能写出来的,因为它这得基于最近的结果和正在进行的研究。不可避免地,我们的在此文档中一些建议也将需要更新以考虑新的结果和改进的工作流程。我们不知道最好的深度学习秘诀,但在大众开始记录它并讨论各个步骤之前,我们不能指望找到它。为此,我们鼓励发现我们的建议存在问题的读者提出替代建议以及令人信服的证据,以便我们更新建议。我们也希望看到可能有不同建议的替代指南和方式,以帮助大众追求最佳方法。最后,任何标有🤖表情符号的地方是我们要进一步调查的地方。只有在尝试编写这本 playbook 之后,我们才完全清楚在深度学习从业者的工作流程中可以找到多少有趣及被忽视的研究问题。
在调优过程中的许多抉择,我们可以在项目开始时一次性做出决定。只有偶尔在情况发生变化时,才需要重新考虑。
在开始调优之前,请确保您满足以下假设:
问题制定、数据清理等基本工作已经完成,花时间在模型架构和训练配置上是有意义的。
已经有一个工作流设置用来进行训练和评估,并且可以很容易地为各种感兴趣的模型执行训练和预测工作。
已选择并实现适当的评估指标。这些指标应该尽可能地代表在部署环境中测量的内容。
总结: 在开始一个新项目时,尽量重用有效的模型。
首先选择一个完善且常用的模型架构来开始工作。这样可以尽早让模型进入工作状态,之后再构建自定义模型也是可行的。
模型架构通常具有各种超参数,用于确定模型的大小和其他细节(例如层数、层宽度、激活函数类型)。
因此,选择架构实际上意味着选择一整个系列的各种模型(每个模型都有不同的超参数设置)。
如果可以的话,请尝试找到一篇尽可能接近手头问题的相关论文,并将复现该论文中的模型作为起点。
总结: 从针对手头问题类型的最常用的优化器开始。
没有一个优化器是适用于所有类型的机器学习问题和模型架构的‘最佳’优化器。即使只是 比较优化器的性能也是一项艰巨的任务。 🤖
我们建议坚持使用成熟、流行的优化器,尤其是在开始新项目时。
理想情况下,选择用于同类问题的最常用优化器。
做好关注选择的优化器的 *所有* 超参数的准备。
具有更多超参数的优化器可能需要更多的调优工作才能找到最佳配置。
当我们试图找到各种其他超参数(例如架构超参数)的最佳值时,将优化器超参数视为冗余参数是有意义的,这在项目的初始阶段尤其重要。
在项目的初始阶段,从更简单的优化器开始会更可取(例如,具有固定动量的 SGD 或具有固定 ϵ、$\beta_{1}$ 和 β2 的 Adam ) ,之后可以切换到更通用的优化器。
常用且较为完善的优化器包括(但不限于):
SGD with momentum(Nesterov 变体)
Adam and NAdam,它们比具有动量的 SGD 更通用。请注意,Adam 有 4 个可调超参数,他们都很重要!
参见 [Adam 的超参数应该如何调整?](#Adam 的超参数应该如何调整?)
总结: Batch Size决定训练速度,并且不应该被直接用于调整验证集性能。通常来说,可用硬件支持的最大Batch Size是较为理想的数值。
Batch Size是决定训练时间和计算资源消耗的关键因素。
增加Batch Size通常会减少训练时间。这非常有益,因为它:
能使固定时间间隔内超参数调整更彻底,最终训练出更好的模型。
减少开发周期的延迟,能更多地测试新想法。
资源消耗和Batch Size之间并没有明确的关系,增加Batch Size让资源消耗增加、减少或是保持不变都有可能。
Batch Size不应该被当作验证集性能的可调超参数。
只要调整好所有超参数(尤其是学习率和正则化超参数)并且训练步数足够,理论上任意的Batch Size都能获得相同的最终性能(参见 Shallue et al. 2018) .
详见 [为什么不应该调整Batch Size来直接提高验证集性能?](#为什么不应该调整Batch Size来直接提高验证集性能?)
[点击展开]
[点击展开]
[点击展开]
[点击展开]
Batch Norm会对Batch Size的选择造成什么影响?
[点击展开]
在开始超参数调整之前,我们必须确定起点。这包括指定 (1) 模型配置(例如层数),(2) 优化器超参数(例如学习率),以及 (3) 训练步数。
确定此初始配置将需要一些手动配置的训练运行和反复试验。
我们的指导原则是找到一个简单、相对快速、资源消耗相对较低的配置,以获得“合理”的结果。
“简单”意味着尽可能避免花里胡哨的东西;这些总是可以在以后添加。即使花里胡哨的东西在未来被证明是有用的,但在初始配置中添加它们可能会浪费时间调整无用的功能和/或烘烤不必要的并发症。
例如,在添加花哨的衰减方案之前以恒定的学习率开始。
选择快速且消耗最少资源的初始配置将使超参数调整更加高效。
例如,从较小的模型开始。
“合理”性能取决于问题,但至少意味着经过训练的模型在验证集上的性能比随机机会好得多(尽管它可能很糟糕,不值得部署)。
选择训练步数的数量涉及平衡以下方面:
一方面,训练更多的步数可以提高性能并使超参数调整更容易(参见 Shallue et al. 2018)。
另一方面,更少步数的训练意味着每次训练运行得更快并且使用更少的资源,通过减少周期之间的时间并允许并行运行更多实验来提高调整效率。此外,如果一开始选择了一个不必要的大训练步数,那么以后可能很难改变它,例如,已经将学习率针对该步数进行了调整。
机器学习开发的最终目标是最大化模型的效用。尽管不同应用场景的开发流程有所不同(例如时间长度、可用计算资源、模型类型等),基本步骤和原则都是相似的。
接下来的指南中我们做出了这些假设:
已有能运行且得到不错结果的训练工作流。
有足够的计算资源来进行调参实验,至少能够并行发起数个训练流程。
总结: 从简单的配置开始,循序渐进,同时进一步了解问题。确保任何改进都有据可循,以避免增加不必要的复杂度。
我们的最终目标是找到一种训练配置来最大化我们模型的性能。
在某些情况下,我们的目标是在固定截止日期(例如提交给竞赛)之前最大限度地改进模型。
在其他情况下,我们希望无限期地改进模型(例如,不断改进生产中使用的模型)。
原则上,我们可以使用算法自动搜索整个配置空间来最大化性能,但实践中这往往不实际。
配置空间可能非常大,目前还没有任何算法可以在没有人工指导的情况下有效地搜索这个空间。
大多数自动搜索算法依赖于人工设计的搜索空间,这些搜索空间往往非常重要。
更有效的方法是从简单的配置开始,逐步添加功能并进行改进,同时深化对问题的理解。
我们在每一轮调整中都使用自动搜索算法,并随着我们理解的深度不断更新我们的搜索空间。
随着我们的探索,我们自然会找到越来越好的配置,因此我们的“最佳”模型将不断改进。
当我们更新我们的最佳配置时,我们称之为上线(这不一定对应线上模型的实际上线)。
对于每次上线,我们必须确保更改是有据可循的——而不仅仅是碰运气找到的配置——以避免给训练工作流增加不必要的复杂性。
综上所述,我们的增量调优策略需要重复以下四个步骤:
为下一轮实验确定适当的目标。
设计并展开实验,朝着这个目标取得进展。
从实验结果中获取经验。
考虑是否上线新的最佳配置。
本节的其余部分将更详细地讲解增量调优策略。
总结: 大多数时候,我们的目标是更深入地理解问题。
尽管有些人认为我们会花大部分时间来提升验证集的指标,实际上我们把重心放在进一步理解问题上,而不是降低验证集错误率。
也就是说,我们大部分时间都花在了“探索”上,只有一小部分时间花在了“利用”上。
从长远来看,如果我们想最大化我们的最终效果,深入理解问题是至关重要的。将深化理解置于短期收益之上可以帮助我们:
避免仅因历史原因而表现良好的不必要更改。
确定验证集效果对哪些超参数最敏感,哪些超参数交互最多,因此需要一起重新调整,以及哪些超参数对其他变化相对不敏感,因此可以在未来的实验中固定住。
发现潜在的新方向,例如在出现过拟合问题时使用新的正则化器。
确定无效的方向并将其删除,从而降低后续实验的复杂度。
判断超参数的优化空间是否已经饱和。
围绕最佳值缩小我们的搜索空间,以提高调整效率。
最终,我们可以集中提升验证集效果,即便我们无法从新的实验中进一步了解问题的结构了。
总结: 每轮实验都应该有一个明确的目标,并且范围要足够小,这样实验才能真正朝着目标取得进展。
每轮实验都应该有一个明确的目标,并且范围要足够小,这样实验才能真正朝着目标取得进展:如果我们试图一次添加多个特征或回答多个问题,我们可能无法理清各自的影响。
举个例子,目标可以包括:
尝试对训练流程进行改进(例如,新的正则化器、预处理方法等)。
了解特定模型超参数(例如激活函数)的影响
最大化验证集指标。
总结: 根据实验目标,将超参数分为三类:目标超参数、冗余超参数和固定超参数。创建一系列研究以比较目标超参数的不同值,同时优化冗余超参数。注意选择冗余超参数的搜索空间,以平衡资源成本与科学价值。
[点击展开]
[点击展开]
[点击展开]
总结: 除了尝试实现每组实验的原始科学目标之外,还要检查其他问题的清单,如果发现问题,请修改实验并重新运行。
最终,每组实验都有一个特定的目标,我们想要评估实验为该目标提供的证据。
然而,如果我们提出正确的问题,我们通常会发现在一组给定的实验能够朝着最初的目标取得很大进展之前需要纠正的问题。
如果我们不问这些问题,我们可能会得出不正确的结论。
由于运行实验的成本很高,我们还希望借此机会从每组实验中提取其他有用的见解,即使这些见解与当前目标并不直接相关。
在分析一组给定的实验以朝着最初的目标取得进展之前,我们应该问自己以下额外的问题:
如果研究的最佳点在一维或多维搜索空间的边界附近,则搜索可能不够广泛。在这种情况下,我们应该进行另一项具有扩展搜索空间的研究。
如果不是,则在调整目标中运行更多点或不那么雄心勃勃。
每项研究中有多少试验是不可行(即出现分歧的试验、得到非常糟糕的损失值,或者因为违反某些隐式约束而根本无法运行)?
当研究中很大一部分点是不可行时,我们应该尝试调整搜索空间以避免对这些点进行采样,这有时需要重新参数化搜索空间。
在某些情况下,大量不可行点可能表示训练代码中存在错误。
例如,最好的试验是否具有与有问题的过度拟合一致的训练曲线?
如有必要,根据上述问题的答案,改进最近的研究(或研究组)以改进搜索空间和/或抽样更多试验,或采取其他一些纠正措施。
一旦我们回答了上述问题,我们就可以继续评估实验为我们最初的目标提供的证据(例如,评估改变是否有用)。
[点击展开]
[点击展开]
[点击展开]
[点击展开]
[点击展开]
总结: 当决定是否对我们的模型或训练程序进行改变或采用新的超参数配置时,我们需要理解导致我们结果中不同的变化的来源。
当我们试图改进我们的模型时,我们可能会观察到,与我们现有的配置相比,一个特定的候选变化最初取得了更好的验证误差,但在重复实验后发现,没有发现一致的优势。非正式地,我们可以把可能导致这种不一致结果的最重要的变化来源分为以下几大类。
训练程序方差、再训练方差或试验方差:我们在使用相同的超参数但不同的随机种子的训练运行之间看到的差异。
例如,不同的随机初始化、训练数据的shuffles、dropout掩码、数据增强操作的模式和并行运算的顺序,都是试验方差的潜在来源。
超参数搜索方差或学习方差:由我们选择超参数的程序引起的结果变化。
例如,我们可能会在特定搜索空间运行相同的实验,但使用两个不同的种子进行Quasi-Random-Search搜索,并最终选择不同的超参数值。
数据收集和抽样方差:训练数据、验证数据和测试数据的任何一种随机分割所产生的方差,或者更普遍的由于训练数据生成过程而产生的方差。
使用严格的统计测试对有限验证集上估计的验证错误率进行比较是很好的,但往往仅试验方差就能在使用相同超参数设置的两个不同的训练模型之间产生统计上的显著差异。
当我们试图得出超出超参数空间中单个点水平的结论时,我们最关心的是学习方差。
学习方差取决于试验次数和搜索空间,我们已经看到它大于试验方差的情况以及它小得多的情况。
因此,在采用一个候选变化之前,考虑运行最佳试验N次,以估计训练方差。
通常情况下,我们可以只在工作流发生重大变化后重新对试验方差进行估计,但在某些应用中,我们可能需要使用更新鲜的估计。
在其他应用中,估计试验方差的成本太高,不值得这样做。
归根结底,虽然我们只想采用能够产生真正改进的更改(包括新的超参数配置),但要求完全相信某些东西会有所帮助也不是正确的要求。
因此,如果一个新的超参数点(或其他变化)得到比Baseline更好的结果(尽可能考虑新点和Baseline的再训练方差),那么我们可能应该采用它作为新的Baseline为以后的比较。
但是,我们应该只采用产生的改进超过它们增加的复杂性的更改。
总结: 一旦我们完成了对“好”的搜索空间的探索,并决定了哪些超参数甚至应该被调整,贝叶斯优化工具就是一个值得考虑的选择。
在这个时候,我们的优先事项将从学习更多优化经验转向产生一个最佳配置来启动或以其他方式使用。
在这一点上,我们应该有一个精确的搜索空间,可以舒适地包含最佳观察试验周围的局部区域,并且已经过充分采样。
我们的探索工作应该已经揭示了最重要的要调整的超参数(以及它们的合理范围),我们可以使用这些超参数来构建搜索空间,以使用尽可能大的调整预算进行最终的自动调整研究。
由于我们不再关心最大化我们对优化问题的经验,Quasi-Random-Search的优化方式不再适用,这时应该使用贝叶斯优化工具来自动找到最佳超参数配置。
如果搜索空间包含大量发散点(获得 NaN 训练损失或比平均值差很多标准差的训练误差的点),使用黑盒优化工具来正确处理发散试验很重要(请参阅具有未知约束的贝叶斯优化是处理此问题的绝佳方法)。
此时,我们还应该考虑检查测试集上的性能。
原则上,我们甚至可以将验证集折叠到训练集中,并重新训练通过贝叶斯优化找到的最佳配置。但是,这只适用于未来不会有这种特定工作需求的情况(例如,单次 Kaggle 竞赛)。
有两种类型的工作模式:受计算限制的和不受计算限制的。
当训练为受计算限制时,训练受限于我们愿意等待的时间,而不是受我们拥有多少训练数据或其他因素的限制。
在这种情况下,如果我们能以某种方式延长训练时间或提高训练效率,我们应该看到较低的训练损失,并且通过适当的调整,改善验证损失。
换句话说,加快训练速度就等于改善训练效果,而 "最佳 "训练时间总是 "我们愿意等待的时间"范围内。
然而,当工作模式受计算限制时,并不意味我们只能通过更长/更快的训练来改善结果。
当训练为不受计算限制时,我们可以负担得起训练的时间,只要我们愿意。或在某些时候,训练更长的时间并没有多大帮助(甚至会导致过拟合)。
在这种情况下,我们应该期望能够训练到非常低的训练误差,训练时间更长可能会略微减少训练误差,但不会显着减少验证误差。
当训练不受计算限制时,慷慨的训练时间预算可以使调整更容易,特别是在调整学习率衰减计划时,因为它们与训练预算有特别强的相互作用。
换句话说,吝啬的训练时间预算可能需要将学习率衰减计划调整到完美,以实现良好的训练效果。
不管一个给定的工作负载是否是计算约束,使用增加梯度方差(跨Batch)的方法通常会导致较慢的训练进度,从而可能增加达到特定验证损失所需的训练步骤。高梯度方差可能是由以下原因造成的。
使用了较小的Batch Size
使用了数据增强技术
添加了一些类型的正则化(例如 dropout)
我们的主要目标是确保我们训练的时间足够长,以使模型达到最佳效果,同时避免在训练步数的数量上过度浪费。
在有疑问的时候,请偏向于选择延长训练时间。假设回顾性(最佳)检查点选择使用得当,并且检查点足够频繁,那么训练时间越长,性能就越不会下降。
不要在训练中调整 max_train_steps 以获得更好的效果。我们只需要选择一个值并将其用于所有试验。从这些试验中,绘制回顾检查点选择发现的训练steps,以优化max_train_steps的数值。
例如,如果最佳step总是出现在训练过程的前10%,那么最大训练step数就太高了。
或者,如果最好的step总是出现在训练过程的最后的25%中,我们可能可以在增加训练时间和重新调整学习率衰减策略中受益(都与max_train_steps相关)。
当模型架构或数据发生变化时(例如添加数据增强),理想的训练的step数也会发生变化。
下面我们将描述如何根据使用恒定学习率“完全拟合”训练集所需的step数,为max_train_steps选择初始候选值。
注意,我们并没有以精确或数学定义良好的方式使用短语“完美拟合训练集”。 它只是一个非正式的描述语,表示非常低的训练损失。
例如,当训练损失为log loss且没有正则化项时,我们可能会看到训练损失会一直在缓慢减小(这与log loss的特性有关),直到达到浮点极限(floating point limits),因为网络权重可以无限制地增长,模型会对训练集的预测变得越来越自信。在这种情况下,我们可能会说,当训练集中的错误分类为0时,模型“完全拟合”训练集。
如果训练过程中 gradient noise(译注:可参考Umut Simsekl et al) 增大时,则max_train_steps可能需要增加起始值。
例如,如果在模型中引入数据增强或dropout等正则化方法。
如果训练过程以某种方式改进,可能会减少max_train_steps。
例如,使用更好的优化器或更好的学习率更新策略。
使用学习率搜索算法来确定 max_train_steps 的初始值
[点击展开]
在某些情况下,训练误差会无限地改善,而我们的耐心和计算资源就成为了限制因素。
如果训练误差(或甚至验证误差)可以无限地改善,我们是否应该在我们能接受的情况下一直训练?答案是不必要。
通过运行更多的短时间的实验,我们可以更快地找到最佳的模型和优化器超参数,而不必浪费大量的计算资源和时间在不优秀的超参数上。最后,我们可能会运行少量的长时间("production length" 指模型在生产环境中运行的时间,也就是预期的长时间训练)的实验来在最佳超参数点上获得最终模型。这样,我们就可以更有效地使用我们的资源来调整最有可能在生产环境中表现良好的模型。
我们的训练时间越长,我们对模型的理解就会越深入,这样我们就可以更好的了解模型的性能和限制,因此我们可以更确定哪些参数是最有可能在生产环境中表现良好的参数。但是,当我们的训练时间越长,我们能完成的实验就会越少,因为我们的耐心和计算资源有限。
当我们只训练 ~10% 的production length时,我们可能能够回答很多问题,但是在这个时间限制下的结论不一定适用于20%的production length的实验,更不用说100%了。这是因为训练模型的时间越长,模型就会越来越接近其最佳性能,而在较短的训练时间内得出的结论可能不能完全适用于长时间训练后的模型。
因此我们建议在每轮调整中逐渐增加训练步数限制,以在有限的资源和耐心内获得最大的理解,并在最终长时间训练后再进行验证和确认。
我们可以想做多少轮就做多少轮,但通常 1-3 轮是最实用的。
从本质上讲,在进行调整时要在两个方面进行平衡:相关性和彻底性。相关性指的是调整结果与最终长时间运行之间的相似性,而彻底性则指调整结果的详尽程度。因此,在进行调整时,我们应该尽量使用快速转换时间的试验来获得尽可能多的问题理解,同时保证这些结论与最终长时间运行相关。这样可以在有限的时间和资源内获得最大的理解,并尽可能地减少对最终长时间运行的影响。
一旦给定的每次试验时间限制中产生了有用的见解,我们就可以增加训练时间并继续调整,以确保它们在长时间运行中仍然适用。
作为起点,我们建议进行两轮调整:
第一轮:进行短时间的训练来找到较佳的模型和优化器超参数
第二轮:在较佳的超参数上进行少量长时间的训练来得到最终模型
从 Round i → Round i+1 的最大问题是如何调整学习率衰减计划。
在进行调整时,最大的问题是如何调整学习率衰减计划。在调整学习率衰减计划时的一个常见问题是使用了太小的学习率,如果学习率过小,模型的收敛速度会变慢,可能会需要更多的训练步骤才能达到最优状态。这可能会增加训练时间并增加计算资源的需求。
[点击展开]
[点击展开]
总结: 输入管道性能受限的原因及干预措施与具体任务高度相关,使用性能分析工具并注意常见的一些问题。
使用适当的性能分析工具来诊性能受限的输入管道,例如,用于 JAX 的 Perfetto 或用于 TensorFlow 的 TensorFlow profiler。
归根结底,具体原因和干预措施将高度依赖于任务。更广泛的工程考虑(如减少磁盘空间占用)可能会导致较差的输入管道性能。
常见问题:
数据未与训练进程存放在同一位置,从而导致I/O延迟(通过网络读取训练数据时可能会发生这种情况)。
昂贵的在线数据预处理(考虑进行一次性离线预处理并保存)。
无意间的同步屏障干扰数据管道预读取。例如,在 CommonLoopUtils(link) 中同步设备和主机之间的数据时。
常见技巧:
例如使用 tf.data.Dataset.prefetch 之类的工具对输入管道预读取数据。
尽可能早地在管道中删除不必要的特征和元数据。
通过使用 tf.data service 来增加输入管道生成数据的进程的数量。
总结: 使用比训练时更大的 batch size 进行评估。在固定步长间隔进行评估,而不是固定的时间间隔。(注:如100个epoch评估一次,而不是10分钟评估一次)。
[点击展开]
[点击展开]
[点击展开]
总结:运行固定步长的训练,并回顾性地从中选择最佳检查点。
大多数深度学习框架都支持模型检查点。模型的当前状态会定期保存在磁盘上。这允许训练作业对计算实例中断具有弹性。
最佳检查点并不一定是最后一个检查点,尤其是当验证集性能不会随时间持续增加而是围绕特定值波动时。
设置管道以跟踪到目前为止在训练期间看到的 N 个最佳检查点。在训练结束时,模型选择就是选择训练期间看到的最佳检查点。我们将此称为 回顾性最佳检查点选择。
因为预先指定了试验预算并保留了迄今为止看到的 N 个最佳检查点,所以通常不必要支持预期提前停止。
总结:在跟踪不同的实验时,一定要注意一些要点,比如研究中检查点的最佳性能,以及对研究的简短描述。
我们发现,在电子表格中跟踪实验结果有助于我们解决各种建模问题。它通常有以下列:
实验名称
实验配置存储位置的链接
实验的注释或简短描述
运行次数
最佳模型在验证集上的表现
训练所需的配置和运行命令
选择一种跟踪系统,能够满足上述信息的记录要求并且对使用者友好易用是非常重要的,未经记录的实验可能不会得到重视。
总结:目前Batch Norm通常可以用Layer Norm代替,但在不能替换的情况下,在更改批大小或主机数量时会有一些棘手的细节。
Batch norm 使用当前批次的均值和方差对激活值进行归一化,但在多设备设置中,除非明确同步处理,否则这些统计数据在每个设备上都是不同的。
据说(主要在ImageNet上)仅使用约 64 个样本计算这些归一化统计数据在实际应用中效果更好(请参阅 Ghost Batch Norm)。
将总批大小与用于计算批归一化统计数据的样本数量分离对于批次大小的比较特别有用。
Ghost batch norm 实现并不总能正确处理每台设备的批次大小 > 虚拟批次大小的情况。在这种情况下,我们实际上需要在每个设备上对批次进行二次抽样,以获得适当数量的批归一化统计样本。
在测试模式中使用的指数移动平均(EMA)仅仅是训练统计数据的线性组合,因此这些 EMA 只需要在将它们保存在检查点之前进行同步。然而一些常见的批归一化实现不同步这些EMA,并只保存第一个设备的EMA。
总结: 在日志记录、评估、RNG(随机数生成器)、检查点和数据分片方面,多主机训练非常容易引入错误!
保证管道只在一台主机上进行日志记录和检查点
确保在运行评估或检查点之前,批处理规范统计信息在主机之间同步
保证在多主机之间使用相同的随机数生成器种子(用于模型初始化)和不同的种子(用于数据混洗和预处理)是非常重要的,因此请确保合适地标记它们
为了提升性能,通常建议将数据文件在多台主机之间进行分片
[点击展开]
[点击展开]
[点击展开]
[点击展开]
为什么在优化的探索阶段使用Quasi-Random-Search而不是更复杂的黑盒优化算法?
[点击展开]
在哪里可以找到Quasi-Random-Search的实现?
[点击展开]
需要多少次试验才能通过Quasi-Random-Search获得较好的结果?
[点击展开]
[点击展开]
为什么将学习率和其他优化参数称为超参数? 它们不是任何先验分布的参数。
[点击展开]
[点击展开]
[点击展开]
我们要感谢Max Bileschi, Roy Frostig, Zelda Mariet, Stan Bileschi, Mohammad Norouzi, Chris DuBois以及Charles Sutton 阅读本手稿并提出宝贵的意见来改进我们的内容。
我们复用了最初由Naman Agarwal为其他联合研究制作的几个分析图的一些实验数据。
我们要感谢Will Chen对文档演讲内容提出的宝贵建议。
我们还要感谢 Rohan Anil 与我们进行了有益的讨论。
@misc{tuningplaybookgithub,
author = {Varun Godbole and George E. Dahl and Justin Gilmer and Christopher J. Shallue and Zachary Nado},
title = {Deep Learning Tuning Playbook},
url = {http://github.com/google/tuning_playbook},
year = {2023},
note = {Version 1.0}
}
这并不是一款由谷歌官方所支持的产品。
我们欢迎听到来自您的反馈。
如果你喜欢这本手册, 请给我们 留一颗小星星!或者,可以给我们的邮箱 deep-learning-tuning-playbook [at] googlegroups.com发送邮件。 这些推荐有帮于证明我们创建更多这样的内容是合理的。
如果有任何不正确的地方,欢迎在GitHub的讨论区提出相关问题。对于不适合问题的问题或其他消息,请在 GitHub 上打开一个新的讨论主题。
正如在序言中所讨论的,这是一份在线文档。我们会定期进行大大小小的修改。如果你想获取相关通知,请关注我们的仓库 (具体配置请查看 操作指南).
请不要在未通过问题跟踪系统与作者协调的情况下提交pull request。
对该项目的贡献必须附有贡献者许可协议 (CLA)。 对于你(或你的雇主)所贡献的内容将保留其相关版权; 这只是允许我们使用和重新分配您的贡献作为项目的一部分。 请前往 https://cla.developers.google.com/ 查看您当前存档的协议或签署新协议。
通常,您只需要签署一次CLA协议即可。因此,如果您已经签署过一次(即使针对的是其他项目),那么您可能无需再次签署。
所有的提交(包括来自项目成员的提交)都需要进行审核。出于这个目的,我们会使用Github提供的pull request功能来进行代码审核。 关于如何使用pull request,请查看 GitHub Help 获取更多信息.
本项目遵循 谷歌开源社区指南.
Footnotes
Ben Recht 和 Kevin Jamieson 指出 使用2倍预算随机搜索作为Baseline有多强大(Hyperband的论文也有类似的观点),但肯定有可能找到最先进的贝叶斯优化技术可以击败两倍预算随机搜索的搜索空间和问题。然而,根据我们的经验,在高并行机制中击败 2 倍预算的随机搜索变得更加困难,因为贝叶斯优化没有机会观察先前试验的结果。 ↩
About
一本系统地教你将深度学习模型的性能最大化的战术手册。
Resources
License
Citation
Cite this repository
Stars
Watchers
Forks
No releases published
No packages published
Footer
Footer navigation