tuning_playbook

GitHub
30k 2.4k 非常简单 1 次阅读 昨天NOASSERTION开发框架
AI 解读 由 AI 自动生成,仅供参考

tuning_playbook 是一份由 Google Research 团队开源的深度学习模型性能调优实战指南。它旨在解决当前深度学习领域中普遍存在的“试错成本高、经验难传承”的痛点:许多论文和商业项目往往只展示最终结果,却省略了达成该结果所经历的关键调参过程和工程细节,导致开发者不得不重复大量低效的摸索工作。

这份文档特别适合希望系统化提升模型效果的机器学习工程师和研究人员使用。它不局限于介绍某个具体的算法库,而是提供了一套科学的调优方法论。其核心亮点在于提出了“增量调优策略”,指导用户如何在“探索”新配置与“利用”已知最优解之间取得平衡,并详细涵盖了从模型架构选择、优化器设定、批量大小调整,到训练步数决策、输入管道优化及实验追踪等全流程的最佳实践。

通过遵循 tuning_playbook,团队可以将原本依赖直觉的调参过程转化为可复现、可度量的科学实验流程,从而在有限的计算资源下更高效地挖掘模型潜力,显著减少盲目尝试带来的时间与算力浪费。

使用场景

某电商推荐算法团队正致力于优化深度点击率(CTR)预测模型,试图在有限的算力预算下将模型准确率提升 0.5% 以满足上线标准。

没有 tuning_playbook 时

  • 调参过程依赖工程师的“直觉”和零散经验,缺乏系统性的实验设计,导致大量计算资源浪费在无效的超参数组合上。
  • 面对模型性能瓶颈时,团队难以判断是继续延长训练时间、调整批量大小(Batch Size),还是更换优化器,决策过程充满盲目猜测。
  • 实验记录混乱,缺乏统一的评估标准,经常无法复现之前的最佳结果,甚至因过早停止训练而错过了全局最优解。
  • 输入管道和检查点保存策略未经优化,导致数据加载成为瓶颈,且难以回溯选择历史训练中的最佳模型状态。

使用 tuning_playbook 后

  • 团队遵循其科学的增量调优策略,按顺序系统地确定架构、优化器和初始配置,将试错成本降低了 60% 以上。
  • 依据指南中关于“探索与利用”的建议,清晰制定了每一轮实验的目标,精准判断何时该尝试新方向、何时该深耕现有配置。
  • 建立了规范的实验追踪体系,根据算力约束科学设定训练步数,并通过回顾性选择检查点机制,成功挖掘出被忽略的高性能模型版本。
  • 参照输入管道优化和多主机训练的最佳实践,消除了数据加载瓶颈,确保了训练流程的高效与稳定。

tuning_playbook 将深度学习调优从一门“玄学”转变为可复制、可度量的科学工程流程,显著提升了模型迭代效率与最终性能上限。

运行环境要求

GPU

未说明

内存

未说明

依赖
notes该工具(tuning_playbook)是一份关于深度学习超参数调优的指南文档,而非可执行的软件代码库。因此,README 中未包含具体的操作系统、GPU、内存、Python 版本或依赖库等运行环境需求。其内容主要面向工程师和研究人员,提供模型架构选择、优化器选择、批次大小设定及实验设计等方法论指导。用户需根据自己实际使用的深度学习框架(如 TensorFlow 或 PyTorch)自行配置相应的运行环境。
python未说明
tuning_playbook hero image

快速开始

深度学习调参手册

本文档并非 Google 官方支持的产品。

Varun Godbole, George E. Dahl, Justin Gilmer, Christopher J. Shallue, Zachary Nado

† Google Research,Brain 团队

‡ 哈佛大学

目录

本文档面向哪些读者?

本文档面向对最大化深度学习模型性能感兴趣的工程师和研究人员(个人及团队)。我们假定读者具备机器学习和深度学习的基本知识。

我们的重点在于超参数调优的过程。虽然我们也涉及深度学习训练的其他方面,例如流水线的实现与优化,但这些内容并非全面覆盖。

我们假设所处理的机器学习问题属于监督学习,或者与之非常相似的问题(如自监督学习)。不过,本文档中的一些建议也可能适用于其他类型的问题。

为什么需要一份调参指南?

目前,在实践中让深度神经网络真正发挥出色效果,仍然需要耗费大量精力,并且很大程度上依赖于猜测和试错。更糟糕的是,人们用来获得良好深度学习结果的具体方法往往很少被记录下来。论文为了呈现更简洁的故事,通常会略过导致最终结果的过程;而从事商业项目的技术人员则很少有时间退后一步,总结并提炼出通用的流程。教科书倾向于回避实用指导,转而强调基础原理,即便作者具备丰富的应用经验,能够提供有价值的建议。在着手编写这份文档时,我们未能找到任何全面阐述“如何通过深度学习获得良好结果”的尝试。相反,我们只在博客文章和社交媒体上零星地看到一些建议,在研究论文的附录中瞥见一些技巧,偶尔还能找到关于某个特定项目或工作流的案例研究,但整体上仍充满困惑。深度学习专家与技能较弱的从业者之间,即使使用看似相似的方法,所取得的结果也存在巨大差距。与此同时,这些专家也坦承,他们的一些做法可能并没有充分的理论依据。随着深度学习逐渐成熟并对世界产生越来越大的影响,社区亟需更多涵盖实用方法的资源,尤其是那些对获得良好结果至关重要的细节。

我们是一支由五位研究人员和工程师组成的团队,多年来一直从事深度学习相关工作,其中一些人早在2006年就开始涉足这一领域。我们曾将深度学习应用于从语音识别到天文学等各个领域的实际问题,并在此过程中积累了丰富的经验。本文正是基于我们在训练神经网络、培训新入职的机器学习工程师以及为同事提供深度学习实践指导方面的亲身经历而撰写而成。尽管看到深度学习从少数学术实验室中的研究方法,发展成为支撑数十亿人日常使用的产品的核心技术,令人倍感欣慰,但作为一门工程学科,深度学习仍然处于起步阶段。我们希望这份文档能够激励更多人共同推动该领域实验协议的系统化。

本文源于我们试图梳理自身在深度学习实践中的方法论,因此它反映的是作者写作时的观点,而非某种客观真理。我们在超参数调优方面遇到的困难使这部分内容成为我们的重点,但我们也涵盖了工作中遇到的其他重要问题(或目睹他人犯下的错误)。我们的初衷是让这份文档成为一个不断生长和演进的活文档,随着我们认知的变化而更新。例如,关于调试和应对训练失败的内容,两年前我们还无法撰写,因为它基于近期的研究成果和持续的探索。不可避免地,部分建议需要根据新的研究成果和改进的工作流程进行更新。我们并不知道“最优”的深度学习配方,但在社区开始系统性地记录和讨论不同实践方案之前,我们也无法期望找到它。为此,我们鼓励读者在发现我们建议存在问题时,提出替代性建议,并附上充分的证据,以便我们能够不断完善这份指南。同时,我们也期待出现更多具有不同建议的替代性指南和手册,从而推动整个社区朝着最佳实践的方向迈进。最后,所有标有🤖表情符号的部分,都代表着我们希望进一步深入研究的领域。只有在尝试编写这份指南之后,我们才彻底意识到,深度学习从业者的日常工作流程中其实隐藏着大量有趣却长期被忽视的研究课题。

新项目启动指南

在调参过程中所做的许多决策,其实只需在项目初期做出一次,之后仅在情况发生变化时才需重新审视。

以下指导基于以下假设:

  • 关键的问题定义、数据清洗等工作已经完成,此时投入时间优化模型架构和训练配置是合理的。
  • 已经搭建好用于训练和评估的工作流,能够方便地运行不同模型的训练和预测任务。
  • 已经选择了合适的评估指标,并将其落实到位。这些指标应尽可能贴近实际部署环境中的衡量标准。

模型架构的选择

要点: 在启动新项目时,尽量复用已有的成熟模型。

  • 首先选择一个经过验证、广泛使用的模型架构来快速落地。自定义模型可以在后续阶段再行构建。
  • 模型架构通常包含多种超参数,用于决定模型的规模及其他细节(如层数、每层宽度、激活函数类型等)。
  • 尽可能寻找一篇与当前问题尽可能接近的研究论文,并以该论文中的模型作为起点进行复现。

选择优化器

总结: 从当前问题类型中最流行的优化器开始。

  • 没有一种优化器在所有类型的机器学习问题和模型架构中都是“最佳”的。即使只是 比较不同优化器的性能也是一项艰巨的任务。 🤖
  • 我们建议坚持使用经过验证的、流行的优化器,尤其是在启动新项目时。
    • 理想情况下,选择与相同类型问题最常用的优化器。
  • 要准备好关注所选优化器的***所有***超参数。
    • 具有更多超参数的优化器可能需要更多的调优工作才能找到最佳配置。
    • 这在项目的初期阶段尤为重要,因为我们正试图在将优化器超参数视为 干扰参数 的同时,寻找其他各种超参数(例如架构超参数)的最佳值。
    • 在项目的初始阶段,可能更适合先使用较简单的优化器(例如带有固定动量的SGD,或$\epsilon$、$\beta_{1}$和$\beta_{2}$均固定的Adam),然后在后期再切换到更通用的优化器。
  • 我们喜欢的一些经过验证的优化器包括(但不限于):

选择批量大小

总结: 批量大小决定了训练速度,不应被用来直接优化验证集性能。通常,理想的批量大小是现有硬件支持的最大批量大小。

  • 批量大小是决定训练时间计算资源消耗的关键因素。
  • 增大批量大小通常会缩短训练时间。这非常有益,因为它可以:
    • 在固定时间内更充分地调优超参数,从而可能得到更好的最终模型。
    • 缩短开发周期的延迟,使新想法能够更频繁地得到验证。
  • 增大批量大小可能会减少、增加或不改变资源消耗。
  • 批量大小不应被视为用于优化验证集性能的可调超参数。

确定可行的批量大小并估算训练吞吐量

[点击展开]
  • 对于给定的模型和优化器,通常会有一系列由现有硬件支持的批量大小。限制因素通常是加速器的显存。
  • 不幸的是,在不运行或至少编译完整训练程序的情况下,很难计算出哪些批量大小能够装入显存。
  • 最简单的方法通常是用不同的批量大小(例如2的幂次方)运行训练任务,每次只进行少量步骤,直到某个任务超出可用显存。
  • 对于每个批量大小,我们都应训练足够长的时间,以获得对训练吞吐量的可靠估计。

训练吞吐量 = (每秒处理的样本数)

或者,等价地,就是每步耗时

