\

MLPerf结果背后:IPU上的ResNet-50训练加速

作者:

分享  

Share on weixin
Share on weibo
Share on linkedin

订阅

Graphcore工程师于2021年12月[9]发布的最新MLPerf v1.1训练结果中提供了出色的大规模性能,我们的IPU-POD16在ResNet-50上的表现优于Nvidia的旗舰DGX A100。

在此,我们将解释我们的团队如何为这种流行的计算机视觉模型实现了这些大规模加速。在本技术指南中,我们将揭示Graphcore工程师使用的各种技术和策略,包括高效的硬件扩展、存储优化、实验跟踪、性能优化等。

在专注于IPU的MLPerf[9]中ResNet-50的基准测试优化的同时,本指南给出了基准测试优化的思考过程背后的一般性观点,这些优化也可以转化为其他应用程序和硬件。

加速ResNet-50

对于我们于2021年12月[9]发布的MLPerf v1.1结果,在一个IPU-POD上,我们在ImageNet(RN50)上以每秒30k图像吞吐量和38个时期训练ResNet-50直至收敛,时间为28.3分钟,验证准确率为75.9%。

在于2020年开始我们的第一个MLPerf项目之前,ResNet-50训练的吞吐量约为每秒16k图像,大约需要65个时期才能达到收敛。将这些数字放在一起,我们得到了3.2倍的整体改进。然后,我们将应用程序从IPU-POD16扩展到IPU-POD256,这使我们的训练时间又缩短了7.5倍,吞吐量提高了12倍。那么,我们是如何实现这种加速的呢?

我们在公共示例中提供了在此过程中开发的工具,这些工具并非特定于RN50或MLPerf基准测试。我们认为,行业里的其他IPU开发人员可能会发现这些工具对他们的模型很有用。关键成分是:

  • 优化作业分配和通信
  • 优化的主机IO和在多个主机上分布的数据布局
  • 在Weights and Biases上的实验跟踪
  • 较小的有效批尺寸
  • 从带有Momentum的SGD切换到LARS优化程序
  • 具有统计缓存的分布式batch-norm
  • 再计算检查点而非流水线处理
  • 随机舍入
  • 优化的编译和存储配置文件

IPU-POD专为人工智能加速至超级计算规模而打造

图:将应用程序从一个IPU-POD16扩展到我们的IPU-POD256

IPU硬件如何扩展机器学习应用程序

为了扩展我们的应用程序,许多功能必须到位。扩展时的一个主要挑战是增加了的批尺寸和通信需要数据传输时间和代码存储。对于本地副本,我们希望保持微批尺寸尽可能大,以获得batch norm(批规范)的良好统计学估计,这是ResNet-50模型的关键部分。每个副本的梯度需要聚合,更新由优化程序执行。

这带来了计算和通信开销。减少这种情况的一个技巧是单个副本上的梯度累积,并使用更大的有效批尺寸。通过添加更多副本,有效批尺寸将呈线性扩展。虽然这种方法将保证近线性扩展,但更高的有效批尺寸会增加获得收敛所需的时期数。因此,对于较大的系统,需要减少梯度累积,并且梯度的有效通信是必不可少的。

在我们的实验中,IPU-POD128和IPU-POD256的最佳折衷方案是梯度累积计数为2,通信量略有减少,但保持尽可能小的有效批尺寸。当批尺寸更大时,“LARS优化程序和超参数优化”中提到的更改是必要的,因为SGD所需的时期比LARS更多。此外,如“扩展主机-IPU通信”中所述,我们过度使用了负载分配工具PopDist。通过增加具有本地数据存储的主机数量,我们提高了数据加载带宽,并确保无论使用多少个加速器,数据传输都不会减慢。

硬件扩展:连接IPU-POD64平台

正如我们最新的MLPerf提交所展示的惊人扩展,Graphcore的IPU-POD在设计之初就考虑到了可扩展性。在机架内,IPU通过高带宽IPU-Link彼此直接连接,形成两个环。使用这些直接连接,每个IPU-POD64提供10.24TB/秒的巨大IPU-Link带宽,具有超低时延(250纳秒)。在这些垂直的机架内连接之上,IPU跨机架被(直接或通过交换机)连接起来,形成一个水平的环。这意味着机架数量增加一倍,可用带宽量增加超过一倍。

