0
点赞
收藏
分享

微信扫一扫

论文阅读-CheckFreq:频繁、精细的DNN检查点操作。

目标践行者 03-03 10:00 阅读 2

论文名称:CheckFreq: Frequent, Fine-Grained DNN Checkpointing.

摘要

训练深度神经网络(DNNs)是一项资源密集且耗时的任务。在训练过程中,模型在GPU上进行计算,重复地学习权重,持续多个epoch。学习到的权重存在GPU内存中,并偶尔进行检查点操作(写入持久存储)以实现容错。传统上,模型参数在epoch边界处进行检查点操作;对于现代深度神经网络,一个epoch需要运行数小时。因此,由于抢占、节点故障或进程故障等原因导致训练作业中断,会导致恢复后丢失数小时的GPU工作。

我们提出了CheckFreq,这是一个自动、精细的检查点框架,它具有以下特点:

  1. 通过系统的在线分析算法,在迭代的粒度上算法地确定检查点频率
  2. 在运行时通过自适应速率调节动态地调整检查点频率,以控制检查点开销
  3. 使用轻量级可恢复迭代器检查数据加载器状态,以保持每个epoch使用数据集中的每个项仅一次的不变性
  4. 通过引入两阶段检查点,仔细地将检查点与计算流水线化,以降低检查点成本。

我们在各种模型、存储后端和GPU代数上进行了实验,结果表明,CheckFreq可以将恢复时间从数小时缩短到数秒,并将运行时开销控制在3.5%以内

1. 引言

深度神经网络(DNNs)广泛应用于许多人工智能应用中,包括图像分类[20, 23, 41]、语言翻译[46]和语音识别[17]。尽管DNN在这些任务中实现了最先进的准确性,但其计算复杂度很高,训练时间长达数天[8, 35]。

训练始于一组随机选择的可学习参数(例如权重和偏差),并在由数据小批次组成的迭代中进行前向和反向传递。在每次反向传递结束时,使用获得的梯度重新计算可学习参数,并在GPU内存中更新。训练持续多个时期,其中一个时期是对数据集的完整遍历。训练结束时,学习到的参数被保存到持久存储中以供推断使用。

由于DNN训练的运行时间较长,模型权重和优化器状态(即模型状态)有时会写入持久存储,以实现容错性;否则,由于进程失败或节点崩溃而导致作业中断,可能会清除所有作业状态,导致数小时的GPU工作丢失。这被称为检查点。传统上,模型在epoch边界处进行检查点[30]。

DNN训练作业经常中断。无论是专用企业集群还是云实例,由于软件和硬件错误导致的故障是不可避免的。以往的研究表明,在大规模大数据集群中,基础设施和进程故障很常见,平均故障间隔时间(MTBF)为4-22小时[19, 27]。同样,针对GPU集群,在微软进行的大规模DNN训练集群研究[22]突出显示DNN训练作业遇到基础设施故障、节点崩溃、软件错误和用户错误等中断。在分析期间(2个月),在微软集群中,作业故障之间的平均时间为45分钟(不包括早期故障)。

此外,云服务提供商最近出现了具有成本效益的可抢占式VM,其价格比专用VM便宜6-8倍[9, 16, 29];这些VM可能随时被抢占。最近的研究表明,在谷歌云上,GPU VM可能每15分钟被抢占至少一次,每24小时至少一次[31]。

当发生中断时,长时间运行的、有状态的DNN作业会突然终止,清除内存中的模型参数。例如,使用V100 GPU在ImageNet-1K数据集上对ResNext101进行准确性训练需要270小时(每个时期约3.9小时)[35];如果在时期边界处进行检查点,每次中断平均会浪费约两个小时的GPU计算。更一般地,数据集大小不断增长[3,7,24],模型架构变得更大、更复杂[8,10,35],因此增加了DNN时期时间和总体训练时间。因此,频繁对训练进度进行检查点处理至关重要,比epoch更精细的粒度,即在迭代级别进行。在本文中,我们探讨如何以自动且与模型和硬件无关的方式进行细粒度检查点处理,而无需对训练工作负载进行干扰性更改

我们提出了CheckFreq,这是一个用于DNN训练的细粒度检查点框架。CheckFreq在确保低运行时开销和提供高检查点频率之间取得平衡,以便在作业中断或失败时最大限度地减少GPU时间损失,通过执行迭代级检查点。CheckFreq有两个主要组成部分:自动确定何时进行检查点的检查点策略,以及执行正确、低成本检查点的检查点机制。为此,我们借鉴了高性能计算(HPC)和存储社区的一系列技术,并结合了针对DNN的新型优化,如基于内存的流水线快照、利用空闲GPU能力进行快速快照和DNN感知的系统化剖析来动态调整检查点频率。使用CheckFreq,我们展示了在作业中断期间,恢复时间从几小时缩短到几秒钟。