每步耗时 = (批量大小) / (训练吞吐量)

  • 当加速器尚未饱和时,如果批量大小翻倍,训练吞吐量也应该翻倍(至少接近翻倍)。等价地,随着批量大小的增加,每步耗时应该保持恒定(至少接近恒定)。
  • 如果情况并非如此,则说明训练流水线存在瓶颈,例如I/O或计算节点之间的同步问题。在继续之前,值得诊断并解决这些问题。
  • 如果训练吞吐量仅在达到某个最大批量大小时才停止增长,那么即使硬件支持更大的批量大小,我们也只需考虑不超过该最大批量大小的设置。
    • 使用更大批量大小的所有优势都建立在训练吞吐量会随之增加的基础上。如果吞吐量没有增加,请先解决瓶颈问题,或者改用较小的批量大小。
    • 梯度累积虽然可以模拟超过硬件支持的更大批量,但并不会带来任何吞吐量上的好处。因此,在实际应用中通常应避免使用。
  • 每当模型或优化器发生变化时(例如,不同的模型架构可能允许更大的批量大小装入显存),这些步骤可能都需要重复进行。

选择最小化训练时间的批量大小

[点击展开]

训练时间 = (每步耗时) × (总步数)

  • 对于所有可行的批量大小,我们通常可以认为每一步所需的时间大致恒定。这种情况发生在没有并行计算开销、且所有训练瓶颈已被诊断并解决时(有关如何识别训练瓶颈,请参阅 前一节)。但在实践中,增加批量大小通常至少会带来一定的开销。
  • 随着批量大小的增加,达到固定性能目标所需的总步数通常会减少(前提是批量大小改变时所有相关超参数都经过重新调整; Shallue 等人, 2018)。
    • 例如,将批量大小翻倍可能会使所需总步数减半。这被称为完美缩放
    • 完美缩放适用于所有小于临界批量大小的批量,超过该值则会进入收益递减阶段。
    • 最终,继续增大批量大小将不再减少训练步数(但也不会增加)。
  • 因此,能够最小化训练时间的批量大小通常是仍能减少所需训练步数的最大批量大小。
    • 该批量大小取决于数据集、模型和优化器,而如何在不通过实验逐一确定的情况下计算出这一值,目前仍是一个开放问题。🤖
    • 在比较不同批量大小时,需注意区分“样本预算”与“轮次预算”(即固定训练样本遍历次数的所有实验)和“步数预算”(即固定训练步数的所有实验)之间的区别。
      • 使用轮次预算比较批量大小时,只能考察完美缩放区间,即便更大的批量大小仍可通过减少所需训练步数带来显著加速。
    • 常常,现有硬件支持的最大批量大小会小于临界批量大小。因此,在未进行任何实验的情况下,一个较好的经验法则是尽可能使用最大的批量大小。
  • 如果增大批量大小反而导致训练时间延长,则没有必要再进一步增大。

选择最小化资源消耗的批量大小

[点击展开]
  • 增大批量大小会带来两类资源成本:
    1. 前期成本,例如购买新硬件或为实现多 GPU/多 TPU 训练而重写训练流水线。
    2. 使用成本,例如团队资源预算的支出、云服务提供商的计费、电力及维护费用等。
  • 若增大批量大小需要较高的前期成本,则可能最好将其推迟到项目成熟后再实施,以便更准确地评估成本效益。实施多主机并行训练程序可能会引入 错误细微问题,因此从一开始就采用较简单的流水线或许更为妥当。(另一方面,在早期阶段,如果需要进行大量调参实验,大幅缩短训练时间可能会非常有益)。
  • 我们将总使用成本(可能包含多种不同类型的成本)称为“资源消耗”。资源消耗可分解为以下组成部分:

资源消耗 = (每步资源消耗)×(总步数)

  • 增大批量大小通常可以 减少总步数。至于资源消耗是增加还是减少,则取决于每步资源消耗的变化情况。
    • 增大批量大小可能会降低资源消耗。例如,如果使用较大批量的每一步可以在与较小批量相同的硬件上运行(仅每步耗时略有增加),那么每步资源消耗的任何增加都可能被步数减少所抵消。
    • 增大批量大小也可能不改变资源消耗。例如,若批量大小翻倍使所需步数减半、同时使用的 GPU 数量也翻倍,则以 GPU 小时计的总消耗将保持不变。
    • 增大批量大小有时也会增加资源消耗。例如,若增大批量大小需要升级硬件设备,则每步资源消耗的增加可能会超过步数减少带来的节省。

更改批量大小需要重新调整大多数超参数

[点击展开]
  • 大多数超参数的最优值对批量大小非常敏感。因此,更改批量大小通常意味着需要重新开始调参过程。
  • 与批量大小关联最紧密、因而需要针对每个批量大小单独调整的重要超参数包括优化器超参数(如学习率、动量)以及正则化超参数。
  • 在项目初期选择批量大小时请务必考虑到这一点。如果后续需要切换到不同的批量大小,为新批量重新调整所有超参数可能会非常困难、耗时且昂贵。

批量归一化与批量大小的关系

[点击展开]
  • 批量归一化较为复杂,一般而言,其用于计算统计量的批量大小应与梯度计算所用的批量大小不同。有关详细讨论,请参阅 批量归一化章节

选择初始配置

  • 在开始超参数调优之前,我们必须确定起点。这包括指定 (1) 模型配置(例如层数)、(2) 优化器的超参数(例如学习率),以及 (3) 训练步数。
  • 确定这一初始配置需要进行一些手动配置的训练运行,并通过试错来调整。
  • 我们的指导原则是找到一个简单、相对快速、资源消耗较低的配置,能够获得“合理”的结果。
    • “简单”意味着尽可能避免使用复杂的功能;这些功能可以随时在后期添加。即使这些复杂功能在未来被证明有用,在初始配置中加入它们也可能导致浪费时间去调优无益的特性,或者将不必要的复杂性固化下来。
      • 例如,在引入复杂的衰减策略之前,先从固定的学习率开始。
    • 选择一个快速且资源消耗少的初始配置,将使超参数调优更加高效。
      • 例如,可以从较小的模型开始。
    • “合理”的性能取决于具体问题,但至少意味着训练后的模型在验证集上的表现要远优于随机猜测水平(尽管其性能可能仍然不足以部署)。
  • 选择训练步数时需要权衡以下矛盾:
    • 一方面,增加训练步数可以提升性能,并使超参数调优更容易(参见 Shallue et al. 2018)。
    • 双方面,减少训练步数可以使每次训练运行更快、资源消耗更少,从而提高调优效率——缩短迭代周期,并允许更多实验并行进行。此外,如果最初选择了过大的步数预算,后续可能难以更改,例如当学习率调度已经针对该步数进行了调优时。

提升模型性能的科学方法

就本文而言,机器学习开发的最终目标是最大化已部署模型的效用。尽管不同应用场景的开发过程在许多方面存在差异(如所需时间、可用计算资源、模型类型等),但我们通常可以在任何问题上采用相同的基本步骤和原则。

以下指导假设:

  • 已经存在一个完全运行的训练流水线,以及一个能够获得合理结果的配置。
  • 具有足够的计算资源来进行有意义的调优实验,并至少能够并行运行多个训练任务。

增量式调优策略

摘要: 从简单配置开始,逐步改进,同时加深对问题的理解。确保每一次改进都有充分的证据支持,以避免引入不必要的复杂性。

  • 我们的最终目标是找到能够最大化模型性能的配置。
    • 在某些情况下,我们的目标是在固定截止日期前尽可能地提升模型性能(例如参加竞赛)。
    • 在另一些情况下,则希望持续不断地改进模型(例如持续优化生产环境中使用的模型)。
  • 从理论上讲,我们可以通过算法自动搜索所有可能的配置空间来实现性能最大化,但这并不现实。
    • 可能的配置空间极其庞大,目前尚不存在足够智能的算法能够在没有人工指导的情况下高效地搜索这一空间。
  • 大多数自动化搜索算法依赖于人工设计的“搜索空间”,该空间定义了要搜索的配置集合,而不同的搜索空间可能会产生显著影响。
  • 最有效的性能提升方式是从一个简单的配置开始,逐步添加功能并进行改进,同时不断加深对问题的理解。
    • 我们在每一轮调优中都会使用自动化搜索算法,并随着理解的加深不断更新搜索空间。
  • 随着探索的深入,我们会自然而然地发现越来越好的配置,因此我们的“最佳”模型也会不断进步。
    • 当我们更新最佳配置时,就称之为一次“发布”(这不一定对应于生产模型的实际上线)。
    • 对于每一次发布,我们都必须确保变更有充分的证据支持——而不仅仅是基于幸运配置的偶然结果——以避免向训练流水线中引入不必要的复杂性。

从宏观层面来看,我们的增量式调优策略包括重复以下四个步骤:

  1. 确定下一轮实验的适当目标范围。
  2. 设计并运行一组能够朝着该目标取得进展的实验。
  3. 从实验结果中学习有价值的信息。
  4. 考虑是否发布新的最佳配置。

本节的剩余部分将更详细地探讨这一策略。

探索与利用

摘要: 大多数情况下,我们的首要目标是深入了解问题。

  • 尽管人们可能会认为我们应将大部分时间用于最大化验证集上的性能,但在实践中,我们通常会花更多的时间去理解问题的本质,而较少地单纯追求验证误差的最小化。
    • 换句话说,我们主要进行“探索”,只有少量时间用于“利用”。
  • 从长远来看,若要最大化最终性能,深入理解问题至关重要。优先考虑洞察力而非短期收益,可以帮助我们:
    • 避免盲目引入那些仅因偶然因素而在表现较好的实验中出现的改动。
    • 确定哪些超参数对验证误差最为敏感,哪些超参数之间存在强烈的交互作用需要同时调整,以及哪些超参数相对不敏感,可以在后续实验中固定下来。
    • 提出可尝试的新特性建议,例如在过拟合问题严重时引入新的正则化方法。
    • 找出对模型无益的特征并将其移除,从而降低未来实验的复杂度。
    • 判断超参数调优带来的改进是否已趋于饱和。
    • 缩小搜索空间至最优值附近,以提高调优效率。
  • 当我们准备好专注于优化验证误差时,即使实验本身无法充分揭示调优问题的结构,也可以直接聚焦于验证误差的最小化。

选择下一轮实验的目标

摘要: 每一轮实验都应有明确的目标,并且范围足够狭窄,以便实验能够切实朝着目标推进。

  • 每一轮实验都应设定清晰的目标,且实验范围不宜过于宽泛,否则难以区分不同因素对结果的具体影响。
  • 常见的目标示例包括:
    • 尝试对流水线进行潜在改进(如引入新的正则化方法、预处理方式等)。
    • 探究某一特定模型超参数的影响(如激活函数的选择)。
    • 盲目地最小化验证误差。

