此文整理总结github上的一个资料,结尾附上链接。对于工程应用很有现实参考,带入实际工作场景中会有不少的收获。
这份文档旨在帮助工程师和研究人员系统性地优化深度学习模型的性能。它涵盖了从项目启动到模型部署的各个环节,包括:
- 模型选择: 建议从成熟的模型架构开始,并根据需求逐步调整。 优化器选择: 推荐使用流行的优化器,并根据模型和任务进行调整。
- BatchSize: 强调 Batch Size 对训练时间和资源消耗的影响,并提供选择合适 Batch Size 的方法。
- 初始配置: 指导如何选择初始的模型配置、优化器超参数和训练步数。
- 科学方法: 介绍如何使用增量调整策略、探索与利用、以及如何设计实验来提高模型性能。
- 训练运行步数: 解释如何根据训练是否受计算限制来确定训练时间。
- 训练管道:提供优化输入管道、评估模型性能、保存检查点和设置实验跟踪的指导。
- 常见问题: 回答关于学习率衰减、Adam超参数、Quasi-Random-Search 和优化失败的常见问题。
总而言之,这份文档提供了一个全面且实用的指南,帮助深度学习从业者有效地优化模型性能,并提高工作效率。
1 开启新任务准备
1.1 选择模型架构
总结: 从成熟的模型架构开始,并根据需求进行调整。
建议:
- 选择一个完善且常用的模型架构来开始工作。
- 尝试找到一篇尽可能接近手头问题的相关论文,并将复现该论文中的模型作为起点。
1.2 选择优化器
总结: 从针对手头问题类型的最常用的优化器开始。
建议:
- 使用成熟、流行的优化器。如SGD with momentum,Adam,NAdam
- 理解优化器的所有超参数,并做好调整的准备。
- 在项目的初始阶段,从更简单的优化器开始。
1.3 选择 BatchSize
总结: BatchSize 决定训练速度,并且不应该被直接用于调整验证集性能。通常来说,可用硬件支持的最大
Batch Size 是较为理想的数值。
原因:
- 增加 BatchSize 通常会减少训练时间,这对超参数调整和开发周期有利。
- 资源消耗和 BatchSize 之间没有明确的关系。
- 理论上,任何 BatchSize 都能获得相同的最终性能。
选择 BatchSize 的步骤:
- 确定可行的 BatchSize 并估计训练吞吐量。
- 选择合适的 BatchSize 以最小化训练时间。
- 选择合适的 BatchSize 以最小化资源消耗。
- 更改 BatchSize 需要重新调整大多数超参数。
- 考虑 BatchNorm 对 BatchSize 选择的影响。
1.4 选择初始配置
总结: 在开始超参数调整之前,必须确定起点。这包括指定 模型配置(例如层数),优化器超参数(例如学习率),以及训练步数。
原则:
- 选择一个简单、快速、资源消耗相对较低的配置,以获得"合理"的结果。
考虑因素: - 简单:避免花里胡哨的东西,可以以后添加。
- 快速:消耗最少资源,提高超参数调整效率。
- 合理:性能比随机机会好得多。
- 确定训练步数的数量: 平衡训练步数和资源消耗,以及训练步数和调整效率之间的关系。
第 2 章 提高模型性能的科学方法
机器学习开发的最终目标是最大化模型的效用。尽管不同应用场景的开发流程有所不同(例如时间长度、可用计算资源、模型类型等),基本步骤和原则都是相似的。
接下来的指南中我们做出了这些假设:
- 已有能运行且得到不错结果的训练工作流。
- 有足够的计算资源来进行调参实验,至少能够并行发起数个训练流程。
2.1 增量调整策略
总结:从简单的配置开始,循序渐进,同时进一步了解问题。确保任何改进都有据可循,以避免增加不必要的复杂度。我们的最终目标是找到一种训练配置来最大化我们模型的性能。
- 更有效的方法是从简单的配置开始,逐步添加功能并进行改进,同时深化对问题的理解。
- 随着我们的探索,我们自然会找到越来越好的配置,因此我们的 "最佳" 模型将不断改进。
- 当我们更新我们的最佳配置时,我们称之为上线(这不一定对应线上模型的实际上线)。
- 对于每次上线,我们必须确保更改是有据可循的---而不仅仅是碰运气找到的配置---以避免给训练工作流增加不必要的复杂性。
综上所述,我们的增量调优策略需要重复以下四个步骤:
- 为下一轮实验确定适当的目标。
- 设计并展开实验,朝着这个目标取得进展。
- 从实验结果中获取经验。
- 考虑是否上线新的最佳配置。
本节的其余部分将更详细地讲解增量调优策略
2.2 探索与利用
总结:大多数时候,我们的目标是更深入地理解问题。
- 尽管有些人认为我们会花大部分时间来提升验证集的指标,实际上我们把重心放在进一步理解问题上,而不是降低验证集错误率。
- 也就是说,我们大部分时间都花在了 "探索" 上,只有一小部分时间花在了 "利用" 上。
- 从长远来看,如果我们想最大化我们的最终效果,深入理解问题是至关重要的。将深化理解置于短期收益之上可以帮助我们:
- 避免仅因历史原因而表现良好的不必要更改。
- 确定验证集效果对哪些超参数最敏感,哪些超参数交互最多,因此需要一起重新调整,以及哪些超参数对其他变化相对不敏感,因此可以在未来的实验中固定住。
- 发现潜在的新方向,例如在出现过拟合问题时使用新的正则化器。
- 确定无效的方向并将其删除,从而降低后续实验的复杂度。
判断超参数的优化空间是否已经饱和。- 围绕最佳值缩小我们的搜索空间,以提高调整效率。
最终,我们可以集中提升验证集效果,即便我们无法从新的实验中进一步了解问题的结构了。
2.4 设计下一轮实验
总结:根据实验目标,将超参数分为三类:目标超参数、冗余超参数和固定超参数。创建一系列研究以比较
目标超参数的不同值,同时优化冗余超参数。注意选择冗余超参数的搜索空间,以平衡资源成本与科学价值。
2.4.1 识别目标超参数、冗余超参数和固定超参数
对于给定的目标,所有超参数都将是目标超参数、冗余超参数或固定超参数。
- 目标超参数是指,我们希望测量出其对于模型由何种影响的参数。
- 冗余超参数是指,必须优化才能公平比较不同目标超参数值的参数。类似于统计中的冗余参数。
- 固定超参数是指,在当前轮次实验中取固定值的参数。在比较目标超参数的不同值时,固定超参数的值不需要(或者我们不希望它们)改变。因为实验固定了某些超参数,从实验得出的结论可能对固定超参数的其他值无效。换句话说,固定的超参数对我们的实验结论做了限定。
举个例子,如果我们的目标是 "确定更深的模型是否会减少验证集错误",那么模型层数就是目标超参数。
学习率是一个冗余超参数,如果我们要公平对比不同深度的模型,我们必须分别调整学习率(通常情况下最优学习率和模型结构有关)。
激活函数是一个固定超参数。我们可能通过过去的实验发现最优激活函数和模型深度无关。或者我们接受实验得到的最优深度的仅在某个激活函数上有效。或者我们也可以将激活函数作为一个冗余超参数和深度一起调优。
一个超参数是目标超参数、冗余超参数还是固定超参数是根据实验目标来决定的。
比如,激活函数的选择可以是一个目标超参数(对于当前问题,ReLU 或 tanh 是更好的选择吗?),一个冗余超参数(允许使用不同的激活函数,最好的 5 层模型是否优于最好的 6 层模型?),或一个固定超参数(对于一个由 ReLU 构成的网络,在特定位置添加批标准化是否有帮助?)。
在设计新一轮实验时,我们根据实验目的确定目标超参数。
- 在此阶段,我们将所有其他超参数视为冗余超参数。
- 接下来,我们将一些冗余超参数转作为固定超参数。
- 如果有无限的计算资源,我们会将所有非目标超参数保留为冗余超参数,这样我们从实验中得出的结论就不会受到固定超参数的限定。
- 然而,冗余超参数越多,我们没能充分针对每个目标超参数调优冗余超参数的风险就越高,从而我们从实验中得出错误结论的风险也越高。
- 如下文所述,我们可以通过增加计算资源来应对这种风险,但通常我们的最大资源预算低于调整所有非目标超参数所需的计算资源。
- 当我们判断将一个冗余超参数转换为固定超参数所带来的限制少于调优它所需的计算资源时,我们可以进行这种转换。
一个冗余超参数和目标超参数的相互影响越多,固定这个参数所带来的限制就越多。例如,权重衰减强度的最佳值通常取决于模型大小,因此固定权重衰减的强度来比较不同的模型大小,往往得不出有效的结论。
尽管超参数的类型取决于实验目标,但对于某些类别的超参数,我们有以下经验法则:
- 在各种优化器超参数(例如学习率、动量、学习率调度参数、Adam 优化器的 beta 等)中,至少有一些是冗余超参数,因为它们往往与其他变化相互影响。
- 它们很少是目标超参数,因为像 "训练流程的最佳学习率是多少?" 这样的目标没有什么意义------最优学习率很容易随着下一次训练流程的改变而改变。
- 尽管当资源有限或有强力的证据表明它们不影响目标超参数时,我们可能固定其中一些参数,但通常应该假设优化器超参数必须单独调整,以在不同设置之间进行公平比较目标超参数。
- 相比之下,优化器的选择通常是一个目标超参数或固定超参数。
- 如果我们的实验目标涉及在两个或多个不同的优化器之间进行公平比较(例如 "确定哪个优化器在给定的步数中产生最低的验证错误"),那么它就是一个目标超参数。
- 或者,我们可能出于各种原因将其设为固定超参数,包括(1)先前的实验表明最好的优化器和当前的目标超参数无关;(2)当前优化器的训练曲线更容易理解 (3) 当前优化器比其他优化器使用更少的内存。
- 正则化技术引入的超参数通常是冗余超参数,但是否使用正则化技术往往是目标或固定超参数。
例如,dropout 增加了代码的复杂性,因此在决定是否包含它时,我们会将 "no dropout" 与 "dropout"作为一个目标超参数,而将 dropout 率作为一个冗余超参数。
如果我们决定根据这个实验将 dropout 添加到我们的训练流程中,那么在未来的实验中,dropout率将是一个冗余超参数。
- 模型结构超参数通常是目标或固定超参数,因为模型结构变化会影响服务和训练成本、延迟和内存需求。
例如,网络层数通常是一个目标或固定的超参数,因为它往往会对训练速度和内存使用产生巨大影响。
- 在某些情况下,一个超参数是冗余还是固定超参数将取决于目标超参数的值。
- 例如,假设我们想知道 Nesterov momentum 和 Adam 中哪个优化器的验证错误率更低。目标超参数是optimizer,它的值是 {"Nesterov_momentum", "Adam"}。值 optimizer="Nesterov_momentum" 引入了冗余/固定超参数 {learning_rate, momentum},但值 optimizer="Adam" 引入了冗余/固定超参数 {learning_rate, beta1, beta2, epsilon}。
- 仅针对目标超参数的某些值存在的超参数称为条件超参数。
- 我们不应该仅仅因为两个条件超参数具有相同的名称就认为它们是相同的!在上面的示例中,learning_rate对optimizer="Nesterov_momentum" 与 optimizer="Adam" 是不同的条件超参数. 它在两种算法中的作用相似(尽管不完全相同),但在每个优化器中运行良好的值范围通常相差几个数量级。
2.4.2 创建一组研究
- 确定了目标和冗余超参数之后,我们会设计一个 "研究" 或一系列研究,以朝着实验目标取得进展。
- 一项研究指定了一组要运行的超参数配置以供后续分析。每个配置称为 "试验"
- 创建研究通常涉及几个方面:选择试验所需的超参数变量,选择这些超参数的取值范围("搜索空间"),选择试验次数,以及选择自动搜索算法。或者,我们可以通过手动指定一组超参数配置来创建研究。
- 研究的目的是使用目标超参数的不同值运行训练流程,同时 "优化掉"(或 "优化")冗余超参数,以便公平的比较不同的目标超参数值。
- 在最简单的情况下,我们将对目标超参数的每个配置进行单独研究,其中每个研究都会调整冗余超参数。
- 例如,如果我们的目标是从 Nesterov、momentum 和 Adam 中选择最佳优化器,我们可以创建一个研究,并设置 optimizer="Nesterov_momentum" 和冗余超参数为 {learning_rate, momentum}。然后创建另一项研究,并设置 optimizer="Adam" 和冗余超参数为 {learning_rate, beta1, beta2,epsilon}。最后通过比较两个研究中的最优试验来比较这两个优化器。
- 我们可以使用任何无梯度优化算法,包括贝叶斯优化或进化算法等方法,来优化冗余超参数。但是,在探索阶段,我们更偏向使用准随机算法,因为这些方法在探索阶段有多种优势。在探索结束后,我们会优先选择最先进的贝叶斯优化方法。
- 在更复杂的情况下,我们想要比较大量目标超参数的值,并且我们无法进行大量相对独立的研究,我们可以将目标超参数与冗余超参数放在相同的搜索空间中,并使用搜索算法在单个研究中对两种超参数的值进行采样。
- 采用这种方法时,条件超参数可能会是一个问题,因为很难指定对应的搜索空间,除非所有目标超参数值都有相同的冗余超参数集。
- 在这种情况下,我们更加偏好使用 Quasi-Random-Search 算法,因为它确保我们能相对均匀的采样目标超参数值。无论搜索算法如何,我们都需要确保它均匀搜索目标超参数。
在设计一项研究或一系列研究时,我们需要分配有限的预算,以充分满足以下三个要求:
- 比较足够多目标超参数的不同值。
- 在足够大的搜索空间上调整冗余超参数。
- 对冗余超参数的搜索空间进行足够密集的采样。
这三个必要条件,确保我们能从实验中获得足够多的经验。
2.4 从实验结果中获取经验
总结:除了尝试实现每组实验的原始科学目标之外,还要检查其他问题的清单,如果发现问题,请修改实验并重新运行。
- 最终,每组实验都有一个特定的目标,我们想要评估实验为该目标提供的证据。
然而,如果我们提出正确的问题,我们通常会发现在一组给定的实验能够朝着最初的目标取得很大进展之前需要纠正的问题。如果我们不问这些问题,我们可能会得出不正确的结论。
由于运行实验的成本很高,我们还希望借此机会从每组实验中提取其他有用的见解,即使这些见解与当前目标并不直接相关。
- 在分析一组给定的实验以朝着最初的目标取得进展之前,我们应该问自己以下额外的问题:
- 搜索空间够大吗?
- 我们是否从搜索空间中采样了足够多的点?
- 每项研究中有多少试验是不可行(即出现分歧的试验、得到非常糟糕的损失值,或者因为违反某些隐式约束而根本无法运行)?当研究中很大一部分点是不可行时,我们应该尝试调整搜索空间以避免对这些点进行采样,这有时需要重新参数化搜索空间。在某些情况下,大量不可行点可能表示训练代码中存在错误。
- 模型是否存在优化问题?
- 我们可以从最佳试验的训练曲线中学到什么?例如,最好的试验是否具有与有问题的过度拟合一致的训练曲线?
- 如有必要,根据上述问题的答案,改进最近的研究(或研究组)以改进搜索空间和/或抽样更多试验,或采取其他一些纠正措施。
一旦我们回答了上述问题,我们就可以继续评估实验为我们最初的目标提供的证据(例如,评估改变是否有用)。
第3 章 确定每次训练运行的步数
有两种类型的工作模式:受计算限制的和不受计算限制的。
- 当训练为受计算限制时,训练受限于我们愿意等待的时间,而不是受我们拥有多少训练数据或其他因素的限制。
在这种情况下,如果我们能以某种方式延长训练时间或提高训练效率,我们应该看到较低的训练损失,并且通过适当的调整,改善验证损失。换句话说,加快训练速度就等于改善训练效果,而" 最佳" 训练时间总是" 我们愿意等待的时间" 范围内。
然而,当工作模式受计算限制时,并不意味我们只能通过更长/更快的训练来改善结果。
不管一个给定的工作负载是否是计算约束,使用增加梯度方差(跨Batch)的方法通常会导致较慢的训练进度,从而可能增加达到特定验证损失所需的训练步骤。高梯度方差可能是由以下原因造成的。 使用了较小的Batch Size、使用了数据增强技术、添加了一些类型的正则化(例如dropout)
3.1 当训练受计算限制时如何决定该训练多久
- 在某些情况下,训练误差会无限地改善,而我们的耐心和计算资源就成为了限制因素。
- 如果训练误差(或甚至验证误差)可以无限地改善,我们是否应该在我们能接受的情况下一直训练?答案是不必要。
- 通过运行更多的短时间的实验,我们可以更快地找到最佳的模型和优化器超参数,而不必浪费大量的计算资源和时间在不优秀的超参数上。最后,我们可能会运行少量的长时间("production length" 指模型在生产环境中运行的时间, 也就是预期的长时间训练) 的实验来在最佳超参数点上获得最终模型。这样,我们就可以更有效地使用我们的资源来调整最有可能在生产环境中表现良好的模型。
- 我们的训练时间越长,我们对模型的理解就会越深入,这样我们就可以更好的了解模型的性能和限制,因此我们可以更确定哪些参数是最有可能在生产环境中表现良好的参数。但是,当我们的训练时间越长,我们能完成的实验就会越少,因为我们的耐心和计算资源有限。
- 当我们只训练~10% 的production length 时,我们可能能够回答很多问题,但是在这个时间限制下的结论不一定适用于20% 的production length 的实验,更不用说100% 了。这是因为训练模型的时间越长,模型就会越来越接近其最佳性能,而在较短的训练时间内得出的结论可能不能完全适用于长时间训练后的模型。
- 因此我们建议在每轮调整中逐渐增加训练步数限制,以在有限的资源和耐心内获得最大的理解,并在最终长时间训练后再进行验证和确认。
- 我们可以想做多少轮就做多少轮,但通常1-3 轮是最实用的。
- 从本质上讲,在进行调整时要在两个方面进行平衡:相关性和彻底性。相关性指的是调整结果与最终长时间运行之间的相似性,而彻底性则指调整结果的详尽程度。因此,在进行调整时,我们应该尽量使用快速转换时间的试验来获得尽可能多的问题理解,同时保证这些结论与最终长时间运行相关。这样可以在有限的时间和资源内获得最大的理解,并尽可能地减少对最终长时间运行的影响。
- 一旦给定的每次试验时间限制中产生了有用的见解,我们就可以增加训练时间并继续调整,以确保它们在长时间运行中仍然适用。
- 作为起点,我们建议进行两轮调整:
- 第一轮:进行短时间的训练来找到较佳的模型和优化器超参数
- 第二轮:在较佳的超参数上进行少量长时间的训练来得到最终模型 从Round i → Round i+1 的最大问题是如何调整学习率衰减计划。在进行调整时,最大的问题是如何调整学习率衰减计划。在调整学习率衰减计划时的一个常见问题是使用了太小的学习率,如果学习率过小,模型的收敛速度会变慢,可能会需要更多的训练步骤才能达到最优状态。这可能会增加训练时间并增加计算资源的需求。
3.1.1 第一轮
-
遗憾的是,在短时间和不完整训练中找到的超参数在增加训练长度后仍然是好选择的保证是没有的。但是,对于某些类型的超参数,它们通常具有足够的相关性,因此第一轮非常有用。
-
我们期望在短运行中找到的哪些超参数值会转移到更长的训练运行中?对于这一切,我们需要更多的研究。但是根据已有的结论我们可以提出一些猜测,以下是作者的猜测,按转移概率的降序排列:
- 极有可能转移
在第一轮调参中,使用较少的训练步数可以解决早期训练的不稳定性。也许这些超参数是最能保证转移的选择。- 可能转移
模型架构- 模型架构上的显著胜利通常会转移,但可能有很多例外。- 可能会转移
- 优化算法/优化器超参数---我们认为这将" 松散" 转移。它明显比上面的东西弱。
- 数据增强方法
- 正则化:如果不可能完美地拟合训练集,则模型可能处于正则化不太可能有太大的帮助。
- 不太可能转移
学习率衰减计划:不太可能完美迁移。
3.1.2 第二轮
- 运行第一轮中最佳的超参数配置。
- 使用额外的步骤来延长高学习率的训练时间。
例如,如果是线性计划,则保持第一轮中衰减大小的固定值,并在开始时延长恒定的lr 期。 对于余弦衰减,只需保留第一轮的基础lr 并增大max_train_steps。
- 对于具有非常成熟建模和调整的工作流以及非常长且昂贵的生产训练运行的团队来说,更多回合可能更有意义,但它们通常会过于复杂。
第 4 章 关于训练管道的额外补充
4.1 优化输入管道
总结:输入管道性能受限的原因及干预措施与具体任务高度相关,使用性能分析工具并注意常见的一些问题。
- 使用适当的性能分析工具来诊性能受限的输入管道,例如,用于JAX 的Perfetto 或用于TensorFlow 的Ten- sorFlow profiler。
- 归根结底,具体原因和干预措施将高度依赖于任务。更广泛的工程考虑(如减少磁盘空间占用) 可能会导致较差的输入管道性能。
- 常见问题:
- 数据未与训练进程存放在同一位置,从而导致I/O 延迟(通过网络读取训练数据时可能会发生这种情况)。
- 昂贵的在线数据预处理(考虑进行一次性离线预处理并保存)。
- 无意间的同步屏障干扰数据管道预读取。例如,在CommonLoopUtils(link) 中同步设备和主机之间的数据时。
- 常见技巧:
- 例如使用tf.data.Dataset.prefetch 之类的工具对输入管道预读取数据。
- 尽可能早地在管道中删除不必要的特征和元数据。
- 通过使用tf.dataservice 来增加输入管道生成数据的进程的数量。
4.2 评估模型性能
总结:使用比训练时更大的batch size 进行评估。在固定步长间隔进行评估,而不是固定的时间间隔。(注:如100 个epoch 评估一次,而不是10 分钟评估一次)。
4.2.1 评估设置
我们可以通过多种方式来评估模型的性能。
- 在线评估-当模型在生产环境中提供预测时收集指标。
- 离线评估-当模型在代表生产环境的离线训练/验证/测试集上运行时,收集指标。
- 定期评估-在模型训练期间收集的指标可能是离线评估的代理,和(或) 离线评估中使用的数据的子集。
- 在线评估是最佳标准,但在模型开发阶段往往是不切实际的。
- 根据问题的不同,离线评估可能会相当复杂,并且计算成本很高。
- 定期评估是最实际和最经济的选择,但可能不能完全代表生产环境。
我们在定期评估时的目标是在训练期间获得可靠信号,使同时尽可能缩短评估时间。
4.2.2 设置定期评估
- 我们在训练期间定期进行评估,以实时监控其进度,以便于追溯模型检查点选择,以便我们可以在训练结束时检查训练曲线。
- 其中最简单的配置是在同一计算实例中执行训练和定期评估,并定期在训练和评估之间交替。(注:比如固定步长间隔评估一次)
- 在这种情况下,用于执行评估的batch size 大小应该至少与用于训练的batch size 大小一样大,因为在评估期间不需要保持模型运行(注:如不用计算梯度之类的),从而降低了每个示例的计算要求。
- 定期评估应在固定步长间隔进行,而不是按时间间隔进行。
4.2.3 选择样本进行定期评估
- 定期评估作业的运行速度可能不够快,无法在合理的时间内计算完整离线评估集的指标。这通常需要对数据进行抽样以进行定期评估。
- 在构建采样数据集时,我们会考虑以下因素:
- 样本量
- 确保定期作业使用的采样数据集的性能与整个离线评估集的性能相似,确保采样集与完整数据集之间没有偏差。
- 用于定期评估的数据集应该足够小,以便很容易生成整个模型的预测,但也应该足够大,以便可以准确地测量模型的改进(即不被大量标签噪声影响)。
- 它应该足够大,以适应顺序试验中的多个这样的评估,并仍然产生准确的估计。也就是说,避免在多轮评估中对验证集过度适应,从而影响模型对留出集的表现。然而,这种考虑很少是一个实际的问题。
- 不平衡的数据集
- 对于不平衡的数据集,在稀有类别样本上的表现往往会有噪音。
- 对于每个类别只有少量样本的数据集,记录正确预测样本的数量,可以更深入地了解准确性改进
4.3 保存检查点并追溯选择最佳检查点
总结:运行固定步长的训练,并回顾性地从中选择最佳检查点。
- 大多数深度学习框架都支持模型检查点。模型的当前状态会定期保存在磁盘上。这允许训练作业对计算实例中断具有弹性。
- 最佳检查点并不一定是最后一个检查点,尤其是当验证集性能不会随时间持续增加而是围绕特定值波动时。
- 设置管道以跟踪到目前为止在训练期间看到的N 个最佳检查点。在训练结束时,模型选择就是选择训练期间看到的最佳检查点。我们将此称为回顾性最佳检查点选择。
- 因为预先指定了试验预算并保留了迄今为止看到的N 个最佳检查点,所以通常不必要支持预期提前停止。
4.4 设置实验跟踪
总结:在跟踪不同的实验时,一定要注意一些要点,比如研究中检查点的最佳性能,以及对研究的简短描述。
- 我们发现,在电子表格中跟踪实验结果有助于我们解决各种建模问题。通常有下列:
实验名称
实验配置存储位置的链接
实验的注释或简短描述
运行次数
最佳模型在验证集上的表现
训练所需的配置和运行命令
- 选择一种跟踪系统,能够满足上述信息的记录要求并且对使用者友好易用是非常重要的,未经记录的实验可能不会得到重视。
4.6 多主机管道的注意事项
总结:在日志记录、评估、RNG(随机数生成器)、检查点和数据分片方面,多主机训练非常容易引入错误!
- 保证管道只在一台主机上进行日志记录和检查点
- 确保在运行评估或检查点之前,批处理规范统计信息在主机之间同步
- 保证在多主机之间使用相同的随机数生成器种子(用于模型初始化) 和不同的种子(用于数据混洗和预处理) 是非常重要的,因此请确保合适地标记它们
- 为了提升性能,通常建议将数据文件在多台主机之间进行分片
第5 章 常见问题的回答
5.1 最好的学习率衰减方案是什么
这是一个开放性问题。目前尚不清楚如何构建一组严格的实验来自信地回答最佳的LR 衰减方案是什么。
虽然我们不知道最好的方案是什么,但我们相信尝试一些(非恒定的)方案很重要并且调整它很重要。
在优化过程中,不同的学习率在不同的时间效果最好。有某种衰减方案可以使模型更有可能达到良好的学习率。
5.2 我应该使用哪种学习率衰减方案作为默认值?
我们的偏好是linear decay 或cosine decay,其他一些方案可能也不错。
5.4 Adam 的超参数应该如何调整?
正如之前讨论的那样, 对搜索空间以及应该从搜索空间中采样数量做出概括性陈述是非常困难的。请注意,并非Adam 中的所有超参数都一样重要。以下经验法则对应于研究中试验次数的不同"预算"。
如果在一次研究中,训练次数试验次数小于10,那么只需要对基本学习率进行调整
如果试验次数在10 到25 次之间,那么需要对学习率以及β1 进行调整。
如果试验次数在25 次以上,那么需要对学习率、β1 以及ϵ 进行调整。
如果可以运行的试验次数大于25 次,还需要额外调整β2。
5.8 如何调试和缓解优化失败
总结:如果在优化模型时遇到困难,那么在尝试其他东西之前解决这些问题很重要。诊断和纠正训练失败是一个活跃的研究领域。
5.8.1 识别不稳定的训练任务
- 当学习率过大时,任何训练任务都会变得不稳定,但当不稳定迫使我们使用太小的学习率时,这才会是问题
- 这里至少有两种类型的不稳定的训练任务值得需要进行区分:
初始化/训练早期中存在的不稳定。
训练中期突然出现的不稳定。
- 我们可以采用系统的方法来找出训练任务中存在的稳定性问题.
进行一次学习率扫描(不考虑学习率衰减的固定学习率),并找到最佳的学习率lr*.
绘制学习率略高于lr* 的训练损失曲线。
如果学习率大于lr* 的训练损失曲线显示不稳定(误差在训练期间上升而不下降),那么修复不稳定性可能会得到更好的训练结果(说明我们最佳的学习率比较临界)。
- 在训练过程中记录全损失梯度的L2 范数的变化(全损失梯度的L2 范数是指在深度学习中,对于每个参数的梯度进行平方并相加后再取平方根的过程,反映了损失函数在当前状态下沿着梯度方向的变化程度。当前状态下的梯度向量越大,说明当前状态下的模型参数需要更大的更新量才能更好的逼近最优解),如果我们发现全损失梯度的L2 范数异常值非常大,这可能表明模型参数在某一时刻发生了非常大的变化,导致训练过程中出现不稳定性(例如误差上升而不下降)。这可以告诉我们该如何选择梯度/更新剪辑。
注意:某些模型会在非常早期的阶段显示出不稳定的情况,随后出现恢复,这会导致出现缓慢但稳定的训练(这可能会成为问题)。为了检查出这一问题,我们可以使用lr = 2 * current best 来进行一次仅包含500 次训练的计划,但每执行一次训练都要进行一次评估。
5.8.2 常见不稳定模式的潜在修复方式
- 使用学习率预热--最适合用于早期训练不稳定的情况。
- 使用梯度截断
对于早期和中期训练中不稳定情况都有好处,可能会解决一些学习率预热无法解决的问题。
- 尝试使用新的优化器
Adam 有时可以处理一些Momentum 无法处理的不稳定影响。这也是该领域的一个活跃研究领域。 - 确保使用最佳实践/初始化:
例如,如果模型中尚未包含残差连接和归一化,则添加它们。 归一化应该是残差之前的最后一个操作。例如,x +Norm(f(x))。
- 降低学习率。这是最终手段。
如何对学习率进行预热
- 在上面的内容中,我们假设从业者已经确定了让模型变得不稳定的学习率。也就是unstable_base_learning_rate。
- 预热的过程涉及了预先安排一个学习率计划,这个计划会将学习率从0 提升到某个稳定的base_learning_rate,这至少比 unstable_base_learning_rate 要大一个数量级。默认设置是尝试使用unstable_base_learning_rate 10 倍大小的base_learning_rate。
值得注意的是,对于使用例如 100 倍unstable_base_learning_rate 这样的数值,那么可能需要重新运行整个过程。具体安排如下:
在warmup_steps 的过程中,将数值从0 提升到base_learning_rate。post_warmup_steps 的过程中,以一个恒定的速率进行训练。
- 我们的目标是找到最少的warmup_steps,以此来让我们获得远高unstable_base_learning_rate 的峰值学习率。
因此,对于,每个base_learning_rate 来说,我们需要对warmup_steps 以及post_warmup_steps 进行调优。通常将post_warmup_steps 设定为warmup_steps 的两倍就可以了。
- 预热可以独立于现有的衰减计划进行调整。
warmup_steps 应该以几个不同的数量级进行扫描。例如,在样本学习中可以以[10, 103, 104,105] 这样的数量级进行尝试。最大的搜索值不应超过max_train_steps 的10%。
- 一旦建立了不会破坏以base_learning_rate 进行训练的warmup_steps,就应该将其应用于Baseline 模型。
梯度截断
- 当出现较大或离群的梯度问题时,梯度截断会变得非常有用。
- 梯度截断可以修复早期训练中出现的不稳定性(早期较大的梯度范数),或中期训练中出现的不稳定性(训练中期突然出现的梯度尖峰)。
- 有时,较长的预热时间可以纠正梯度截断无法纠正的不稳定性:。
- 理想的截断阈值要刚好高于"典型的" 梯度范数。 下面是一个关于如何进行梯度截断的案例:
如果梯度范数|g| 大于梯度截断的阈值λ,那么就需要进行g′ = λ × g 。此处的g′ 是新的梯度。
- 在训练期间记录下未截断梯度范数。默认情况下会生成:
梯度范数与步骤数量的关系图
聚合所有步数的梯度范数直方图
- 根据梯度范数的第90 百分位数选择梯度截断阈值。
这个阈值的大小与工作量有关。但90% 是一个很好的选择。但如果这个奏效,那么可以对其进行调优。 - 如果我们尝试梯度截断并不稳定问题仍然存在,那么我们可以更努力地尝试(例如,阈值更小)。
- 极端激进的梯度截断本质上是一种降低学习率的奇怪方式。如果我们发现自己使用了非常激进的截断,那么我们可能应该只降低学习率。
- 我们通常会认为以某种方式将超过50% 的更新剪裁为"极其激进"。
- 如果我们需要进行极其激进的梯度截断来处理我们的不稳定问题,那么我们不妨降低学习率。
总结
欢迎点赞,收藏,关注,支持小生,打造一个好的遥感领域知识分享专栏。
同时欢迎私信咨询讨论学习,咨询讨论的方向不限于:地物分类/语义分割(如水体,云,建筑物,耕地,冬小麦等各种地物类型的提取),变化检测,夜光遥感数据处理,目标检测,图像处理(几何矫正,辐射矫正(大气校正),图像去噪等),遥感时空融合,定量遥感(土壤盐渍化/水质参数反演/气溶胶反演/森林参数(生物量,植被覆盖度,植被生产力等)/地表温度/地表反射率等反演)以及高光谱数据处理等领域以及深度学习,机器学习等技术算法讨论,以及相关实验指导/论文指导等多方面。