Graphcore通信库(GCL)旨在充分利用这些硬件特性。

IPU-POD128和IPU-POD256由多个IPU-POD64构建而成。单个IPU-POD64由16个IPU-M2000垂直堆叠组成,并与IPU-Link连接形成2D-Torus。我们的横向扩展解决方案的灵活性使我们能够将IPU-POD64水平连接在一起,形成更大的系统。有两种可能的方法可以连接此类系统:直接(一个IPU-M上的GW-Link直接连接到其他IPU-POD64系统上的IPU-M2000)或通过交换结构,其中所有IPU-M2000上的GW-Link都连接到交换机,然后将流量转发到其他IPU-POD64上的正确目标IPU-M2000。在这两种情况下,多个IPU-POD64之间的同步都是通过GW-Link发送的,而不需要物理同步线来实现更简单的横向扩展。对于用于MLPerf作业的IPU-POD128和IPU-POD256,我们使用切换解决方案,因为它能让我们更加灵活,并提供更好的故障切换。

图:Graphcore针对IPU-POD128到IPU-POD512的横向扩展解决方案

观察IPU-POD横向扩展拓扑的各个方面,现在我们可以大致了解一下它在实践中的样子。这表明,从需要的“额外工具包”的角度来看,即使现有交换结构上的部署带来了所有的灵活性和出色的选项,但它实际上并不像最初认为的那样密集。该系统有8个IPU-POD64机架,因此我们可以将其称为IPU-POD512。只需使用两个128端口-100GbE交换机即可实现IPU-POD512中每个IPU-M2000之间的所有GW-Link互连。

使用Graphcore通信库(GCL)扩展通信

为了加快人工智能模型的训练,一个想法是在许多IPU上复制模型,每个IPU处理不同的批。在处理了一个批之后,副本使用全缩减来共享它们从批(梯度)中学到的内容。在理想情况下,如果全缩减是瞬时的,我们将在吞吐量方面实现完美的扩展:副本数量翻倍将使我们能够处理双倍的训练样本。

GCL中已经实现了多项优化,可以实现超出单个IPU-POD64的横向扩展。在编译时Poplar已知并详细说明所有模型副本内部数据交换,并且假设所有集体通信、机器学习模型的详细信息和网络拓扑在编译时也是已知的,GCL执行是确定性的,可以相应地进行调度和优化。GCL还公开了一个公共API,用于将通信组指定为整个副本集的子集,使我们能够灵活地在大型系统上执行操作。对于IPU-POD256的更大扩展,我们使用分阶段的全缩减,其中多POD系统上的张量减少作为三个不同的操作加以执行。

首先,缩减散射在每个IPU-POD64内的IPU-Link上完成,这些IPU-POD64是IPU-POD256的构建块。缩减散射的输出成为在GW-Link上运行的全缩减的输入。这将在多个POD之间交换数据元素,确保同一级别的每个副本都包含相同的数据。最后,对全缩减的输出执行全聚集集体操作,并再次在每个单独的IPU-POD64中运行,以便最终每个副本都包含相同的数据副本。

我们的实现有一个关键特征,即在全缩减中花费的时间是要共享的数据总量除以可用总带宽的函数。因为IPU数量翻倍意味着带宽量翻倍,所以全缩减的时间保持不变。时间恒定的前提下,全缩减是Graphcore产品的关键特性:它使创新者能够通过使用更多硬件来更快地进行实验,有效地减少反馈循环,最终带来令人兴奋的发现。

鉴于我们针对大型系统的小梯度累积计数为2,任何对梯度通信的优化都会对我们的扩展性能产生重大影响。例如,我们将不同类型和形状的张量组合在一起,一次性进行通信。此外,为了充分利用带宽,我们优化了主机和IPU之间的网关,以立即转发数据,从而显著降低跨各种应用程序的延迟。每个IPU-POD64都有自己的网关。因此,这种变化主要有利于从IPU-POD16到IPU-POD64的扩展。

图:三阶段全缩减的可视化表示

针对扩展的存储优化

虽然数据所需的存储在扩展时保持不变,但交换代码需要额外的存储。因此,例如“其他存储和速度优化”中提到的存储优化对于扩展的成功至关重要,特别是因为LARS优化程序需要比SGD更多的存储。扩展到IPU-POD128和IPU-POD256的特定优化是减少IPU-POD之间交换的代码大小。