DNN在迭代粒度上进行细粒度检查点面临着几个独特的挑战,CheckFreq解决了这些挑战,如下所述。

  1. 检查点频率。没有一个适用于所有模型、硬件和训练环境的单一检查点频率。检查点频率取决于多个因素,例如模型大小、存储带宽和训练迭代时间。此外,作业可能在写入检查点时面临干扰,原因是从相同的存储设备读取数据集,或者由于并发运行的作业共享存储带宽以写入检查点。在训练环境中静态确定检查点频率对于运行时来说是次优的,如果作业面临干扰。因此,CheckFreq通过在运行时分析作业特征来算法地确定初始检查点频率。CheckFreq使用系统化的在线剖析来确定给定训练环境下模型的最佳检查点频率。然而,在实践中,由于干扰导致的额外开销可能会减慢检查点过程。为了解决这个问题,CheckFreq引入了自适应速率调整,以动态监视检查点间隔之间的作业运行时间,并适当地调整检查点频率,以保证总体的运行时开销在用户给定的界限内。

  2. 检查点暂停。要检查点当前状态,模型状态必须在每次迭代时更新。因此,训练必须暂停一小段时间,以准确检查点当前状态;GPU(或任何加速器)在检查点完成之前保持空闲,从而导致训练中的检查点暂停。简单地增加检查点频率(例如每次迭代)会导致很高的运行时开销,因为会出现检查点暂停。
    CheckFreq使用DNN感知的两阶段检查点策略来减少检查点暂停。检查点操作分为snapshot()和persist()两个阶段。在snapshot()阶段,CheckFreq对所有可学习的模型状态进行一致的内存复制。此操作与计算并行进行,直到下一个迭代的权重更新,即模型参数最后更新的时间点。在persist()阶段,快照被异步写入存储设备。CheckFreq保证在开始下一个检查点操作之前,检查点可靠地持久化在磁盘上(使用fsync())。因此,在出现意外中断的情况下,作业状态最多会回滚一个检查点。

  3. 数据不变性。对于一大类在每个训练周期(例如CNN)中执行随机数据预处理操作的模型,确保以下数据不变性至关重要:每个周期必须以随机顺序、随机预处理(如裁剪、调整大小等)的方式处理数据集中的所有项目。现有的数据迭代器(如PyTorch和MxNet中的迭代器)不支持可恢复性。当作业中断时,这些迭代器可能会错过或重复数据项目,导致在迭代粒度上继续训练时模型准确性下降。
    为了解决这个挑战,CheckFreq引入了一个可恢复的数据迭代器,在中断的情况下,即使在存在中断的情况下,也能保持数据不变性。该迭代器使用基于周期种子的伪随机变换,可以在中断之前重构迭代器状态。因此,CheckFreq的迭代器使得正确的迭代级检查点成为可能。

我们将CheckFreq实现为PyTorch的可插拔模块,只需对原始作业脚本进行最小的更改(<10行代码)。我们在各种模型、GPU和存储类型上进行评估,证实CheckFreq将浪费的GPU时间从数小时减少到不到一分钟,并且与现有的基于周期的检查点方案相比,运行时开销不到3.5%。当在1080Ti GPU上训练ResNet50作业时,CheckFreq将端到端训练时间缩短了2倍,在V100 GPU上训练ResNext101作业时,将其缩短了1.6倍,这两种情况下作业每5小时中断一次。我们进一步通过在频繁中断(每2个周期一次)和迭代级检查点的情况下使用ImageNet数据集训练ResNet18来展示CheckFreq可恢复迭代器的重要性;现有的最先进数据加载器(如DALI)导致准确性下降高达13%,而CheckFreq能够将模型训练到目标准确性。

总之,本文的主要贡献如下:

  • 分析了当前DNN检查点技术的现状,并强调了对细粒度检查点的需求以及实现它所涉及的挑战。
  • 设计和实现了CheckFreq,这是一个自动的、细粒度的DNN训练检查点框架,利用DNN计算模型提供低成本、流水线式的检查点。
  • 实验证明CheckFreq在各种模型和硬件配置下将恢复时间从数小时缩短到数秒,同时产生不到3.5%的运行时开销。

2 背景

本部分简要介绍了DNN计算模型以及在DNN训练中检查点的作用。

DNN计算模型。训练深度神经网络(DNN)是确定网络中的权重和偏差集合(统称为可学习参数)的过程。一旦训练完成,DNN会使用在训练阶段学到的权重来计算输出。

DNN训练从一个随机选择的可学习参数集开始,并按照迭代步骤进行,称为迭代。每个迭代处理数据集的一个小不相交子集,称为小批量。当整个数据集被处理一次时,就完成了一个时期。训练的每个迭代按顺序执行以下步骤。

  • 数据增强。从存储中获取一个数据小批量并应用随机预处理操作。例如,在像ResNets这样的流行图像分类模型中,预处理包括随机裁剪输入图像、调整大小、旋转和翻转等操作。
  • 前向传播。在数据小批量上应用模型函数以获得预测结果。
  • 反向传播。使用损失函数来确定预测与正确答案之间的偏差程度;DNN中的每个层都会计算损失的梯度。
  • 权重更新。使用在反向传播中计算出的梯度来更新可学习模型参数。

在训练结束时(通常在固定数量的时期后),最终学到的参数会被保存到持久存储中。为了对模型进行推断,DNN会使用学到的参数初始化,然后进行输出预测。

检查点。训练DNN是一个非常耗时的任务。例如,BERT-large,最先进的语言建模网络,在使用16个V100 GPU并行训练时需要2.5天。由于可学习参数在训练过程中一直保留在GPU内存中,任何由于进程崩溃、服务器崩溃、作业或虚拟机抢占或作业迁移而导致的训练工作中断都会导致到目前为止学到的模型状态丢失。通常,这种状态的大小在几百MB到几百GB之间。因此,花费数小时的GPU时间进行训练将会丢失。为了克服这一问题,模型状态通常会在时期边界处进行检查点设置;即写入到持久存储中以实现容错。当训练工作恢复时,可以加载该检查点,以确保不会完全丢失进度。