设计下一轮实验

摘要: 针对实验目标,明确哪些超参数是研究对象(科学超参数),哪些是干扰因素(干扰超参数),哪些则是固定不变的超参数。设计一系列实验,在优化干扰超参数的同时,比较研究对象超参数的不同取值。合理选择干扰超参数的搜索空间,以在资源成本与科学价值之间取得平衡。

确定科学超参数、干扰超参数和固定超参数

[点击展开]
  • 对于给定的目标,所有超参数都将属于以下三类之一:科学超参数干扰超参数固定超参数
    • 科学超参数是指我们试图衡量其对模型性能影响的超参数。
    • 干扰超参数是指为了公平比较科学超参数的不同取值而需要进行优化的超参数。这类似于统计学中的“干扰参数”概念(nuisance parameter)。
    • 固定超参数则会在当前一轮实验中保持不变。这些超参数在比较科学超参数的不同取值时,其值不需要(或我们不希望其)改变。
      • 通过为一组实验固定某些超参数,我们必须接受这样一个事实:从这些实验得出的结论可能不适用于固定超参数的其他设置。换句话说,固定超参数会为我们从实验中得出的任何结论带来一定的限制条件。
  • 例如,如果我们的目标是“确定增加隐藏层的数量是否能降低验证误差”,那么隐藏层的数量就是科学超参数。
    • 学习率则是干扰超参数,因为只有为每种不同的隐藏层数量分别调优学习率,我们才能公平地比较不同隐藏层数量的模型(最优的学习率通常取决于模型架构)。
    • 激活函数可以作为固定超参数,如果我们先前的实验已经表明最佳激活函数的选择与模型深度无关,或者我们愿意将关于隐藏层数量的结论仅限于这一特定的激活函数选择。当然,如果我们要为每种隐藏层数量单独调优激活函数,它也可以被视为干扰超参数。
  • 某个特定超参数究竟是科学超参数、干扰超参数还是固定超参数,并不是该超参数本身的固有属性,而是取决于实验目标。
    • 例如,激活函数的选择可以是科学超参数(对于我们的问题,ReLU和tanh哪个更好?),也可以是干扰超参数(当我们允许使用几种不同的激活函数时,最好的5层模型是否优于最好的6层模型?),或者固定超参数(对于ReLU网络,在某个特定位置添加批归一化是否有帮助?)。
  • 在设计新一轮实验时,我们首先需要明确针对实验目标的科学超参数。
    • 在这一阶段,我们将所有其他超参数视为干扰超参数。
  • 接着,我们会将部分干扰超参数转化为固定超参数。
    • 如果资源无限,我们可以将所有非科学超参数都保留为干扰超参数,这样我们从实验中得出的结论就不会受到固定超参数取值的限制。
    • 然而,我们尝试调优的干扰超参数越多,就越有可能无法为科学超参数的每个设置充分调优,从而导致实验结论出现偏差。
    • 当我们认为固定某个干扰超参数所带来的限制小于将其作为干扰超参数的成本时,就会选择将其固定。
      • 某个干扰超参数与科学超参数的交互越强烈,固定它的值就越不利。例如,权重衰减强度的最佳取值通常依赖于模型大小,因此假设权重衰减采用单一固定值来比较不同模型大小的意义并不大。
  • 尽管我们为每个超参数分配的类型取决于实验目标,但对于某些类别的超参数,我们仍有一些经验法则:
    • 在各种优化器超参数中(如学习率、动量、学习率调度参数、Adam的beta参数等),至少有一部分会是干扰超参数,因为它们往往与其他变化的交互最为密切。
      • 它们很少成为科学超参数,因为像“当前流水线的最佳学习率是多少?”这样的目标并不能提供太多洞见——最佳设置很可能随着下一次流水线的变更而改变。
      • 虽然有时由于资源限制,或者当我们有强有力的证据表明它们与科学超参数无关时,可能会将其中一些固定,但我们通常应假定优化器超参数必须单独调优,以实现科学超参数不同设置之间的公平比较,因此不应将其固定。
      • 此外,我们并没有先验理由偏好某一组优化器超参数的取值(例如,它们通常不会以任何方式影响前向传播或梯度计算的开销)。
    • 相反,优化器的选择通常是科学超参数或固定超参数。
      • 如果实验目标涉及对两种或多种不同优化器进行公平比较(例如,“确定在给定步数内哪种优化器能产生最低的验证误差”),那么优化器的选择就是科学超参数。
      • 另一方面,出于多种原因,我们也可以将其设为固定超参数,包括:(1) 先前的实验表明,我们问题的最佳优化器对当前的科学超参数不敏感;以及/或者 (2) 我们更倾向于使用这种优化器来比较科学超参数的不同取值,因为它产生的训练曲线更容易分析;以及/或者 (3) 我们更喜欢使用这种优化器,因为它比其他优化器占用的内存更少。
    • 正则化技术引入的超参数通常是干扰超参数,但是否采用正则化技术本身则是科学超参数或固定超参数。
      • 例如,Dropout会增加代码复杂度,因此在决定是否使用它时,我们会将“不使用Dropout”与“使用Dropout”设为科学超参数,而Dropout率则为干扰超参数。
      • 如果我们根据这次实验决定在流水线中加入Dropout,那么在未来的实验中,Dropout率就将成为干扰超参数。
    • 架构相关的超参数往往是科学超参数或固定超参数,因为架构的变化会影响推理和训练成本、延迟以及内存需求。
      • 例如,层的数量通常是科学超参数或固定超参数,因为它往往会对训练速度和内存使用产生显著影响。
  • 在某些情况下,干扰超参数和固定超参数的集合会依赖于科学超参数的取值。
    • 例如,假设我们要确定Nesterov动量和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"时是完全不同的超参数。尽管它们在这两种算法中的作用相似(但并不完全相同),但每种优化器中表现良好的取值范围通常相差几个数量级。

创建一组研究

[点击展开]
  • 一旦我们确定了科学超参数和干扰超参数,就会设计一项“研究”或一系列研究,以逐步推进实验目标。
    • 研究会指定一组需要运行的超参数配置,用于后续分析。每个配置称为一个“试验”。
    • 创建研究通常涉及选择在不同试验中变化的超参数、这些超参数可以取哪些值(即“搜索空间”)、试验的数量,以及选择一种自动搜索算法来从搜索空间中采样相应数量的试验。或者,我们也可以手动指定一组超参数配置来创建研究。
  • 这些研究的目的是使用科学超参数的不同值来运行流水线,同时**“优化掉”**(或“优化过”)干扰超参数,从而使对科学超参数不同值之间的比较尽可能公平。
  • 在最简单的情况下,我们会为科学参数的每种配置单独进行一项研究,其中每项研究都会针对干扰超参数进行调优。
    • 例如,如果我们的目标是从Nesterov动量和Adam中选择最佳优化器,我们可以创建一项研究,其中optimizer="Nesterov_momentum",干扰超参数为{learning_rate, momentum};再创建另一项研究,其中optimizer="Adam",干扰超参数为{learning_rate, beta1, beta2, epsilon}。然后通过分别从两项研究中选出表现最好的试验来比较这两种优化器。
    • 我们可以使用任何无梯度优化算法,包括贝叶斯优化或进化算法等,来优化干扰超参数,尽管我们更倾向于在调优的探索阶段使用准随机搜索,因为它在这种情况下具有多种优势。探索结束后,如果有最先进的贝叶斯优化软件可用,那将是我们的首选。
  • 在更复杂的情况下,如果我们希望比较大量科学超参数的取值,而逐一进行那么多独立研究并不现实,那么可以将科学参数与干扰超参数放在同一个搜索空间中,使用一种搜索算法在一个研究中同时采样科学和干扰超参数的值。
    • 采用这种方法时,条件超参数可能会带来问题,因为除非所有科学超参数取值对应的干扰超参数集合都相同,否则很难定义一个统一的搜索空间。
    • 在这种情况下,我们更倾向于使用准随机搜索而非更复杂的黑箱优化工具,因为这样能够确保对科学超参数的取值进行相对均匀的采样。无论使用哪种搜索算法,我们都必须确保它能均匀地搜索科学超参数。

平衡信息性和经济性的实验

[点击展开]
  • 在设计一项或一系列研究时,我们需要在有限的预算内合理分配资源,以充分满足以下三个要求:
    1. 比较足够多的科学超参数取值。
    2. 在足够大的搜索空间内调优干扰超参数。
    3. 对干扰超参数的搜索空间进行足够密集的采样。
  • 我们在这三个要求上做得越好,就能从实验中获得越多的洞见。
    • 尽可能多地比较科学超参数的取值,可以拓宽我们从实验中获得的洞察范围。
    • 包含尽可能多的干扰超参数,并让每个干扰超参数在其尽可能宽的范围内变化,可以增加我们对这样一个事实的信心:对于科学超参数的每种配置,干扰超参数的“良好”取值确实存在于其搜索空间中。
      • 否则,由于没有搜索到某些科学参数取值下可能存在更好干扰超参数值的区域,我们可能会对科学超参数的取值做出不公平的比较。
    • 尽可能密集地采样干扰超参数的搜索空间,可以增加我们对这样一个事实的信心:只要干扰超参数的良好设置确实存在于我们的搜索空间中,搜索过程就一定能找到它们。
      • 否则,由于某些取值在干扰超参数的采样过程中运气更好,我们可能会对科学超参数的取值做出不公平的比较。
  • 不幸的是,要在这三个维度中的任何一个方面取得改进,要么需要增加试验次数,从而提高资源成本,要么需要在其他某个维度上找到节省资源的方法。
    • 每个问题都有其独特性及计算约束,因此如何在这三个要求之间分配资源,需要一定的领域知识。
    • 在完成一项研究后,我们总是会评估该研究是否充分调优了干扰超参数(即是否在足够大的空间内进行了足够广泛的搜索),以便公平地比较科学超参数(具体细节请参阅下方内容)。

从实验结果中提取洞见