将验证扩展到IPU-POD256

对于验证,不需要反向传递,并且在batch norm层中应用了同步的移动均值和方差。因此,计算布局大不相同。为了不浪费时间进行计算图置换,我们改为应用离线评估方案,即我们在训练期间存储检查点,然后使用验证数据评估性能。我们还保持IPU的相同配置,以避免重新配置需要花费的时间。这意味着在POD256的情况下,我们有128个主机进程,其中每个进程负责一个验证文件,然后汇总结果以计算整体性能。由于我们使用的是静态计算图,因此即使批尺寸为1,也无法完美分割50000张验证图像,效率会比较低。但是,对于MLPerf设置,需要对所有图像进行处理,并且不能省略样本。因此,我们将数据填充到下一个更大的批,然后在后处理过程中移除填充结果。

在IPU硬件上大规模加速ResNet-50

实验跟踪

在整个项目过程中,跟踪实验、查找详细的参数配置并深入研究日志非常重要。因此,我们充分利用了使用Weights and Biases进行的实验跟踪,并定期创建报告以与同事交流结果,并比较运行以找出任何潜在的差异。实验具有挑战性的原因是,在时期数较少的情况下,收敛对任何变化都过于敏感。例如,将累积计数减半可以轻松地将非收敛设置转换为收敛设置。此外,实验之间存在很大差异,需要这种方法来进行实验跟踪。我们跟踪了2600多个实验。最近,我们在卷积神经网络存储库中扩展了跟踪。使用–wandb和–wandb-project选项,结果会立即上传,而无需等待最终结果上传。

图:Weights and Biases报告

减少时期数

Batch-Norm与Group-Norm

在实践中,人们通常训练的网络大约有90个时期甚至更多。由于MLPerf基准测试只关心训练时间,因此需要进行大量调整来减少这个数字。考虑到之前的比赛结果,我们的目标是将数量减少到44个时期甚至更少。最初的实现使用group norm(组规范)而不是batch-norm来加快处理速度并避免样本之间的依赖。有关讨论,请参见[1]。

对于65个或更多时期,这种归一化(Normalization)效果很好。然而,在对超参数进行微调的同时,我们了解到需要更激进和更昂贵的归一化才能如希望的那样在较小时期计数中完成收敛。这意味着我们开发的用于实现较大batch-norm的工具是特定于MLPerf基准测试的,因为必须减少时期的数量。如果没有这个要求,我们可能会坚持group norm。

图:每个子图对应于一种特定的归一化技术,其特征在于其组件组共享相同的归一化统计数据。在每个子图中,中间激活的张量由批轴B、通道轴C和空间轴(H, W)组成。图片来自作者,改编自[7]。

增加批尺寸

我们最初的设置是一个超过4个IPU(智能处理器)的流水线,复制因子为4,用于数据并行处理和分组调度。我们使用了16的批尺寸。将该设置更改为batch-norm只不过是一个简单的配置更改,但收敛性仍然略有改善。当我们通过使用存储高效通信、限制每个IPU的代码存储大小以及调整流水线阶段的长度来微调存储和流水线阶段以获得24的批尺寸时,情况会变得更好。尽管如此,我们还是无法达到预期的44个时期。因此,我们运行了一些模拟,发现批尺寸为32就足够了。通过模拟,我们可以在44个时期内达到收敛,但吞吐量低于可接受的水平,我们需要进行一些“提高吞吐量”部分所述的调整。

较小的有效批尺寸

为了获得良好的硬件加速,处理大批量数据是很常见的。在单个加速器上使用更多数据通常会增加ALU(算术逻辑单元)的使用,并确保加速软件获得足够的工作负载。请注意,IPU具有分配工作负载的独特方式,还可以加速小批量的工作负载。此外,梯度和优化软件更新的通信可能很昂贵,因此可以通过降低更新的频率来增加吞吐量,例如通过使用梯度累积。请注意,梯度累积会随着每次增加而产生递减收益。在我们的实验中,我们意识到更大的批尺寸需要更多的训练时期,这也可以在MLPerf参考收敛点[8]中看到。因此,批尺寸更大的好处可能超过速度的收益。另一方面,每个“副本”需要至少32的批尺寸才能使batch norm发挥作用。