恢复时间。当DNN训练作业中断时,它会回滚到上一个已检查点的已完成时期,如图1所示。请注意,最后一个检查点和中断点之间执行的所有GPU工作都会丢失,并且在恢复训练时必须重新执行。由于中断而丢失的GPU时间量被称为恢复时间。换句话说,这是将模型带回中断前状态所需的时间。

3 检查点的当前状态

我们分析了流行的开源ML训练框架(如PyTorch、TensorFlow和MxNet)中检查点的当前状态。我们分析了MLPerf提交v0.7中的训练工作负载以及由NVIDIA、TensorFlow和PyTorch发布的官方工作负载。我们发现开源ML训练框架中的检查点设置是不正确且低效的

  • 正确性。训练脚本中使用的检查点机制可能会导致在作业失败或中断时丢失或损坏检查点文件。
  • 效率。检查点设置效率低下。检查点设置的频率是以专断方式确定的,通常在epoch边界处进行,这会导致数小时的GPU时间丢失以进行恢复。此外,目前缺乏对细粒度检查点设置的支持;现有数据迭代器不支持在迭代边界处恢复训练状态,导致检查点停顿较高。

3.1 检查点设置不正确

由于覆盖而导致损坏。PyTorch维护的一些官方训练工作负载在每个时期结束时会覆盖同一个检查点文件以减少存储利用率。然而,这会使得在检查点操作期间发生崩溃时检查点文件损坏的风险增加。之前的研究表明,不同的文件系统以不同方式处理覆盖;在ext3的回写模式下崩溃可能导致非原子数据更新,导致数据损坏,而在ext4上可能会截断文件,导致数据丢失。在任一情况下,检查点文件都无法使用;训练必须从第一个时期重新开始。

检查点文件可能不会持久保存。分析训练框架用于检查点的基本原语,例如torch.save,发现它们没有对检查点文件进行fsync()操作。我们验证了这可能导致数据丢失。此外,频繁执行同步的fsync()会严重影响训练性能(§5.3.1)。

3.2 检查点效率低下

检查点是以一种临时的方式进行的。在训练作业中没有系统的检查点策略;检查点间隔是以一种临时的方式选择的。例如,有些作业在训练过程中不进行检查点,而其他一些作业仅在经过大量的epochs(训练的60%)之后开始检查点。总体来说,我们观察到检查点通常在epoch边界处执行,提供的容错性有限;如果作业中断,则训练将从上次完成的epoch继续,这可能会损失数小时的GPU训练时间需要重新进行。例如,当使用ImageNet在V100 GPU上训练ResNext101时,平均损失两个小时的GPU时间(§5.5)。

频繁进行检查点调度会导致检查点停顿。提供更高的容错性要求检查点比在epoch边界处更频繁地进行;即在迭代边界处进行。然而,简单地增加检查点频率会导致训练过程中出现长时间的检查点停顿。由于模型权重在迭代之间不断更新,检查点需要训练过程暂停一小段时间以准确捕获模型权重。我们将这种开销(即GPU空闲等待检查点完成的时间)称为检查点停顿。因此,根据DNN(因为DNN的检查点大小在100MB到100GB之间变化)和存储带宽,找到正确的检查点频率以最小化检查点停顿至关重要

在训练过程中违反数据不变量可能会影响模型准确性。每个epoch对数据集进行完整遍历,顺序随机,并保持每个数据项在每个epoch中只被看到一次的不变量。在epoch边界处进行检查点的一个好处是数据迭代器状态不需要持久保存,因为在epoch结束时会重置。在更细粒度(即在迭代边界处)进行检查点,需要基础设施支持来恢复数据迭代器的状态。我们注意到,在某些自定义的NLP模型的数据加载器中存在持久化迭代器状态的支持,它们不会对每个批次执行随机预处理操作。然而,对于在每个批次中对输入数据应用随机变换的图像和视频模型,PyTorch、MxNet和NVIDIA的DALI等现有的数据加载器在迭代边界处无法恢复。结果就是,它们在中断情况下违反数据不变量,导致热门模型ResNet18的准确性下降高达13%(图6)。

3.3 总结

总之,我们观察到当前的检查点机制是不正确的;可能导致检查点数据丢失或损坏。此外,检查点策略是临时的;没有确定检查点频率的系统方法,既能最小化恢复时间,又能产生低检查点停顿。

最小化恢复时间的解决方案是进行频繁的迭代级别检查点。然而,执行正确且高效的细粒度检查点是具有挑战性的。我们需要(1)低成本的检查点机制,(2)轻量级、可恢复的数据迭代器以保持模型准确性,以及(3)一种系统确定检查点频率的方法。

4 CheckFreq:设计与实现

我们介绍CheckFreq的目标和它提供的恢复保证。然后,我们概述CheckFreq的整体架构,并讨论CheckFreq使用的技术来实现列出的目标。

4.1 目标

准确性。CheckFreq 的目标是提供频繁的迭代级检查点,确保一致性和持久性。

不影响模型准确性。CheckFreq 的目标是通过确保在训练中断后数据不变时,不影响模型的统计效率。

自动频率选择。CheckFreq 的目标是根据正在训练的模型和训练环境(GPU 生成,存储类型,迭代时间)自动确定和调整检查点的频率。检查点频率影响恢复时间,即将模型状态恢复到中断前状态所需的时间。