摘要: 除了努力实现每组实验的原始科学目标外,还应对照一份附加问题清单逐一检查;若发现问题,则需修改实验并重新运行。

  • 归根结底,每组实验都有其特定目标,我们希望评估这些实验为此目标所提供的证据。
    • 然而,如果我们提出正确的问题,往往会发现一些需要在实验取得实质性进展之前加以修正的问题。
      • 如果不提出这些问题,我们可能会得出错误的结论。
    • 由于运行实验可能成本较高,我们也希望借此机会从每组实验中挖掘其他有用的信息,即便这些信息与当前目标并非直接相关。
  • 在分析某组实验以推进其原始目标之前,我们应先问自己以下几个问题:
    • 搜索空间是否足够大?
      • 如果某次研究中的最优点在一个或多个维度上接近搜索空间的边界,则说明搜索范围可能不够宽。在这种情况下,我们应该开展另一项扩大搜索空间的研究。
    • 我们是否已从搜索空间中采样了足够多的点?
      • 如果没有,可以增加采样点数,或者适当降低调参目标的雄心程度。
    • 每次研究中有多少比例的试验是不可行的(即发散、损失值极差,或因违反某些隐含约束而根本无法运行)?
      • 当一项研究中“不可行”的点占很大比例时,我们应尝试调整搜索空间,避免采样到这类点;有时这甚至需要重新参数化搜索空间。
      • 在某些情况下,大量不可行的点可能表明训练代码中存在缺陷。
    • 模型是否存在优化问题?
    • 我们能从最佳试验的训练曲线中获得哪些启示?
      • 例如,最佳试验的训练曲线是否显示出有问题的过拟合现象?
  • 如有必要,根据上述问题的答案,我们可以对最近一次研究(或一组研究)进行调整,以改进搜索空间和/或增加试验次数,或采取其他纠正措施。
  • 一旦回答了上述问题,我们就可以继续评估实验为我们原始目标所提供的证据(例如,评估某项改动是否有用)。

识别不良搜索空间边界

[点击展开]
  • 如果从某个搜索空间中采样的最佳点非常接近其边界,那么这个搜索空间就值得怀疑。如果我们朝那个方向扩展搜索范围,很可能会找到更好的点。
  • 为了检查搜索空间的边界,我们通常会绘制所谓的基础超参数轴图,即以验证目标值为纵轴、某一超参数(如学习率)为横轴的图表。图表中的每个点都对应一次试验。
    • 每次试验的验证目标值通常应为其在整个训练过程中达到的最优值。

不良搜索空间边界的示例 良好搜索空间边界的示例