对于最佳IPU-POD16配置,我们最终得到了3200的有效批尺寸(16个副本,每个副本的微批尺寸为20,梯度累积计数为10),在38个时期内收敛。为了扩展到更大的系统,我们分别减少了梯度累积计数。由于大型机器上的通信效率和优化,将梯度累积计数保持为2就足够了。对于IPU-POD64系统,我们使用类似的3840的有效批尺寸(64个副本,梯度累积计数为3),也在38个时期内收敛。对于IPU-POD128和IPU-POD256,我们使用2的梯度累积计数,有效批尺寸为5120和10240,其达到收敛的时期分别是41和45。使用更大的尺寸会增加时期数,故而不可行。

LARS优化程序与超参数优化

虽然正常的机器学习设置在超参数的选择上表现出一定的鲁棒性,但MLPerf中较低的时期数使得收敛对任何变化都很敏感。这尤其体现在优化程序的选择上。众所周知,LARS是一个很好的针对较大批尺寸优化程序。在我们的项目中,我们了解到它也是一个比带有Momentum的随机梯度下降(SDG)更好的优化程序,因为收敛前需要的时期更少。这种好处随着批尺寸的增加而增加。请注意,LARS需要更多的存储和计算,但次要成本超过了主要节省。我们的第一次和第二次MLPerf提交之间的一个主要变化是优化存储使用并启用LARS,这带来了极大的加速。例如,对于POD16设置,LARS将所需的时期数量从44个减少到38个。这是预热时期数量的一个关键因素。SGD需要5个时期,而LARS只能使用2个时期。另一个敏感的超参数是LARS中的权重衰减参数,将其减少两倍并调整学习率,最多可将收敛加速到2个时期。

增加吞吐量

流水线平衡

与自然语言处理模型BERT相比,为RN50优化流水线可能具有挑战性。有很多不同的组件需要不同的代码,并且层之间的数据规模变化很大。因此,对拆分策略的轻微修改可能会对存储配置文件产生重大影响,从剩余大量存储跳转到需要过多存储。此外,正如我们在PopVision计算图分析工具中发现的那样,处理负载可能会高度不平衡。第四个IPU的处理时间是第二个的两倍,并且由于数据的存储需求,没有可用于平衡的空间。另一方面,IPU0不能做太多的处理,因为它需要存储最大的激活。同样,IPU1和IPU2也有一些空余时间,甚至比绿条所示的同步时间还要长。由于计算和存储需求不平衡,很难进一步改进,我们选择了不同的路径,使用可以在单个IPU上工作的再计算方法,并使用分布式batch norm来实现足够大的批尺寸。

图:PopVision计算图分析工具摘录了4个IPU上的分组调度流水线,批尺寸为20。第三行(IPU 2)对应于最后一个阶段,即第四阶段。与IPU 2相比,IPU 1需要的处理周期不到IPU 2所需的60%。图片来自作者。

分布式Batch Norm

我们的batch norm实现在Poplar级别上进行了融合和优化。通过我们之前用于流水线设置的所有存储微调,我们意识到现在可以将单个IPU上的新设置的批尺寸从6增加到12,而无需任何流水线。现在,要使batch norm达到32的批尺寸,我们只需要一个分布式batch norm。对于其他的,正常的数据并行处理就足够了。我们只用几行代码,就将这个特性添加到了框架中,我们在规范化实现中聚合了多个副本的统计信息。这种方法非常有效,而且不需要更多的存储,尤其是因为统计的向量非常小。此外,反向传递只是IPU之间的梯度聚合,它促成分布式batch norm,因此只产生一行代码。

对于TensorFlow 1.15中的应用程序代码,界面保持简约。只需设置一个配置号:

对于12的批尺寸,我们需要在至少3个IPU之间聚合数据,以达到至少32的batch norm批尺寸。为了避免IPU-M2000机器之间的通信,必须是4个IPU。

再计算