低检查点停顿。CheckFreq 的目标是减少训练过程中的检查点停顿,以便频繁检查点产生较低的运行时开销(例如,< 5%)。

最小代码更改。CheckFreq 的目标是对训练代码进行最少更改,以自动化检查点管理和恢复。

4.2 CheckFreq 恢复保证

中断的作业将从磁盘上最新的可用检查点恢复训练。在传统的基于时期的检查点中,无论作业何时中断,训练都将从前一个时期分界线恢复,如图 1 所示。 如果作业每个时期执行 n 次迭代,每次迭代花费 t_i 时间,那么该作业的平均恢复时间 R_avg 为:

这是因为,当在一个时期的中间中断时,重新开始时必须重新做到目前为止在该时期已完成的工作,因为状态被重置到前一个时期的结尾。因此,基于时期的检查点的恢复时间 R 受到限制:

注意,n * t_i 是一个时期的持续时间;它可能长达几小时。CheckFreq 的目标是提供对恢复时间的严格边界,并采用更精细的在迭代分界线进行检查点处理的方法。CheckFreq 保证在任何时刻系统中最多只有一个正在进行的检查点操作。中断时,它将回滚至多一个检查点 - 可能是最后启动的检查点(如果完成),或如图 2 所示的前一个检查点。如果 CheckFreq 自动确定的频率为 k 次迭代,那么 CheckFreq 保证恢复时间 R 受到限制:

所选的检查点频率 k 是 n 的 100 到 300 倍以下,如我们在评估中所示(§5.4),因此,与基于时期的检查点相比,恢复时间将大大减少。

4.3 设计

我们现在介绍 CheckFreq 的架构概述以及如何使用各种技术来提供有界成本的频繁检查点,详见 §4.2。表1列出了 CheckFreq 使用的不同技术以及每种技术的好处。

概述。CheckFreq 的架构如图3所示。CheckFreq 有三个主要组件:可恢复数据迭代器,它将一个小批量数据返回给训练作业;基于反馈的检查点策略,确定何时触发检查点;以及低成本的检查点机制,分为快照(snapshot())和持久化(persist())两个阶段。CheckFreq 监控每个检查点间隔中产生的运行时开销,这被用作反馈,以动态调整检查点频率,确保运行时开销不超过用户给定的限制 p(例如,5%)。在中断时,CheckFreq 恢复最新可用的检查点并继续训练。我们以下面详细描述每个组件。

4.3.1 检查点机制

目前的深度神经网络(DNN)检查点是同步执行的,即在检查点操作完成之前会暂停训练。然而,同步检查点会引入大量的检查点停顿,如果频繁执行,将导致较大的运行时开销。换句话说,同步检查点的成本(Tc)较高。例如,考虑一个每三次迭代执行一次检查点的策略。模型状态在权重更新阶段后被写入磁盘,该阶段根据反向传播中计算的梯度更新权重。如图4a所示,检查点成本发生在关键路径上,导致较大的检查点停顿,从而显著降低整个训练时间。为了在开销 p 内掩盖这种较高的检查点成本,需要较少频繁地执行检查点,这反过来又会导致较高的恢复成本

两阶段检查点。CheckFreq 旨在通过减少检查点停顿来降低中断时的恢复成本。为了实现低检查点成本,CheckFreq 引入了一个针对 DNN 的两阶段检查点机制。CheckFreq 将检查点分为两个阶段:快照(snapshot())和持久化(persist()),并与计算流水线化。CheckFreq 两阶段检查点的主要见解是利用了 DNN 计算模型(§2)在现代加速器(如 GPU)上进行检查点操作的能力。

第一阶段:快照(snapshot())。

在迭代的权重更新步骤之后执行该阶段。在这里,模型状态的副本被捕获到内存中,以便可以异步地写入存储介质。由于模型状态位于 GPU 内存中,快照(snapshot())涉及将模型参数从 GPU 复制到 CPU 内存。如图4b所示,如果在关键路径中同步执行此操作,则会出现非常大的快照(snapshot())开销。因此,CheckFreq 将快照(snapshot())与计算仔细地进行流水线化。

要谨慎地对快照(snapshot())与计算进行流水线化,以确保模型参数的一致性并保持随机梯度下降(SGD)的正确性,SGD 是一种常用的学习算法优化技术。简单地进行流水线化可能会导致一个不一致的快照,其中包含了一次迭代的部分权重更新和另一次迭代的其余权重更新。CheckFreq 利用 DNN 学习结构来实现正确的、流水线化的快照。

我们观察到,在迭代的反向传播后,可学习的模型参数在 GPU 内存中进行更新;这个步骤称为权重更新。因此,我们可以将第 i 次迭代的快照(snapshot())与计算流水线化,直到第 i + 1 次迭代的权重更新。如果快照(snapshot())在那时之前没有完成,那么第 i + 1 次迭代将等待正在进行的快照(snapshot())成功完成,如图4c所示。这种紧密耦合是为了确保一致的快照;否则,我们可能会捕获到一个由后续迭代部分更新的状态,从而影响学习算法的正确性[28]。

基于 GPU 的 snapshot()。虽然 snapshot() 与后续迭代的计算进行了流水线化,但在无法完全隐藏从 GPU 复制模型状态到 CPU 的成本的情况下,它可能导致检查点停顿。因此,CheckFreq 在可行的情况下进一步优化了这个操作,使用基于 GPU 的 snapshot()。