图1: 不良搜索空间边界与可接受搜索空间边界的示例。

  • 图1 中的图表展示了误差率(越低越好)与初始学习率之间的关系。
  • 如果最佳点集中在搜索空间的边缘(在某个维度上),则可能需要扩大搜索空间的边界,直到观测到的最佳点不再靠近边界。
  • 通常,一项研究中会包含一些“不可行”的试验,这些试验要么发散,要么得到非常糟糕的结果(如上方图表中用红色叉号标记的点)。
    • 如果所有学习率高于某个阈值的试验都不可行,且表现最好的试验的学习率恰好位于该区域的边缘,那么模型【可能因稳定性问题而无法使用更高的学习率】(见#如何调试和缓解优化失败)。

搜索空间采样不足

[点击展开]
  • 总体而言, 很难判断 搜索空间是否已被充分采样。🤖
  • 当然,运行更多试验总是更好,但这也意味着更高的成本。
  • 由于难以确定何时才算采样充分,我们通常会根据预算尽可能多地采样,并通过反复查看各种超参数轴图来校准自己的直觉信心,从而大致判断搜索空间中“良好”区域有多少个点。

检查训练曲线

[点击展开]

摘要: 检查训练曲线是一种简便的方法,可以帮助我们识别常见的失败模式,并据此优先安排下一步行动。

  • 尽管在许多情况下,我们的实验主要目标只需关注每次试验的验证误差,但在将每次试验简化为一个单一数值时仍需谨慎,因为这可能会掩盖底层正在发生的重要细节。
  • 对于每项研究,我们始终会查看至少前几轮表现最佳试验的训练曲线(即在整个训练过程中,训练误差和验证误差随训练步数的变化趋势)。
  • 即使这并非解决主要实验目标所必需,检查训练曲线也是一种简便的方法,可以帮助我们识别常见的失败模式,并优先确定下一步应采取的行动。
  • 在检查训练曲线时,我们主要关注以下几个问题:
  • 是否有试验表现出严重过拟合
    • 严重过拟合是指在训练过程中,验证误差开始上升的现象。
    • 在通过选择每组科学超参数设置下的“最佳”试验来优化并消除干扰超参数的实验环境中,我们应至少检查与所比较的科学超参数设置对应的每一组最佳试验是否存在严重过拟合。
      • 如果任何一组最佳试验出现严重过拟合,我们通常会在比较科学超参数值之前,重新运行实验,加入额外的正则化技术,或进一步调优现有的正则化参数。
        • 如果科学超参数本身包含正则化参数,则此规则可能不适用,因为在这种情况下,较低强度的正则化参数设置导致严重过拟合并不令人意外。
      • 使用常见的正则化技术(如丢弃法、标签平滑、权重衰减等)来减少过拟合通常较为简单,且不会显著增加代码复杂度或计算开销,因此在下一轮实验中加入一两种此类技术通常并无太大困难。
      • 例如,若科学超参数是“隐藏层数量”,而使用最多隐藏层的最佳试验出现了严重过拟合,则我们通常会选择在加入更多正则化措施后再次尝试,而不是立即选择较少的隐藏层数量。
      • 即使所有“最佳”试验均未表现出严重过拟合,如果其他试验中存在这种情况,仍然可能存在潜在问题。
        • 选择最佳试验的过程会倾向于排除那些表现出严重过拟合的配置,而偏向于没有过拟合的配置。换句话说,它会倾向于采用更强的正则化。
        • 然而,任何使训练效果变差的因素都可能起到正则化的作用,即便这些因素并非设计初衷。例如,降低学习率可以通过拖慢优化进程来实现正则化,但通常我们并不希望以这种方式调整学习率。
        • 因此,我们必须意识到,针对每组科学超参数设置选出的“最佳”试验,其结果可能受到某些科学或干扰超参数不良取值的影响。
  • 在训练后期,训练误差或验证误差是否表现出较大的步间波动?
    • 如果存在这种波动,可能会干扰我们比较不同科学超参数值的能力(因为每次试验最终停留在某个“幸运”或“不幸”的步数上),同时也会影响我们在生产环境中复现最佳试验结果的能力(因为生产模型可能不会恰好停在与研究中相同的“幸运”步数上)。
    • 步间波动最常见的原因包括:批次间的随机性(由于每个批次从训练集中随机采样样本)、验证集规模较小,以及在训练后期使用了过高的学习率。
    • 可能的解决方法包括:增大批次大小、获取更多的验证数据、使用学习率衰减策略,或采用Polyak平均法。
  • 在训练结束时,各试验的表现是否仍在持续改善?
    • 如果是,这表明我们正处于【计算受限】状态(参见#确定每次训练的步数),此时可以通过【增加训练步数】(参见#当训练处于计算受限状态时如何决定训练时长)或调整学习率调度来进一步提升性能。
  • 训练集和验证集上的性能是否在最终训练步数之前就已饱和?
    • 如果是,这表明我们处于【非计算受限】状态(参见#确定每次训练的步数),此时可以考虑【减少训练步数】(参见#当训练非计算受限时如何决定训练时长)。
  • 虽然无法一一列举,但从训练曲线中还可以观察到许多其他行为特征(例如,训练损失在训练过程中增加通常意味着训练流水线中存在错误)。

使用隔离图检测变更是否有效

[点击展开]

用于探究ResNet-50在ImageNet数据集上训练时最佳权重衰减值的隔离图。

图2:用于探究ResNet-50在ImageNet数据集上训练时最佳权重衰减值的隔离图。

  • 通常,一组实验的目标是比较科学超参数的不同取值。
    • 例如,我们可能希望确定使验证误差最小的权重衰减值。
  • 隔离图是基本超参数轴图的一种特殊情况。隔离图上的每个点对应于在某些(或全部)干扰超参数上表现最佳的试验结果。
    • 换句话说,我们在“优化掉”干扰超参数后绘制模型性能。
  • 隔离图使得对科学超参数的不同取值进行更直接的比较成为可能。
  • 例如,图2展示了在ImageNet数据集上训练的特定ResNet-50配置下,能够产生最佳验证性能的权重衰减值。
    • 如果我们的目标是决定是否使用权重衰减,那么就需要将该图中的最佳点与不使用权重衰减的基线进行比较。为了公平比较,基线的学习率也应经过同样良好的调优。
  • 当我们拥有通过(准)随机搜索生成的数据,并且考虑为隔离图选择一个连续型超参数时,可以通过对基本超参数轴图的x轴值进行分桶,并取每个桶所定义的垂直切片中的最佳试验来近似得到隔离图。

自动化生成通用性较强的图表

[点击展开]
  • 绘制图表所需的工作量越大,我们就越少去查看它们,因此有必要建立基础设施,尽可能自动地生成这些图表。
  • 至少,我们会自动为实验中变化的所有超参数生成基本超参数轴图。
  • 此外,我们还会自动为所有试验生成训练曲线,并尽可能简化查找每次研究中表现最好的几个试验及其训练曲线的过程。
  • 还有许多其他潜在的图表和可视化方式可以添加,以提供帮助。尽管上述方法是一个不错的起点,但正如杰弗里·辛顿所说:“每当你绘制一个新的图表时,你就会学到新的东西。”

判断是否采用训练流程的改动或超参数配置

摘要: 在决定是否对模型或训练流程进行更改,或者在未来采用新的超参数配置时,我们需要意识到结果中存在的不同来源的变异性。

  • 当我们试图改进模型时,可能会发现某个候选方案最初比现有配置获得了更低的验证误差,但重复实验后却发现并无持续优势。非正式地讲,我们可以将可能导致这种不一致结果的重要变异性来源归纳为以下几类:
    • 训练过程方差重训练方差试验方差:指使用相同超参数但不同随机种子进行的多次训练之间观察到的差异。
      • 例如,不同的随机初始化、训练数据打乱顺序、dropout掩码、数据增强操作模式以及并行计算操作的执行顺序等,都可能是试验方差的来源。
    • 超参数搜索方差研究方差:由我们选择超参数的过程所导致的结果差异。
      • 例如,我们可能使用相同的搜索空间运行同一实验,但分别采用两个不同的准随机搜索种子,最终选出的超参数值却不同。
    • 数据收集与采样方差:由于训练、验证和测试数据的随机划分,或更一般意义上的训练数据生成过程所带来的变异性。
  • 使用严谨的统计检验来比较基于有限验证集估算的验证误差固然重要,但往往仅凭试验方差就足以在使用相同超参数设置的两个不同模型之间产生统计显著差异。
  • 我们最关心研究方差的情况,是在试图得出超出单个超参数点之外的结论时。
    • 研究方差取决于试验次数和搜索空间,我们既见过其大于试验方差的情形,也见过其远小于试验方差的情形。
  • 因此,在采纳某个候选方案之前,建议对最佳试验重复运行N次,以评估其试验间的方差。
    • 通常情况下,只有在流程发生重大变化时才需要重新评估试验方差;但在某些应用中,则可能需要更频繁地更新这一评估。
    • 而在另一些应用中,评估试验方差的成本过高,不值得投入。
  • 归根结底,虽然我们只希望采纳那些确实能带来改进的变更(包括新的超参数配置),但一味追求绝对确定性也并非明智之举。
  • 因此,如果一个新的超参数点(或其他变更)相较于基线取得了更好的结果(在尽可能考虑到新点和基线各自的重训练方差之后),那么我们很可能应该将其作为未来比较的新基线。
    • 不过,我们应当只采纳那些带来的改进能够超过其增加的复杂性的变更。

探索阶段结束后

总结: 在我们完成对良好搜索空间的探索,并确定究竟需要调优哪些超参数之后,贝叶斯优化工具便成为极具吸引力的选择。

  • 到某一时刻,我们的优先级将从进一步了解调优问题,转变为生成一个最佳配置用于部署或实际应用。
  • 此时,应已形成一个经过精炼的搜索空间,该空间能够合理地覆盖当前观测到的最佳试验点附近区域,并且已被充分采样。
  • 通过前期的探索工作,我们应当已经识别出最需要调优的超参数及其合理的取值范围,从而构建出最终自动化调优研究所需的搜索空间,并尽可能分配较大的调优预算。
  • 由于此时我们不再关注最大化对调优问题的理解,准随机搜索的优势中的许多优势已不再适用,因此应采用贝叶斯优化工具来自动寻找最优的超参数配置。
    • 开源 Vizier 实现了多种用于机器学习模型调优的先进算法,其中包括贝叶斯优化算法。
    • 如果搜索空间中存在大量发散点(即训练损失为 NaN,或显著偏离均值的点),则必须使用能够妥善处理发散试验的黑盒优化工具(参见 带有未知约束的贝叶斯优化 一文,其中介绍了一种优秀的解决方案)。开源 Vizier 支持通过将发散试验标记为不可行的方式来处理此类情况,但其具体实现方式可能并不完全符合 Gelbart 等人 提出的优选方案,这取决于配置的具体设置。
  • 在此阶段,我们也应考虑评估模型在测试集上的性能。
    • 原则上,甚至可以将验证集并入训练集,并基于贝叶斯优化找到的最佳配置重新训练模型。然而,这种做法仅适用于不会再次针对相同任务进行部署的情况(例如一次性 Kaggle 比赛)。

确定每次训练的步数

  • 工作负载可分为两类:计算受限型和非计算受限型。
  • 当训练处于 计算受限 状态时,训练过程主要受制于我们愿意等待的时间,而非训练数据量或其他因素。
    • 在这种情况下,若能以更长的时间或更高的效率进行训练,通常会观察到更低的训练损失;而在适当调优后,验证损失也会相应改善。
    • 换言之,加快 训练速度等同于提升 训练效果,“最优”的训练时长始终是“在资源允许范围内尽可能长”。
    • 尽管如此,即使工作负载受计算能力限制,延长或加速训练也并非提升效果的唯一途径。
  • 当训练 非计算受限 时,我们可以根据需求自由选择训练时长;但在某一点之后,继续延长训练时间不仅难以带来明显收益,还可能导致严重的过拟合问题。
    • 在这种情况下,我们有望将训练损失降至极低水平,即便进一步延长训练时间,也只能小幅降低训练损失,而对验证损失的影响则微乎其微。
    • 特别是在非计算受限的情况下,更为充裕的训练时间预算往往能使调优过程更加容易,尤其是在调整学习率衰减策略时,因为这类策略与训练预算之间存在强烈的交互作用。
      • 换言之,如果训练时间预算非常有限,可能就需要将学习率衰减策略调整至近乎完美的程度,才能获得理想的误差率。
  • 不论工作负载是否属于计算受限类型,任何增加梯度方差(跨批次)的方法通常都会导致训练进度放缓,从而可能需要更多的训练步数才能达到特定的验证损失目标。造成梯度方差增大的常见原因包括:
    • 使用较小的批量大小
    • 应用数据增强技术
    • 添加某些类型的正则化方法(如 Dropout)

当训练并非计算受限时,如何确定训练时长

  • 我们的主要目标是确保模型经过足够长时间的训练以达到最佳效果,同时避免在训练步数上过度浪费。
  • 如有疑问,宁可多训练一些。只要正确使用事后(最优)检查点选择机制,并且检查点设置得足够频繁,延长训练时间通常不会导致性能下降。
  • 在超参数调优实验中,切勿调整 max_train_steps 参数。应选定一个固定值,并在整个实验中保持一致。然后根据这些实验的结果,绘制出事后检查点选择机制所找到的最佳训练步数,以此来优化 max_train_steps 的取值。
    • 例如,如果最佳步数总是出现在前10%的训练阶段,那么最大训练步数就设定得过高了。
    • 相反,如果最佳步数持续位于最后25%的训练阶段,则可能需要进一步延长训练时间,并重新调整学习率衰减策略。
  • 当模型架构或数据发生变化时(如引入数据增强),理想的训练步数也可能随之改变。
  • 下面我们将介绍如何基于使用固定学习率“完美拟合”训练集所需的步数,来初步确定 max_train_steps 的候选值。
    • 需要注意的是,“完美拟合训练集”在这里并不是一个精确或数学上严格定义的概念,而仅仅是一个非正式的描述,用来表示训练损失非常低的状态。
      • 例如,在使用对数损失函数进行训练时,如果没有正则化项,训练损失可能会持续缓慢下降,直到网络权重无限增长、模型对训练集的预测越来越自信,最终达到浮点数精度的极限。在这种情况下,我们可能会认为当训练集上的分类错误率为零时,模型就已经“完美拟合”了训练集。
    • 如果训练过程中梯度噪声增加,我们可能需要提高 max_train_steps 的初始值。
      • 比如,当模型引入了数据增强或诸如 Dropout 等正则化方法时。
    • 另一方面,如果训练过程有所改进,也有可能减少 max_train_steps
      • 例如,通过更精细地调整优化器或学习率调度策略。

使用学习率扫描法确定 max_train_steps 初始候选值的算法

[点击展开]
  • 本流程假设不仅能够“完美拟合”训练集,而且可以使用固定的学习率调度来实现这一点。
  • 如果确实能够完美拟合整个训练集,则必然存在某个配置(即某个特定的 max_train_steps 值)能够做到这一点。找到任意这样的配置,并将其 max_train_steps 值作为起点 N
  • 接着,在不使用数据增强和正则化的情况下,运行一次固定学习率扫描实验(即对学习率进行网格搜索),每一轮实验都训练 N 步。
  • 扫描实验中,速度最快的一轮达到完美训练表现所需的步数,即为我们对 max_train_steps 的初始猜测。
  • 注意: 不恰当的搜索空间可能导致自我欺骗。
    • 例如,如果所有学习率都过小,我们可能会错误地得出结论,认为需要一个非常大的 max_train_steps 值。
    • 至少应检查实验中的最优学习率是否位于搜索空间的边界上。

在计算资源受限的训练中决定训练时长

  • 在某些情况下,训练损失会持续改进,直到我们的耐心和计算资源成为限制因素。
  • 如果训练损失(甚至验证损失)持续改进,我们是否应该尽可能长时间地训练?不一定。
    • 我们可以通过运行更多较短的实验来更有效地调参,并将最长的“生产级”训练留给那些我们希望上线的模型。
    • 当每次试验的训练时间接近我们的耐心极限时,调参实验对潜在的上线候选模型变得更加重要,但我们可以完成的实验数量也会减少。
    • 或许我们可以在只训练到生产长度约10%的情况下回答许多问题,但始终存在这样的风险:在这一时间限制下得出的结论可能并不适用于训练到20%或100%的情况。
  • 采用多轮调参、逐步增加每次试验的训练步数上限是一种合理的方法。
    • 我们可以根据需要进行任意多轮调参,但通常1到3轮最为实用。
    • 基本思路是利用周转时间极短的试验,尽可能多地理解问题,同时在调参的全面性与最终最长时间运行的相关性之间做出权衡。
    • 一旦某个训练时长上限产生了有用的见解,就可以延长训练时间并继续调参,必要时再对之前短时间运行的结论进行复核。
  • 作为起点,我们建议进行两轮调参:
    • 第一轮:通过较短的运行找到较好的模型和优化器超参数。
    • 第二轮:在表现良好的超参数基础上,进行少量长时间运行,以获得最终模型。
  • 从第i轮过渡到第i+1轮时,最大的问题是如何调整学习率衰减策略。
    • 在不同轮次之间调整学习率策略时,常见的陷阱是用过多的额外训练步数却使用过小的学习率。

第一轮

[点击展开]
  • 不幸的是,无法保证在短暂、不完整的训练中找到的优秀超参数,在显著延长训练时长后仍然适用。不过,对于某些类型的超参数,它们之间往往存在足够的相关性,因此第一轮调参仍然具有参考价值。
  • 那么,我们在较短运行中发现的哪些超参数值有望迁移到较长的训练中呢?这仍需进一步研究。但根据目前所知,作者按迁移可能性由高到低列出以下猜测:
    • 很有可能迁移
      • 初期训练中的不稳定现象可以通过较少的训练步数在第一轮调参中解决。这些超参数可能是我们目前认为最有可能成功迁移的选择。
        • 热身步数
        • 初始化方法
    • 可能迁移
      • 模型架构——如果在模型架构上取得显著提升,通常可以迁移,但也可能存在许多反例。
    • 有可能迁移
      • 优化算法/优化器超参数——我们认为这些超参数可能会“松散地”迁移。其迁移的可能性显然弱于上述内容。
      • 数据增强
      • 正则化
        • 如果无法完美拟合训练集,模型可能处于正则化效果有限的区间。
    • 不太可能迁移
      • 学习率调度策略:几乎不可能完全迁移。
        • 这篇论文指出,即使是衰减策略也可能迁移,但我们并不认同这一观点。例如,在少量训练步数上调整平方根衰减策略,然后扩展到大量步数时,大部分训练都将在过小的学习率下进行。
        • 在极端的计算预算下,大多数学习率调度策略都能达到“足够好”的效果,但如果针对具体情况进行调优,则很可能带来明显的性能提升。
        • 关于随机元优化中短期视野偏差的理解描述了盲目选择学习率所带来的风险。

第二轮

[点击展开]
  • 使用第一轮中表现最好的超参数配置进行训练。
  • (推测) 🤖 利用额外的步数延长高学习率阶段的持续时间。
    • 例如,如果是线性调度,可以保持第一轮中衰减阶段的长度不变,同时延长初始阶段的恒定学习率部分。
    • 对于余弦衰减策略,只需沿用第一轮的基础学习率,并按照Chinchilla论文的做法延长max_train_steps
  • 对于拥有非常成熟建模和调参流程,且生产训练耗时又昂贵的团队来说,增加调参轮次或许有意义,但通常会显得过于复杂。
    • 我们已经描述了如何从第一步过渡到第二步。如果完全不考虑分析时间,而首要关注点是高效利用计算资源,那么理想的做法是在多轮调参中呈指数级地增加训练时长(从而延长整个研究的端到端时间)。
      • 在每一轮中,我们都系统地验证之前的决策是否仍然有效。
      • 新的想法会经过一个逐步降低风险的流程,通过从第i步到第i+1步不断延长实验时长来实现。

训练流水线的其他指导建议

优化输入流水线

摘要: 输入受限型流水线的原因及应对措施高度依赖具体任务;应使用性能分析工具,并留意常见问题。

  • 使用合适的性能分析工具来诊断输入受限型流水线。例如,对于 JAX 可使用 Perfetto,对于 TensorFlow 则可使用 TensorFlow 性能分析器
  • 最终,具体原因和解决方案将高度依赖于任务特性。在某些情况下,出于更广泛的工程考量(如尽量减少磁盘占用),可能需要接受较低的输入流水线性能。
  • 常见原因:
    • 数据未与训练过程部署在同一位置,导致 I/O 延迟(例如通过网络读取训练数据时)。
    • 在线数据预处理开销过大(建议改为离线一次性完成并保存)。
    • 意外的同步屏障干扰了数据流水线的预取。例如,在 CommonLoopUtils 中同步设备端与主机端的指标时(链接)。
  • 常用技巧:
    • 对输入流水线进行插桩以实现示例预取(例如使用 tf.data.Dataset.prefetch)。
    • 尽早从流水线中移除每个样本中未使用的特征或元数据。
    • 增加用于生成输入流水线示例的工作进程数量。例如,可以使用 tf.data service

评估模型性能

摘要: 在比训练时更大的批处理大小下运行评估。按固定的步数间隔而非固定的时间间隔进行评估。

评估设置

[点击展开]
  • 我们可以从多个角度来评估模型的性能。
    • 在线评估 - 在模型处于生产环境并提供预测服务时收集指标。
    • 离线评估 - 在模型对代表生产环境的离线训练/验证/测试数据集上运行时收集指标。
    • 定期评估 - 在模型训练过程中收集指标,这些指标可能是离线评估的代理,或者是在离线评估所用数据的一个子集上进行的。
  • 在线评估是黄金标准,但在模型开发阶段通常不切实际。
  • 根据具体问题,离线评估可能相当复杂且计算成本高昂。
  • 定期评估是最实用且经济的选择,但可能无法完全反映生产环境。
    • 我们在定期评估中的目标是使用一种便捷的离线评估替代方案,同时不牺牲训练过程中信号的可靠性。

设置定期评估

[点击展开]
  • 我们在训练过程中进行定期评估,以实时监控训练进度,以便 便于事后选择最佳检查点,并且能够在训练结束时 检查训练曲线
  • 最简单的配置是在同一台计算实例中同时进行训练和定期评估,定期在训练和评估之间切换。
    • 在这种情况下,用于评估的批处理大小应至少与训练时使用的批处理大小相同,因为在评估过程中无需保留模型激活值,从而降低了每个样本的计算需求。
  • 定期评估应按照固定的步数间隔进行,而不是按时间间隔。
    • 如果按时间间隔进行评估,可能会使训练曲线更难解释,尤其是在训练任务可能因抢占、网络延迟等问题而中断的情况下。
  • 当使用随机打乱的训练/验证/测试划分时,验证/测试指标的周期性波动可能表明存在实现错误,例如测试数据与训练数据有重叠,或训练数据未正确打乱。按固定步数间隔进行评估可以更容易地发现这些问题。
  • 当评估数据集不能被批处理大小整除时,可能会出现部分批次。请确保对填充的示例进行正确的加权,以防止损失函数因此产生偏差。通常,可以将这些填充示例的权重设为零。
  • 每次评估时保存足够的信息,以支持离线分析。理想情况下,应保存部分独立样本的预测结果,因为它们对于调试非常有价值。
    • 生成诸如SavedModels之类的文件,可以方便在评估作业完成后进行临时性的模型检查。

选择定期评估的样本

[点击展开]
  • 定期评估作业可能无法在合理时间内完成对整个离线评估数据集的指标计算。这通常需要对数据进行采样以供定期评估使用。
  • 构建采样数据集时,我们需考虑以下因素:
    • 样本大小
      • 确保定期评估任务所用的采样数据集上的性能与整个离线评估数据集上的性能一致,即采样数据与完整数据之间不存在偏差。
      • 定期评估所用的数据集应足够小,以便能够轻松地对其全部样本生成模型预测;同时又应足够大,以准确衡量模型的改进(即不会被标签噪声所掩盖)。
      • 数据集还应足够大,能够在多次试验中连续进行多次此类评估,并仍能产生准确的估计。也就是说,要避免随着时间推移逐渐“适应”验证集,从而导致模型在保留的测试集上表现不佳的情况。不过,这一顾虑在实践中很少成为问题。
    • 类别不平衡的数据集
      • 对于类别不平衡的数据集,稀有类别的性能往往较为不稳定。
      • 对于某一类别样本数量较少的数据集,建议记录正确预测的样本数量,以便更深入地了解准确率的提升情况(例如,灵敏度提高了0.05听起来很令人振奋,但这是否仅仅是因为多预测对了一个样本?)。

保存检查点和事后选择最佳检查点

摘要: 按固定步数进行训练,并在训练结束后事后选择最佳检查点。

  • 大多数深度学习框架都支持 模型检查点功能。 即定期将模型的当前状态保存到磁盘上。这样可以使训练作业在计算实例中断时仍能恢复。
  • 最佳检查点往往不是最后一个检查点,特别是在验证集性能并未持续提升,而是围绕某个值上下波动的情况下。
  • 应设置一个管道来跟踪训练过程中迄今为止看到的前N个最佳检查点。训练结束后,只需从这些检查点中选择最佳的一个即可。我们称这种方法为 事后最优检查点选择
  • 通常不需要支持提前停止训练的功能,因为我们已经预先设定了每次试验的预算,并且会保存迄今为止最好的N个检查点。

实验跟踪设置

摘要: 在跟踪不同实验时,务必记录一些关键信息,例如该研究中最佳检查点的性能,以及对该研究的简要描述。

  • 我们发现,使用电子表格来记录实验结果,对于我们处理的各类建模问题非常有帮助。通常,表格会包含以下列:
    • 研究名称
    • 该研究配置文件的存储链接
    • 备注或研究的简要说明
    • 运行的试验次数
    • 该研究中最佳检查点在验证集上的性能
    • 具体的复现命令,或关于启动训练所需但尚未提交的修改的说明
  • 寻找一个能够至少记录上述信息、且对执行人员来说方便易用的跟踪系统。未被跟踪的实验,几乎可以视为不存在。

批归一化实现细节

摘要: 如今,批归一化常常可以被层归一化替代;但在无法替代的情况下,调整批量大小或主机数量时,仍存在一些棘手的细节。

  • 批归一化会基于当前批次内的均值和方差对激活值进行归一化,然而在多设备环境下,除非显式同步,否则每个设备上的统计量都会有所不同。
  • 根据一些经验性报告(主要来自 ImageNet 数据集),仅使用约 64 个样本计算这些归一化统计量,实际上在实践中效果更好(参见 这篇论文 中提出的 Ghost Batch Norm)。
  • 将总批量大小与用于计算批归一化统计量的样本数解耦,对于比较不同批量大小的情况尤为有用。
  • Ghost batch norm 的实现并不总是能正确处理每台设备的批量 > 虚拟批量的情况。在这种情况下,实际上需要在每台设备上对批次进行子采样,以获得足够数量用于计算批归一化统计量的样本。
  • 测试模式下批归一化的指数移动平均值只是训练统计量的线性组合,因此只需在将它们保存到检查点之前进行同步即可。然而,一些常见的批归一化实现并不会同步这些指数移动平均值,而只保存第一台设备上的 EMA。

多主机流水线的注意事项

摘要: 在日志记录、评估、随机数生成器、检查点保存以及数据分片等方面,多主机训练很容易引入错误!

  • 确保流水线仅在一个主机上进行日志记录和检查点保存。
  • 在执行评估或检查点保存之前,务必确保各主机之间的批归一化统计量已同步。
  • 各主机之间必须保持一致的随机种子(用于模型初始化),同时又要有不同的随机种子(用于数据打乱/预处理),因此请务必妥善标记这些种子。
  • 通常建议将数据文件跨主机分片,以提升性能。

常见问题解答

最佳的学习率衰减策略家族是什么?

[点击展开]
  • 这仍然是一个开放性问题。目前尚不清楚如何设计一套严谨的实验,以确信地回答“最佳”的学习率衰减策略究竟是什么。
  • 尽管我们不知道最佳的策略家族,但我们相信,采用某种非恒定的学习率衰减策略非常重要,且对其调优也确实有意义。
  • 不同的学习率在优化过程的不同阶段表现最佳。采用某种形式的衰减策略,能够提高模型找到合适学习率的可能性。

默认情况下应该使用哪种学习率衰减策略?

[点击展开]
  • 我们倾向于选择线性衰减或余弦衰减,当然,其他许多类型的衰减策略也可能同样有效。

为什么有些论文会采用复杂的学习率衰减策略呢?

[点击展开]
  • 论文中出现复杂的分段式学习率(LR)衰减策略并不少见。
  • 读者常常会好奇,作者是如何得出这样复杂的策略的。
  • 很多复杂的 LR 衰减策略,其实是通过根据验证集性能临时调整学习率得来的:
    1. 首先以某种简单的 LR 衰减策略(或恒定学习率)开始一次训练。
    2. 持续训练,直到性能似乎停滞不前。此时暂停训练,然后以更陡峭的 LR 衰减策略(或更低的恒定学习率)继续训练。重复这一过程,直到会议或发布截止日期到来。
  • 盲目照搬最终得到的策略通常并不是一个好主意,因为最佳的具体策略往往对其他超参数的选择非常敏感。
    • 更好的做法是复制产生该策略的算法,不过当策略是由人为判断随意制定时,这往往难以实现。
  • 这种依赖于验证误差的策略,如果能够完全自动化,倒也无妨;但那些需要人工干预、并根据验证误差动态调整的策略,往往不够稳定且难以复现,因此我们建议尽量避免使用此类策略。
    • 在发表使用了这类策略的结果之前,请务必尝试将其完全可复现。

应该如何调优 Adam 优化器的超参数?

[点击展开]
  • 如上文所述,很难对搜索空间及其采样点的数量做出普遍性的结论。需要注意的是,Adam 优化器中的各个超参数重要性并不相同。以下是针对不同试验次数预算的参考规则:
    • 如果一项研究中少于 10 次试验,只需调优基础学习率。
    • 如果有 10 到 25 次试验,则需调优学习率和 $\beta_1$。
    • 如果超过 25 次试验,则应调优学习率、$\beta_1$ 和 $\epsilon$。
    • 若试验次数远超 25 次,还可进一步调优 $\beta_2$。

为什么在调参的探索阶段要使用拟随机搜索,而不是更复杂的黑箱优化算法?

[点击展开]
  • 拟随机搜索(基于 低差异序列) 是我们的首选,相较于更为复杂的黑箱优化工具,尤其是在作为迭代调参流程的一部分、旨在深入理解调参问题(即我们所说的“探索阶段”)时。贝叶斯优化及类似工具则更适合用于开发阶段。
  • 基于随机平移的低差异序列的拟随机搜索可以被视为“抖动、打乱后的网格搜索”,因为它以均匀但随机的方式遍历给定的搜索空间,并且比随机搜索更能分散搜索点。
  • 拟随机搜索相较于更复杂的黑箱优化工具(如贝叶斯优化、进化算法等)的优势包括:
    1. 由于是非适应性的采样方式,可以在事后分析中更改调参目标,而无需重新运行实验。
      • 例如,我们通常希望找到在训练过程中任意时刻验证误差最低的试验。然而,拟随机搜索的非适应性特性使得我们能够在不重新运行任何实验的情况下,根据最终验证误差、训练误差或其他评估指标来确定最佳试验。
    2. 拟随机搜索的行为具有一致性和统计上的可重复性。
      • 即便搜索算法的实现发生变化,只要其保持相同的均匀性特征,就应当能够复现六个月前的研究结果。而如果使用复杂的贝叶斯优化软件,不同版本之间实现可能会发生重大变化,从而大大增加复现旧有搜索结果的难度。此外,有时也无法回滚到旧版本的实现(例如当优化工具以服务形式运行时)。
    3. 它对搜索空间的均匀探索使得我们更容易对结果进行推理,并推断这些结果可能揭示的关于搜索空间的信息。
      • 例如,如果拟随机搜索遍历过程中找到的最佳点位于搜索空间的边界上,这通常是一个很好的信号(尽管并非绝对可靠),表明可能需要调整搜索空间的边界。本节将对此进行更详细的讨论。然而,自适应的黑箱优化算法可能会因为早期几次不太理想的试验结果而忽略搜索空间的中部区域,即使那里同样存在表现优异的点。这是因为优秀的优化算法往往需要利用这种非均匀性来加速搜索过程。
    4. 使用拟随机搜索(或其他非适应性搜索算法)时,无论并行还是串行运行不同数量的试验,其统计结果都不会有显著差异;而对于适应性算法则不然。
    5. 更复杂的搜索算法并不总是能正确处理不可行的点,尤其是那些并非专门为神经网络超参数调优设计的算法。
    6. 拟随机搜索简单易用,在需要大量试验并行运行的情况下尤为有效。
      • 根据经验[^3],自适应算法很难在预算仅为拟随机搜索两倍的情况下超越后者,特别是在需要大量试验并行执行的情形下(此时几乎无法利用先前试验的结果来指导新试验的开展)。
      • 如果缺乏贝叶斯优化及其他高级黑箱优化方法的专业知识,我们可能无法充分发挥这些方法理论上所能带来的优势。在真实的深度学习调参场景中,很难对高级黑箱优化算法进行基准测试。这类方法目前仍是研究热点,而越复杂的算法对于缺乏经验的用户来说往往伴随着更多的陷阱。虽然相关领域的专家能够取得不错的效果,但在高并行度条件下,搜索空间和预算的影响往往会更加显著。
  • 当然,如果计算资源仅允许少量试验并行运行,而我们可以负担得起顺序执行大量试验的话,尽管贝叶斯优化会使调参结果更难解释,但它会变得更具吸引力。

[^3]: Ben Recht 和 Kevin Jamieson 指出,预算为两倍的随机搜索作为基线非常强大(Hyperband 论文也提出了类似观点),不过确实存在一些搜索空间和问题,其中最先进的贝叶斯优化技术能够轻松击败预算为两倍的随机搜索。然而,根据我们的经验,在高并行度环境下,要超越预算为两倍的随机搜索则要困难得多,因为贝叶斯优化在这种情况下几乎没有机会观察到先前试验的结果。

在哪里可以找到拟随机搜索的实现?

[点击展开]
  • 开源 Vizier 提供了拟随机搜索的实现。只需在使用示例中设置 algorithm="QUASI_RANDOM_SEARCH" 即可。
  • 另一种实现可以在这里找到。
  • 上述两种实现都会为给定的搜索空间生成 Halton 序列(旨在实现 https://arxiv.org/abs/1706.03200 中推荐的平移、打乱后的 Halton 序列)。
  • 如果没有基于低差异序列的拟随机搜索算法可用,也可以用伪随机均匀搜索代替,尽管效率可能会略低。
    • 在 1–2 维情况下,网格搜索也是可以接受的,但在更高维情况下则不建议使用(参见 Bergstra & Bengio, 2012)。

进行拟随机搜索需要多少次试验才能获得良好结果?

[点击展开]

箱线图展示了充分采样的重要性

图3:在ImageNet数据集上使用ResNet-50模型进行了100次试验的调优。通过自助法模拟了不同规模的调优预算。上方绘制了对应不同试验次数的最佳性能的箱线图。

  • 一般情况下无法给出一个通用的答案,但我们可以通过具体例子来分析。
  • 如图3所示,试验次数会对结果产生显著影响。
    • 注意当只采样6次试验时,四分位距非常大;而当采样20次时,四分位距明显缩小。
    • 即便进行了20次试验,运气特别好或特别差的几次试验之间的差异,仍可能大于在固定超参数下、使用不同随机种子对同一模型进行多次重新训练时的典型波动。对于该任务而言,这种波动可能表现为验证误差率约23%时上下浮动0.1%左右。

如何调试并缓解优化失败问题?

[点击展开]

摘要: 如果模型在优化过程中遇到困难,在尝试其他方法之前,务必先解决这些问题。诊断和修复训练失败是当前研究的热点领域。

更改WideResnet中单个残差块的步幅会导致训练不稳定。

图4:更改WideResnet中单个残差块的步幅(从2×2改为1×1)会导致训练不稳定。在低学习率下,这并不会降低性能,但在高学习率下,由于不稳定现象,模型将无法正常训练。通过应用1000步的学习率预热,可以解决这一特定的不稳定问题,从而允许在最大学习率为0.1的情况下稳定训练。

识别不稳定的训练工作负载

  • 如果学习率过大,任何工作负载都可能变得不稳定。只有当不稳定迫使我们使用过小的学习率时,这个问题才会真正成为瓶颈。
  • 至少有两种类型的训练不稳定值得区分:
    1. 初始化阶段或训练初期的不稳定。
    2. 训练中期突然出现的不稳定。
  • 我们可以采用系统化的步骤来识别工作负载中的稳定性问题:
    1. 进行学习率扫描,找到最佳学习率lr*。
    2. 绘制略高于lr*的学习率下的训练损失曲线。
    3. 如果这些高于lr*的学习率显示出损失不稳定(即在训练过程中损失不是下降而是上升),那么很可能通过修复这种不稳定现象能够提升训练效果。
  • 在训练过程中记录完整损失梯度的L2范数,异常值可能导致训练中途出现虚假的不稳定现象。这可以帮助我们决定如何设置梯度或更新的裁剪阈值。

注意: 有些模型会在早期表现出明显的不稳定,随后又自行恢复,最终以缓慢但稳定的节奏完成训练。然而,常见的评估频率可能不足以捕捉到这些问题!

为了检查这种情况,我们可以使用“当前最佳学习率的两倍”进行一次简短的训练,仅运行约500步,但每一步都进行评估。

说明在训练初期更频繁评估的重要性。

图5:说明在训练初期更频繁评估的重要性。如果怀疑模型存在早期训练不稳定,这种方法尤为有用。

常见不稳定模式的潜在解决方案

  • 应用学习率预热
    • 最适合解决训练初期的不稳定问题。
  • 应用梯度裁剪
    • 对于训练初期和中期的不稳定都有效,有时甚至能解决预热无法处理的不良初始化问题。
  • 尝试更换优化器
    • 有时Adam优化器能够处理Momentum优化器无法应对的不稳定情况。这仍然是一个活跃的研究方向。
  • 确保我们的模型架构采用了最佳实践和初始化方法(示例如下)。
    • 如果模型尚未包含残差连接和归一化层,应予以添加。
  • 归一化层应置于残差结构内部,例如x + f(Norm(x))。
    • 而Norm(x + f(x))则已知容易引发问题。
  • 尝试将残差分支初始化为0(例如ReZero初始化)。
  • 降低学习率
    • 这是最后的手段。

学习率预热

预热期间出现不稳定现象的例子(注意横轴为对数尺度)。

图6:预热期间出现不稳定现象的例子(注意横轴为对数尺度)。在此案例中,成功训练需要4万步的预热过程。

何时应用学习率预热

带有不稳定现象的模型的超参数轴图

图7a:展示了一种出现训练不稳定现象的模型的超参数轴图。最佳学习率位于可行范围的边缘。所谓“不可行”的试验是指那些产生NaN值或损失值异常高的试验。

带有不稳定现象的模型的损失曲线

图7b:使用导致不稳定现象的学习率训练的模型的训练损失曲线。

  • 图7a显示了一个超参数轴图,表明该模型存在优化方面的不稳定问题,因为最佳学习率正好处于不稳定区域的边缘。
  • 图7b则通过观察使用比峰值学习率高5倍或10倍的学习率训练的模型的训练损失曲线,进一步证实了这一点。如果该曲线在平稳下降后突然出现急剧上升(如上图中约第10,000步处),则可以确定该模型确实存在优化方面的不稳定问题。
如何应用学习率预热

预热对训练稳定性有益的效果

图8:学习率预热在解决训练不稳定问题上的有益效果。

  • 借助上一节的内容,我们假设实践者已经确定了模型开始变得不稳定的那一个学习率。这个值就是 unstable_base_learning_rate
  • 预热是指在训练开始前添加一个学习率调度策略,将学习率从0逐步提升到某个稳定的 base_learning_rate,而这个 base_learning_rate 至少要比 unstable_base_learning_rate 大一个数量级。默认情况下,可以尝试将 base_learning_rate 设置为 unstable_base_learning_rate 的10倍。不过需要注意的是,也可以针对例如 unstable_base_learning_rate 的100倍再次执行整个流程。具体的学习率调度如下:
    • warmup_steps 步骤内,将学习率从0线性提升至 base_learning_rate
    • 然后以恒定的学习率继续训练 post_warmup_steps 步骤。
  • 我们的目的是找到最短的 warmup_steps 数量,使得我们能够使用远高于 unstable_base_learning_rate 的峰值学习率。
  • 因此,对于每一个 base_learning_rate,都需要调整 warmup_stepspost_warmup_steps。通常可以将 post_warmup_steps 设置为 2*warmup_steps
  • 预热可以独立于现有的学习率衰减计划进行调优。warmup_steps 应该在几个不同的数量级范围内进行扫描。例如,可以尝试 [10, 103, 104, 105]。最大可行的步数不应超过 max_train_steps 的10%。
  • 一旦确定了在 base_learning_rate 下不会导致训练崩溃的 warmup_steps,就应将其应用到基准模型上。本质上,我们将这个预热调度插入到现有调度之前,并利用上述讨论的最佳检查点选择方法,将此次实验与基准模型进行比较。例如,如果原本有10,000个 max_train_steps,并且进行了1,000步的预热,那么新的训练过程总共将持续11,000步。
  • 如果为了稳定训练需要较长的预热步骤(超过 max_train_steps 的5%),可能需要增加 max_train_steps 来适应这一情况。
  • 在各种工作负载中并没有一个“典型”的预热步数。有些模型只需要100步,而另一些模型(尤其是Transformer)则可能需要4万步以上。

梯度裁剪

梯度裁剪用于早期训练不稳定

图9:梯度裁剪纠正早期训练不稳定现象的示意图。

  • 梯度裁剪在出现较大或异常的梯度问题时最为有效。
  • 裁剪既可以解决早期训练中的不稳定问题(训练初期梯度范数过大),也可以解决中期训练中的不稳定问题(训练过程中突然出现的梯度尖峰)。
  • 有时,较长的预热期可以解决一些即使通过裁剪也无法解决的不稳定问题:请参阅上文的相关部分
    • 🤖 那么在预热期间进行梯度裁剪怎么样呢?
  • 理想的裁剪阈值应略高于“典型”的梯度范数。
  • 以下是一个梯度裁剪的具体示例:
    • 如果梯度的范数 $\left | g \right |$ 超过梯度裁剪阈值 $\lambda$,则执行 ${g}'= \lambda \times \frac{g}{\left | g \right |}$,其中 ${g}'$ 是新的梯度。
  • 在训练过程中记录未被裁剪的梯度范数。默认情况下,生成:
    • 梯度范数随训练步数变化的曲线图
    • 所有步骤梯度范数的直方图
  • 根据梯度范数的90百分位数来选择梯度裁剪阈值。
    • 阈值会因工作负载而异,但90%是一个不错的起点。如果效果不佳,还可以进一步调整这个阈值。
    • 🤖 那么是否可以采用某种自适应策略呢?
  • 如果尝试了梯度裁剪后,不稳定问题仍然存在,则可以进一步加强裁剪力度(即降低阈值)。
  • 极端激进的梯度裁剪本质上是一种变相降低学习率的方式。如果我们发现自己不得不采取极端激进的裁剪措施,那么直接降低学习率可能更为合适。
  • 一般而言,如果超过50%的更新都被裁剪,就可以认为是“极端激进”的做法。
  • 如果我们需要通过极端激进的梯度裁剪来解决不稳定问题,那么不如直接降低学习率。

为什么你们把学习率和其他优化参数称为超参数?它们并不是任何先验分布的参数。

[点击展开]
  • 确实,“超参数”一词在贝叶斯机器学习中有其精确的定义,而将深度学习中我们经常调整的学习率及其他大部分参数称为“超参数”实际上是一种术语上的误用。
  • 对于学习率、架构参数以及我们在深度学习中调整的其他所有内容,我们更倾向于使用“元参数”这一术语,因为它避免了因滥用“超参数”一词而可能带来的混淆(尤其是在讨论贝叶斯优化时,因为概率响应曲面模型本身也有真正的超参数)。
  • 不幸的是,尽管可能存在混淆,但“超参数”这一术语在深度学习社区中已极为普遍。
  • 因此,对于像本文档这样面向广泛受众的文件——其中包含许多不太了解这一技术细节的人——我们选择了顺应当前的术语习惯,以避免引入另一种潜在的混淆。
  • 当然,如果我们发表研究论文时,可能会做出不同的选择;我们也鼓励大家在大多数情况下使用“元参数”这一术语。

为什么不应该通过调整批量大小来直接提升验证集性能?

[点击展开]
  • 不改变训练流程其他任何细节的情况下,单纯改变批量大小通常会影响验证集性能。
  • 然而,如果为每种批量大小分别优化训练流程,两种批量大小之间的验证集性能差异通常会消失。
  • 与批量大小交互最强烈、因此需要为每种批量大小单独调优的超参数主要是优化器超参数(如学习率、动量)和正则化超参数。
    • 较小的批量大小由于样本方差会引入更多的噪声到训练算法中,这种噪声具有正则化作用。因此,较大的批量大小更容易过拟合,可能需要更强的正则化或额外的正则化技术。
  • 此外,当改变批量大小时,训练步数也可能需要相应调整
  • 综合考虑所有这些因素后,目前尚无令人信服的证据表明批量大小会影响可达到的最高验证性能(参见 Shallue 等人, 2018)。

所有流行优化算法的更新规则是什么?

[点击展开]

随机梯度下降 (SGD)

$$\theta_{t+1} = \theta_{t} - \eta_t \nabla \mathcal{l}(\theta_t)$$

动量法

$$v_0 = 0$$

$$v_{t+1} = \gamma v_{t} + \nabla \mathcal{l}(\theta_t)$$

$$\theta_{t+1} = \theta_{t} - \eta_t v_{t+1}$$

Nesterov 动量法

$$v_0 = 0$$

$$v_{t+1} = \gamma v_{t} + \nabla \mathcal{l}(\theta_t)$$

$$\theta_{t+1} = \theta_{t} - \eta_t( \gamma v_{t+1} + \nabla \mathcal{l}(\theta_{t}))$$

RMSProp

$$v_0 = 1 \text{,} m_0 = 0$$

$$v_{t+1} = \rho v_{t} + (1 - \rho) \nabla \mathcal{l}(\theta_t)^2$$

$$m_{t+1} = \gamma m_{t} + \frac{\eta_t}{\sqrt{v_{t+1} + \epsilon}}\nabla \mathcal{l}(\theta_t)$$

$$\theta_{t+1} = \theta_{t} - m_{t+1}$$

ADAM

$$m_0 = 0 \text{,} v_0 = 0$$

$$m_{t+1} = \beta_1 m_{t} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)$$

$$v_{t+1} = \beta_2 v_{t} + (1 - \beta_2) \nabla \mathcal{l}(\theta_t)^2$$

$$b_{t+1} = \frac{\sqrt{1 - \beta_2^{t+1}}}{1 - \beta_1^{t+1}}$$

$$\theta_{t+1} = \theta_{t} - \alpha_t \frac{m_{t+1}}{\sqrt{v_{t+1}} + \epsilon} b_{t+1}$$

NADAM

$$m_0 = 0 \text{,} v_0 = 0$$

$$m_{t+1} = \beta_1 m_{t} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)$$

$$v_{t+1} = \beta_2 v_{t} + (1 - \beta_2) \nabla \mathcal{l} (\theta_t)^2$$

$$b_{t+1} = \frac{\sqrt{1 - \beta_2^{t+1}}}{1 - \beta_1^{t+1}}$$

$$\theta_{t+1} = \theta_{t} - \alpha_t \frac{\beta_1 m_{t+1} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)}{\sqrt{v_{t+1}} + \epsilon} b_{t+1}$$

致谢

  • 我们衷心感谢 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 和 George E. Dahl 和 Justin Gilmer 和 Christopher J. Shallue 和 Zachary Nado},
  title = {深度学习调优手册},
  url = {http://github.com/google-research/tuning_playbook},
  year = {2023},
  note = {版本 1.0}
}