为了从分布式batch norm中获得更好的吞吐量和更少的通信开销,我们希望增加批尺寸,并将分布式batch norm限制为两个IPU。因此,我们利用了再计算。由于TensorFlow 1.15中没有对此的原生支持,我们使用了编程技巧。流水线的IPU实现带有一个顺序调度,可用于在多个IPU上分割计算图。我们没有将处理分布在多个IPU上,而是将它们全部放在一个IPU上。请注意,片上存储中的代码大小几乎没有增加,但许多中间激活不会被存储而是被再计算。因此,我们释放了大量可用于增加批尺寸的存储。通过将拆分设置为b1/0/relu, b1/2/relu, b2/0/relu, b2/2/relu, b3/0/relu, and b3/3/relu,我们将批尺寸增加到20。我们可以通过将一些优化程序状态卸载到主机的方法,使用更少的再计算点。我们避免了这种可能性,并将所有内容都保存在存储中,因为我们通过将更多数据带到IPU,可以更好地利用通信带宽。因此,再计算所需的只是三个要素:

平衡再计算点需要了解计算图中不同阶段的存储占用情况。为了进行微调,我们使用了PopVision计算图分析工具中的存储配置文件,以确保存储得到优化使用。结果是,我们在初始层有更密集的再计算检查点集,并保留更长的最终阶段以减少计算开销,因为对于最后阶段,前向传递永远不会被再计算。

图:单个IPU的1472个tile的存储利用率。它达到了每个tile的存储极限。(使用PopVision计算图分析工具生成)
图:使用PopVision计算图分析工具创建的活跃度报告。可以看到不包括最后一部分的向前传递,然后是向前传递(存储增加)和向后传递(存储减少)的每个再计算部分的7个凸块。

扩展主机-IPU通信

对于ResNet-50基准测试,预处理上的数据加载是工作负载的关键部分。在我们的一项实验中,我们尝试了一个CPU内核较少的、基于Intel的主机,与使用AMD主机相比,这显著减慢了我们的处理速度。因此,我们的分解主机架构对于能够为手头的应用程序选择正确的主机尤为重要。

获得更多数据传输的一种简单方法是减小其规模。增强后的图像数据以Int8格式传输,然后在IPU而不是主机上进行归一化。归一化被实现为融合操作,将数据转换为Float16,并添加了第四个带零的通道,以减少后续卷积层的存储占用。

此外,为了传输更多数据,需要使用Graphcore的PopRun框架[6]并行化数据加载。我们的分析表明,对于每组两个副本,一个主机进程是最好的。每台主机都使用8个numa感知节点,以最佳方式运行,每个CPU配4个。因此,对于IPU-POD 16、64、128和256,我们分别使用了1、4、8和16台主机。该命令类似于:

poprun --host $HOSTS $MPI_SETTINGS --num-instances “$INSTANCES” --num-replicas “$REPLICAS” python train.py args

使用$MPI_SETTINGS中的“--numa-aware 1”激活numa感知。尽管主机进程是独立的MPI进程,但计算图在所有副本上的组合表示是跨多个机架创建的。每个主机进程读取一组单独的、大小相同的输入文件,因此避免了文件读取中的任何冲突。即使对性能的影响可以忽略不计,分布式读取数据也会保存在缓存中。

其他存储和速度优化

除了再计算,我们还使用了一些优化策略:

  • 我们储存batch-norm统计,以避免再计算。
  • 我们以FP16对权重、激活和梯度进行了所有计算。我们还使用随机舍入来改善收敛,并使用半部分进行卷积和矩阵乘法以加快速度。我们的硬件支持随机舍入。请注意,权重更新需要在每个副本上进行相同的更新,以确保权重始终保持一致。这是通过同步使用horovod广播的起始种子来实现的
with tf.Graph().as_default(), tf.Session():identical_seed = hvd.broadcast(identical_seed, root_rank=0, name=”broadcast_seed”).eval()

并确保在应用权重更新时IPU被同等地播种。这是通过以下实现的

exportPOPLAR_ENGINE_OPTIONS=’{“target.deterministicWorkers”:”portable”}’
  • 通过优化IPUConfig[5]的“availableMemoryProportion”,我们微调了用于代码的存储和用于在IPU上储存激活的存储之间的平衡,该值约为0.15。
config.convolutions.poplar_options[‘availableMemoryProportion’] = …

有关存储和处理优化的更多想法,请查看我们的新指南[4]。

限制