我们观察到,在 GPU 内存中执行快照(snapshot())的成本比执行到 CPU 内存中的成本低一个数量级,因为后者涉及关键路径上的 GPU 到 CPU 的复制。因此,CheckFreq 采取了以下方法:

a)当训练环境中有可用的额外 GPU 内存来保存快照的副本时,我们在 GPU 上的 GPU 内存中进行快照(snapshot())。然后,持久化(persist())阶段异步地将快照复制到 CPU 内存,然后再复制到磁盘。

b)如果没有额外的 GPU 内存可用,CheckFreq 将直接将快照(snapshot())存储到 CPU 内存中。这可能会导致关键路径上的停顿。

c)CheckFreq 根据需要调整检查点频率,以最小化快照(snapshot())的开销,特别是在情况(b)下可能会非常大,并且持久化(persist())阶段的停顿。

第二阶段:持久化(persist())。

检查点的第二阶段是持久化(persist())阶段,类似于已经研究过的异步检查点技术[33, 34, 40, 45]。然而,为了提供 §4.2 中讨论的有界回滚保证,持久化(persist())与计算紧密耦合。CheckFreq 将 persist() 操作作为后台进程执行,并监视其进度。当根据策略触发后续检查点时,将检查正在进行的 persist() 操作的进度。如果 persist() 操作尚未完成,则计算进程将等待正在进行的检查点操作完成。这确保在任何时候只有一个正在进行的检查点操作,并且如果作业中断,将回滚到最多一个先前的检查点。虽然放弃正在进行的检查点可能很诱人,但这是一个棘手且有风险的操作。假设我们放弃当前的检查点并开始写入下一个检查点,如果此时发生故障,可能会丢失两个检查点。这可能引发连锁反应;如果所有最近的检查点都被放弃,故障可能导致回滚到一个相当旧的检查点,从而导致较长的恢复时间。由于 CheckFreq 的目标是确保我们最多回滚到一个先前的检查点,它不会放弃任何正在运行的检查点。

可恢复的轻量级数据迭代器。DNN 训练工作负载通过数据迭代器使用由数据迭代器提供的薄 API 与 CheckFreq 进行交互。DNN 训练中数据迭代器的功能是将预处理的数据项批次返回给 GPU,以满足数据不变性 - 每个时期以随机顺序处理所有数据项。虽然 PyTorch 中的原生迭代器和 DALI 等最先进的数据流水线提供了常见情况下的支持,但如果训练中断,它们缺乏可恢复性。例如,考虑一个包含 1-8 个数据项的数据集。在一个时期内,处理数据项的顺序如图5a所示。假设我们在处理每个数据项的迭代结束时对模型状态进行检查点。如果训练在该时期中断,数据迭代器将丢失状态,并以随机洗牌的数据集顺序重新开始,如图5b所示,导致一个时期中的数据项重复和遗漏,违反了数据不变性。CheckFreq 的数据迭代器使用以下技术来支持恢复:

  • 每个时期使用一个根据时期编号生成的种子对数据项进行洗牌。因此,要重新创建相同的洗牌顺序,只需持久化当前时期 ID 和迄今为止处理的数据项数量(使迭代器检查点轻量级)。
  • 当训练恢复时,迭代器重新构建洗牌顺序,并从上次检查点的位置确定性地重新开始,如图5c所示。

总结。两阶段检查点机制以及可恢复的数据迭代器提供了正确的、低成本的检查点。接下来需要回答的一个重要问题是,我们应该多频繁地对模型进行检查点操作?

4.3.2 检查点策略

为了执行自动的迭代级别检查点,我们必须确定执行检查点的频率。一方面,我们可以在每次迭代之后进行检查点,提供低恢复成本,但可能有很高的运行时开销。另一方面,我们可以在时期边界执行粗粒度的检查点,导致高恢复成本但低运行时开销。一个有效的检查点策略必须在恢复成本和运行时开销之间找到适当的平衡,最小化二者。CheckFreq的检查点策略的主要思想是每隔k次迭代(称为检查点频率)启动检查点,以便一个检查点操作的开销可以分摊到k次迭代中。虽然之前在HPC领域的工作已经探索了根据集群中故障分布来确定检查点频率的方法,CheckFreq则根据DNN和硬件特征找到掩盖检查点开销的最短间隔。

系统化的在线分析。CheckFreq采用基于系统化分析的方法来确定检查点频率。应该选择这样的频率,使由于检查点引起的运行时开销在实际计算时间的百分比p内,其中p是用户决定的允许开销(比如说5%)。

CheckFreq如下确定初始检查点频率。当训练作业启动时,CheckFreq的数据迭代器(§4.3.1)会自动分析几个迭代级别和检查点特定的度量指标,这些度量指标影响检查点频率-迭代时间(Ti)、权重更新时间(Tw)、创建内存中GPU副本时间(Tg)、创建内存中CPU副本时间(Tc)、写入存储的时间(Ts)、检查点大小(m)、峰值GPU内存利用率(M)和总GPU内存(Mmax)。根据CheckFreq的两阶段检查点机制,频率确定算法如算法1所示。

该算法提供两个输出:1)检查点频率k,即每个检查点之间经过的迭代次数,2)快照(snapshot())模式(CPU或基于GPU)。该算法首先基于可用的空闲GPU内存确定快照模式;如果有足够的空间在GPU内存中快照模型状态,那么模式被设置为GPU,否则首选模式被设置为基于CPU的快照。根据选择的模式,算法估计在紧密耦合的方式中流水线化检查点和计算后产生的关键路径开销,如之前描述的那样(§4.3.1)。然后确定需要经过多少迭代来分摊这个开销,使得总运行时开销在阈值p以下。例如,假设检查点操作和迭代持续时间都是1时间单位。如果运行时开销的阈值设置为5%,那么CheckFreq选择每20次迭代执行一次检查点。

自适应速率调整。当模型的训练环境在作业运行时维持不变时,静态的基于分析的频率确定方法效果很好。然而,在实践中,在线分析器估计的检查点成本可能存在偏差,导致高于预期的运行时开销。例如,一个作业可能面临由于共享用于读/写的存储而导致写入干扰,这会影响写入检查点所需的时间。因此,CheckFreq使用一种自适应速率调整技术来执行反馈驱动的频率更改。CheckFreq的迭代器监控作业的运行时和运行时期间检查点成本的实际成本(初步频率确定后)。如果观察到的运行时超过了期望的开销,那么这些值会用于重新计算检查点频率。这个想法是确保总的运行时开销不会超过阈值p。

4.4 实现

我们将CheckFreq作为PyTorch的可插拔模块实现。CheckFreq的数据迭代器是基于PyTorch的DALI的最新数据管道实现的。CheckFreq可以用作PyTorch中现有数据加载器的即插即用替代品。

CheckFreq通过对第一个时期的迭代的1%或前50次迭代进行分析来确定初始检查点频率,选择两者中的最小值。因此,在这个初始阶段,没有进行检查点,这只是总运行时间的一个非常小的部分。此外,我们将分析的度量和确定的策略缓存到持久存储中,以便在作业在崩溃后恢复时可以跳过分析。

CheckFreq内部使用torch.save(),接着使用fsync()执行persist(),从而保证持久性。为了消除数据损坏的可能性,CheckFreq总是将检查点写入一个新文件。然而,为了保持空间利用率有限,CheckFreq在任何给定时间内仅保留两个磁盘上的检查点:一个已完成的检查点和另一个正在进行中的检查点。另外,保存在时期边界执行的检查点(可以由用户关闭)。

CheckFreq在优化器中对权重更新步骤进行包装,使用一个信号量来等待正在进行的snapshot(),以确保在下一次迭代更新之前完成对模型状态的拷贝。

5 评估

在本节中,我们使用一系列微基准测试和端到端训练以评估使用CheckFreq相对于当前基于时代的检查点方案的效力,并在各种DNNs上进行中断。我们的评估旨在回答以下问题。

- CheckFreq的迭代器是否可以使迭代级检查点成为可能,而不影响准确性?(§5.2)

- 与现有同步策略相比,CheckFreq的2阶段检查点机制是否可以减少检查点停顿?(§5.3)

- CheckFreq是否可以更频繁地进行检查点,并且运行时开销较低,而不是基于时代的检查点?(§5.4)

- 当DNN训练被中断时,CheckFreq是否减少恢复成本?(§5.5)

- 在真实的抢占式训练环境中,在存在作业中断的情况下,使用CheckFreq训练至准确度的端到端收益是什么?(§5.6)

5.1 实验设置

我们使用PyTorch中的最新数据流水线DALI对CheckFreq与基于时代的检查点方案的效力进行评估。

服务器。我们在两代GPU上评估CheckFreq;

模型。我们在评估中使用了7个DNN。ResNet18、ResNet50、ResNext101、DenseNet121、VGG16、InceptionV3均基于Imagenet-1k数据集,以及基于Wikipedia和BookCorpus数据集的Bert-Large预训练。对于每个模型,我们使用这些模型在文献中报告的默认小批量大小。

基线。我们使用基于时代的检查点作为所有模型的基线,除了BERT。BERT以迭代为单位进行训练;因此我们使用默认检查点间隔200个迭代作为基线。为了执行持久且正确的检查点,我们在检查点操作返回后明确刷新检查点文件。

5.2 准确性影响

我们首先展示了需要可恢复的数据迭代器以使精细的迭代级检查点成为可能。使用现有的最新数据迭代器执行迭代级检查点会导致违反DNN数据不变性(如第4.3.1节所述)。为了证明这一点,我们进行以下实验。我们在三种不同的情况下训练ResNet18作业,训练70个时代或至目标准确度69.5%之一(以先到者为准);

- 无中断。这是正常的训练场景,作业直到完成时才中断。这里不执行检查点。

- 基线中断。这种情况使用现有的DALI迭代器(与原生PyTorch迭代器相同)在作业被中断前的迭代执行检查点。我们每隔7分钟(大约每两个时代)中断一次作业。这对应于抢占式调度器中常用的轮次持续时间。

- CheckFreq中断。该设置使用能够轻量级检查点迭代器状态并正确恢复的CheckFreq数据迭代器。我们像前一个设置一样进行检查点、中断和恢复作业。

我们绘制了Top-1验证准确率与累积训练时间的图。图6显示,使用现有迭代器无法进行迭代级检查点,而不影响模型准确性。这是因为模型状态在迭代边界处进行检查点,但数据加载器状态丢失。然而,使用CheckFreq的迭代器,模型几乎在与作业完全没有中断时相同的时间内达到目标准确度。

存储开销。检查点数据迭代器状态没有显著的空间开销;它需要持久化两个整数 - 时代和迭代编号,占用几个字节的磁盘空间。因此,CheckFreq提供了轻量级、可恢复的数据迭代器,不影响DNN的准确性。

5.3 检查点机制的性能

现在我们评估CheckFreq的两阶段检查点策略的性能,并将其与同步策略进行比较。我们进一步提供了由于流水线化persist()和snapshot()操作而产生的好处拆分。

5.3.1 检查点停滞

图7显示了在Conf-Pascal上由于CheckFreq和基线检查点机制在选择的频率上进行检查点时产生的运行时开销。频率在不同模型间变化,但对于给定模型,CheckFreq和基线保持恒定。虽然CheckFreq能够将运行时开销限制在约3.5%,基线由于频繁检查点而产生17-73%的运行时开销。运行时开销的减少是由两阶段检查点和与计算的流水线化造成的。

5.3.2 收益的拆分

为了了解检查点机制的每个阶段对减少检查点停滞的贡献有多少,我们在两台服务器上使用相同大小为64的VGG16进行训练,这是Conf-Pascal上能够容纳的最大批量大小。检查点独立选择在两台服务器上进行。我们在表3中评估了三种设置;1) 基线同步模式,2) 仅带有persist()流水线的CheckFreq(由IO流水线表示),以及同步执行snapshot(),3) 带有persist()和snapshot()流水线的CheckFreq。

在两台硬件上,相比只有持续流水线,CheckFreq通过将检查点的两个阶段与计算流水线化,能够将检查点成本显著减少5-18倍。在Conf-Pascal上,由于较慢的存储设备,由于流水线化persist()而产生的好处明显。在Conf-Volta上,由于快速存储,snapshot()的CPU成本和persist()的存储成本对检查点成本的贡献相等。因此,将snapshot()与计算流水线化提供了显著加速。

5.4 检查点策略

我们比较了CheckFreq确定的具有3.5%开销p阈值的检查点频率。表4显示了在Conf-Pascal上使用8个GPU执行分布式数据并行训练时,各个模型每时代执行的检查点数量以及每个检查点大小。这里有两个主要收获。首先,检查点频率随模型不同而变化;因此频率选择必须考虑模型特性。其次,与基于时代边界执行的比较,CheckFreq能够执行83-278倍更频繁的检查点,同时产生≤ 3.5%的开销。在Conf-Volta上,CheckFreq导致比基于时代政策更频繁进行检查点,大约25-100倍。更频繁的检查点直接转换为更快的恢复时间,我们将在第5.5节进行评估。

适应性调整频率。为了展示自适应频率调整的重要性,我们进行了以下实验。我们在一台单独的GPU上运行了一个VGG16训练作业(作业-A),允许其以CheckFreq选择的初始频率进行检查点(开销为5%)。在经过100个迭代后,我们在同一台机器上的另一台GPU上触发另一个VGG16作业(作业-B),使得这两个作业竞争存储带宽来写检查点。我们测量了作业-A的500个迭代运行时间,有和没有自适应频率调整。结果如表5所示。当作业-A独立运行时,在每14次迭代进行检查点会产生5%的开销。然而,当在作业-A经过100次迭代后引入作业-B时,如果两个作业之间没有调整,检查点频率静态地固定为14次迭代,作业-A的运行时开销会增加到35%(在表5中表示为静态)。这是因为作业竞争存储带宽,增加了检查点成本。相反,CheckFreq的自适应速率调整动态地调整检查点频率,并将开销限制在5%。

5.5 恢复时间

为了了解在作业中断时使用CheckFreq的好处,我们评估了基于时期的检查点和CheckFreq的恢复时间。 使用基于时期的检查点,无论在时期的哪个时候作业被中断,作业都会回滚到先前完成的时期。 因此,在最佳情况下,如果一个时期结束后立即发生故障,那么恢复时间就与CheckFreq相同。 但是,平均来说,如果作业在时期中间被中断,则可能会丢失半个时期的工作。 在最坏的情况下,如果作业在时期完成之前失败,那么整个时期必须被重做。 对于七种不同的模型,我们比较了两种不同情况下的平均案例恢复时间; 1)Conf-Volta上的单GPU训练作业在表6a中,2)Conf-Pascal上的8 GPU数据并行作业在表6b中。

可以看到,CheckFreq能够将恢复时间从几分钟(甚至几小时)减少到几秒,同时运行时开销不超过3.5%。 例如,在V100 GPU上训练ResNext101时,CheckFreq将平均恢复时间从2小时减少到32秒。

5.6 端到端训练

我们通过模拟一种抢占式集群场景来评估使用CheckFreq训练的端到端收益。 我们考虑一个具有类似于像Philly [2,22]这样的大型生产集群中的抢占式调度器的集群。 我们考虑平均抢占间隔为5小时。 图8绘制了基于时期的基线检查点策略和使用CheckFreq训练ResNet50的总训练持续时间与前1个验证准确性的图表。 通过将恢复时间从1.9小时减少到每次中断不到一分钟,CheckFreq使训练速度提高了2倍。 在Conf-Volta上进行的类似实验使ResNext101的训练时间加速1.6倍。

6 讨论

在分布式集群训练中的适用性。 CheckFreq目前适用于分布数据并行(DDP)模式,其中每个节点(秩0)只有一个GPU负责检查点。 虽然我们展示了单GPU和多GPU训练的结果,但将其扩展到多节点设置是直接的;在多GPU和多节点设置中进行检查点在PyTorch等框架中与DDP相同。 模型权重在不同的工作节点(同一节点或在分布式集群中)之间通常在每次迭代时同步,或者在同步之前积累几十次迭代;因此,每个节点在这些同步点上看到相同版本的权重。 因此,每个节点上都运行一个CheckFreq实例,并在同步边界处持续相同的检查点以进行本地恢复。 由于每个节点独立持久化检查点且并行进行,因此检查点没有额外的同步开销。

普适性。 CheckFreq专注于优化检查点,这是DNN训练作业从故障中恢复的迄今为止主要方式。 虽然我们的论文重点是数据并行训练,但在模型或管道并行性方面的先前工作也依赖于检查点。 使用CheckFreq,可以在小批量边界(每n次迭代)进行检查点,每个管道阶段仅持久化由该工作者托管的一部分参数和优化器状态。 CheckFreq还允许在管道并行训练期间在小批量边界进行检查点(每m个微批次),因为CheckFreq的迭代器控制每个微批次导入管道。 在微批次粒度进行检查需要存储额外的模型状态 - 特别是每个阶段的累积权重梯度,以及参数和优化器状态。 我们将将CheckFreq的实现集成到支持管道并行性的框架中留待未来研究。

虽然我们在PyTorch中实现了CheckFreq,但我们可以通过将框架特定的API封装到CheckFreq公开的API中来将其扩展到其他框架,如TF和MxNet。

7 相关工作

异步深度神经网络检查点。虽然最近的工作如DeepFreeze [33]执行异步深度神经网络检查点时采用了类似于 CheckFreq 的 IO 管线技术,但它只考虑了 CPU 集群。它没有考虑使用最先进的 GPU 进行训练时,在内存中对模型状态进行快照的成本。我们的工作表明,在现代机器学习优化服务器上,在模型状态进行快照(从 GPU 复制到 CPU)的成本是显著的,展示了如何通过计算管线化这种转移,并利用多余的 GPU 能力实现快速快照。

此外,DeepFreeze 需要手动干预来调整给定模型、硬件和训练环境的检查点频率,而 CheckFreq 可以将这些复杂性隐藏在用户背后,并从分析角度确定最佳的检查点参数。与使用静态检查点频率的 DeepFreeze 不同,CheckFreq 在共享集群环境中也有益处,因为它根据内存和存储干扰调整检查点频率,以减少检查点停顿。

HPC 中的异步检查点。HPC 中的先前工作 [34, 40, 45] 使用异步检查点来掩盖 IO 延迟。将 DNN 检查点与传统 HPC 检查点区分开来的一个关键挑战是,由于 GPU 的计算能力不断增强,从 GPU 同步将模型状态复制到 CPU 的成本很高。CheckFreq 利用 DNN 学习结构,精心设计甚至在内存快照中进行计算管线化,以执行正确、一致的检查点。此外,CheckFreq 还通过利用多余的 GPU 内存和计算能力尽可能进行快速快照,进一步降低了检查点的延迟。

HPC 中的检查点间隔估计。先前的工作 [12, 14, 15] 根据系统中观察到的故障分布,通过 DNN 感知方式确定大规模 HPC 应用程序的检查点间隔。CheckFreq 通过利用 DNN 训练的确定性、重复结构,系统地在运行时对资源利用情况进行概况,以 DNN 感知的方式进行这一操作。

自适应检查点。在 HPC 应用程序中,使用自适应性进行故障管理的想法已被用于根据故障预测模块决定何时进行检查点 [25]。CheckFreq 引入了 DNN 检查点频率的自适应性。它根据正在训练的模型的特性、系统硬件和其他作业干扰的特点,识别并动态调整检查点频率。

TensorFlow 检查点管理器。TF 检查点管理器 [43] 允许在用户指定的时间间隔进行检查点,并支持保持迭代器状态。然而,它存在三个缺点。首先,检查点频率由用户自行决定;如果选择不慎,这会导致较长的检查点停顿。其次,如果涉及随机数据转换,它无法检查迭代器状态;对于大多数基于图像的模型 [44],这是常见情况。最后,即使在可以保持迭代器状态的情况下,TF 会连同预提取的项目将整个运算符图写入存储,导致较大的检查点大小。CheckFreq 通过自动调整检查点频率并使用轻量级、可恢复的数据迭代器来解决这些挑战。

框架透明的检查点。透明的检查点技术,如 CRIU [1],可以备份整个虚拟机状态以实现容错;然而,它们不会检查 GPU 或加速器状态。即使它们能够捕获整个设备状态,设备状态本身也比迭代边界处捕获的模型状态大一个数量级,使频繁的 CRIU 检查点变得不切实际。因此,在这项工作中,我们专注于主导 DNN 容错方法 - 框架辅助的模型状态检查点。

8 结论

本文介绍了 CheckFreq,一种用于 DNN 训练的自动、细粒度检查点框架。CheckFreq 利用可恢复的数据迭代器、流水线化的两阶段检查点机制以及自动确定和调节检查点频率,在迭代级别实现了一致、低成本的检查点。当作业中断时,CheckFreq 将流行的 DNN 的恢复时间从几小时缩短到几秒,同时带来较低的运行时开销。

举报

相关推荐

0 条评论