贡献说明

  • 本项目并非 Google 官方支持的产品。

  • 我们非常期待您的反馈!

    • 如果您喜欢本手册,请点亮星标!或者发送邮件至 deep-learning-tuning-playbook [at] googlegroups.com。您的评价将帮助我们证明创建更多类似资源的必要性。
    • 如果发现任何错误,请提交问题以开启讨论。对于不适合使用问题的功能咨询或其他信息交流,请在 GitHub 上新建讨论主题。
  • 如前言所述,本文档是一个持续更新的活文档。我们预计会定期进行小幅或大幅改进。如果您希望及时获取更新通知,请关注我们的仓库(详见 GitHub 文档)。

  • 请勿在未通过问题跟踪系统与作者沟通的情况下直接提交拉取请求。

贡献者许可协议

对本项目的贡献必须附带贡献者许可协议 (CLA)。您(或您的雇主)保留对贡献内容的版权;该协议仅授予我们使用和再分发您贡献的权利,作为项目的一部分。请访问 https://cla.developers.google.com/ 查看您当前签署的协议或签署新的协议。

通常情况下,您只需提交一次 CLA,因此如果您已经提交过(即使是在其他项目中),则无需再次提交。

代码审查

所有提交内容,包括项目成员的提交,均需经过审查。我们使用 GitHub 拉取请求来进行这一过程。有关如何使用拉取请求的更多信息,请参阅 GitHub 帮助

社区准则

本项目遵循 Google 开源社区准则

常见问题

相似工具推荐

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|今天
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

139k|★★☆☆☆|今天
开发框架Agent语言模型

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

107.7k|★★☆☆☆|2天前
开发框架图像Agent

NextChat

NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。

87.6k|★★☆☆☆|今天
开发框架语言模型

ML-For-Beginners

ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。

85k|★★☆☆☆|今天
图像数据工具视频

ragflow

RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。

77.1k|★★★☆☆|2天前
Agent图像开发框架