本博客中介绍的所有功能都可以在最新版本中获取。但我们想指出的是,尽管所有这些技术技巧可能对您的应用程序有所帮助,但它们并非必须如此。MLPerf基准测试带有不适用于实际应用的特殊规则和限制。

  • 基准测试要求的目标精度低于可实现的最大精度。
  • 对于基准测试,5次运行中只有4次需要收敛。如果有一个失败,它就会被弃用。
  • 只能更改超参数的一个子集,并且唯一可用的优化程序是带有Momentum和LARS的SGD。
  • 目标指标是训练/收敛时间,而不是吞吐量。这可能是因为随着批尺寸和累积计数的增加,吞吐量也可以增加,但收敛将花费更多的时期。
  • 我们仅每4个时期评估一次。更高的评估频率是违反规则的。
  • 训练仅在ImageNet上进行。
  • 学习率进度表是二阶多项式计划,而不是阶梯式或余弦学习率进度表。

在实践中,没有人会在ImageNet上将ResNet-50训练到75.9%的验证准确率。更简易的做法是下载具有更高准确性的预训练网络。

在实践中,人们会在不同的数据集上训练到更高的准确度。但是,当在不同的数据集上进行训练时,为该基准测试选择的参数可能不会转移。此外,可能需要更大的时期数和不同的学习率进度表。但是,随着时期数量的增加,如果训练是从头开始而不是使用预训练模型,那么使用group norm(或proxy norm)可能会更好。

75.9%的Top1准确率对于像搜索等一些应用程序来说是不够的。想象一下,您有一个像YFCC100M数据集这样的100.000.000张图像的搜索引擎,您尝试以这种准确度使用ResNet-50搜索特定类别的图像,例如折纸。丢失所有相关图像的24%对您来说可能没问题。挑战在于,由于其他类也被错误地分类,您将获得更多从其他图像中错误分类的图像,而非折纸。事实上,这些错误分类将占大多数[2]。为了获得更高的准确度,值得考虑使用更先进的模型,例如EfficientNet,这些模型受益于本博客中提到的一些功能。您或许还想阅读《我们如何使EfficientNet更高效》[3]。

结论

将强大的TensorFlow 1.15框架与Weights and Biases、Poplar和PopVision工具相结合,加上强大的MK2 IPU,我们设法充分利用了处理速度和存储,并取得了惊人的性能。

鸣谢

非常感谢Brian Nguyen、Godfrey da Costa(和他的团队)以及Mrinal Iyer,他们不遗余力地完成了这项工作。

我们还要感谢Alex Cunha、Phil Brown、Stuart Cornell、Dominic Masters、Adam Sanders、Håkon Sandsmark、George Pawelczak、Simon Long、Luke Hudlass-Galley、Jorge Bellon Castro、George Matthew等人的宝贵贡献。

参考资料

[1] A. Labatie, Removing Batch Dependence in CNNs by Proxy-Normalising Activations, Towards Data Science 2021

[2] D. Ma, G. Friedland, M. M. Krell, OrigamiSet1.0: Two New Datasets for Origami Classification and Difficulty Estimation, arxiv 2021

[3] D. Masters, How we made EfficientNet more efficient, Towards Data Science 2021

[4] Memory and Performance Optimisation Guide, Graphcore

[5] Optimising Temporary Memory Usage for Convolutions and Matmuls on the IPU, Graphcore

[6] PopDist and PopRun: User Guide, Graphcore

[7] N. Dimitriou and O. Arandjelovic, A New Look at Ghost Normalization, arXiv 2020

[8] MLPerf Reference Convergence Points, MLCommons

[9] MLPerf v1.1训练结果。 MLPerf ID: 1.1–2040, 1.1–2042, 1.1–2044, 1.1–2045, 1.1–2065. MLPerf名称和标识为商标。更多信息请参照www.mlperf.org

这篇博客最初发表在Towards Data Science上。

More Posts

Graphcore开源Argon Streams AV1视频解码器验证工具

没见过雪,神经网络如何模拟降雪?

Paperspace和Graphcore携手为开发者提供免费IPU

深入探讨:Hugging Face Optimum Graphcore上的视觉transformer

Paperspace上的IPU入门

Pienso和Graphcore携手,以更深入、更快速的人工智能洞见为企业赋能

获取最新的GRAPHCORE资讯

在下方注册以获取最新的资讯和更新:




    获取最新的GRAPHCORE资讯

    在下方注册以获取最新的资讯和更新: