深度学习的⾼性能计算技术(Horovod分布式)
深度学习的⾼性能计算技术
介绍
在过去⼏年中,神经⽹络已被证明是解决各种问题的极其有效的⼯具,并且在规模和计算要求⽅⾯迅速增长。 2012年,⽤于图像识别的超级卷积⽹络在物体识别⽅⾯取得了巨⼤进步,花了⼀周时间⽤两个GPU,拥有6000万个参数。 2016年,研究⼈员在语⾔建模⽅⾯取得了突破,该⽹络拥有超过10亿个参数,在32个GPU上训练了三个星期。在百度研究所的硅⾕AI实验室内,2014年我们的深度语⾳识别系统的第⼀次迭代⼤约有1100万个参数,⽽⼀年后的下⼀次迭代已经增长到1亿个参数。
随着神经⽹络的参数数量和计算需求的增长,在许多节点和许多GPU上⾼效并⾏化神经⽹络训练变得越来越重要,因为等待数⽉的⼤型⽹络训练会减慢实验速度并限制进⼀步的发展。在这篇⽂章中,我们介绍了⼀种来⾃⾼性能计算(HPC)领域的技术,并演⽰了如何将其应⽤于深度学习以在神经⽹络训练中实现显着的性能提升。
通信问题
在将神经⽹络的训练并⾏化到许多GPU上时,您必须选择如何将不同的操作分配到可⽤的不同GPU上。
在这⾥,我们专注于⼀种称为数据并⾏随机梯度下降(SGD)的技术。
与模型并⾏技术不同,模型并⾏指的是将模型部署到很多设备上(设备可能分布在不同机器上,下同)运⾏,⽐如多个机器的GPUs。当神经⽹络模型很⼤时,由于显存限制,它是难以在跑在单个GPU上,这个时候就需要模型并⾏。⽐如Google的神经机器翻译系统,其可能采⽤深度LSTM模型,如下图所⽰,此时模型的不同部分需要分散到许多设备上进⾏并⾏训练。深度学习模型⼀般包含很多层,如果要采⽤模型并⾏策略,⼀般需要将不同的层运⾏在不同的设备上,但是实际上层与层之间的运⾏是存在约束的:前向运算时,后⾯的层需要等待前⾯层的输出作为输⼊,⽽在反向传播时,前⾯的层⼜要受限于后⾯层的计算结果。所以除⾮模型本⾝很⼤,⼀般不会采⽤模型并⾏,因为模型层与层之间存在串⾏逻辑。但是如果模型本⾝存在⼀些可以并⾏的单元,那么也是可以利⽤模型并⾏来提升训练速度,⽐如的Inception模块。
在数据并⾏⽅式中与标准SGD⼀样,梯度下降是通过数据⼦集(⼩批量)完成的,需要多次迭代才能在整个数据集中进⾏。然⽽,在数据并⾏训练中,每个GPU具有整个神经⽹络模型的完整副本,并且对于每次迭代,仅分配⼩批量中的样本的⼦集。对于每次迭代,每个GPU在其数据上运⾏⽹络的前向传播,然后进⾏反向误差传播以计算相对于⽹络参数的丢失梯度。最后,GPU彼此通信获取由不同GPU计算出的梯度的平均,将平均梯度应⽤于权重以获得新的权重。 GPU都在锁定步骤中进⾏迭代,并且⼀旦GPU完成其迭代,它必须等待其他所有GPU完成它们⾃⼰的迭代以便可以正确地更新权
重。这相当于在单个GPU上执⾏SGD,但我们通过在多个GPU之间分配数据并⾏执⾏计算来获得加速。
当您只有两个GPU和以兆字节数据为单位的参数时,这些GPU的通信⽅式可能⽆关紧要。 但是,当您的模型具有数⼗亿个参数时,梯度可能占⽤千兆字节的空间(因为每个参数都有⼀个梯度值),并且您正在协调数⼗个GPU,通信机制变得⾄关重要。
例如,考虑最直接的通信机制。 每个GPU都在其⼩批量的⼦集上计算梯度。 然后,每个GPU将其梯度发送到单个GPU,该GPU获取所有梯度的平均值,并将平均值发送回所有其他GPU。
需要发送的数据越多,发送数据的时间就越长;每个通信信道都具有最⼤吞吐量(带宽)限制。例如,良好的互联⽹连接可以提供每秒15兆字节的带宽,⽽千兆以太⽹连接可以提供每秒125兆字节的带宽。 HPC群集上的专⽤⽹络硬件(如Infiniband)可在节点之间提供每秒⼏千兆字节的带宽。质数的孤独
在从单个GPU发送和接收数据的直连机制中,该单个GPU必须从所有GPU接收所有参数,并将所有参数发送到所有GPU。系统中的GPU越多,通信成本就越⾼。
让我们评估⼀下这种通信策略如何在真实模型上运⾏,例如以百度深度语⾳2为模型的语⾳识别⽹络,具有三亿个可训练参数。每个参数四个字节的三亿个参数⼤约是1.2千兆字节的数据。假设您系统上的⽹络硬件可以⽀持每秒1千兆字节的带宽;在这种情况下,如上所述将系统并⾏化到两个GPU上将使每次迭代减慢1.2秒。将您的训练任务并⾏化到10个GPU将使每次迭代减慢10.8秒;随着GPU数量的增长,每次迭代所需的时间呈线性增长。即使每次迭代花费⼏秒钟,通信成本的这种线性增长也会使得进⼀步的并⾏化变得不切实际并且会降低训练效率。
⼀种替代⽅案是放弃训练算法的同步性质,并通过梯度下降的迭代消除所有GPU在锁定步骤中前进的约束。但是,虽然这可以使您的模型更容易并⾏化,删除此约束的算法(异步SGD的变量)却可能难以调试,并且对于某些模型可以收敛到部分⼦结果,这不是我们这篇⽂章的⽬的。
相反,我们可以通过使⽤⾼性能计算领域的分布式reduction算法来解决通信问题,并充分利⽤带宽最
优的ring-allreduce⽅案。风景图
The Ring Allreduce
上述简化通信策略的主要问题是通信成本随着系统中GPU的数量线性增长。 相反,ring allreduce是⼀种算法,其通信成本是恒定的并且与系统中GPU的数量⽆关,并且仅由系统中GPU之间的最慢连接确定; 事实上,如果你只考虑带宽作为通信成本的⼀个因素(并忽略延迟),那么ring allreduce是⼀种最佳的通信算法。 (当您的模型很⼤时,这是对通信成本的⼀个很好的预估,并且您只需要较少数次数发送⼤量数据。)
Ring allreduce中的GPU排列在⼀个逻辑环中。 每个GPU应该有⼀个左邻居和⼀个右邻居; 它只会向其右邻居发送数据,并从其左邻居接收数据。
该算法分两步进⾏:第⼀步是scatter-reduce,然后是all-gather。 在scatter-reduce步骤中,GPU将交换数据,使得每个GPU最终得到最终结果的⼀部分。 在all-gather步骤中,GPU将交换这些块,以便所有GPU最终得到完整的最终结果。
农村义务教育阶段学校教师特设岗位计划
The Scatter-Reduce
为简单起见,让我们假设⽬标是元素层⾯的,即浮点数的单个⼤数组的所有元素的总和; 系统中有N个GPU,每个GPU都有⼀个相同⼤⼩的数组,并且在allreduce的末尾,每个GPU都应该有⼀个相同⼤⼩的数组,其中包含原始数组中数字的总和。
⾸先,GPU将数组分成N个较⼩的块(其中N是环中的GPU数量)。
风之语将数组分区为N个块
接下来,GPU将进⾏N-1次迭代的scatter-reduce; 在每次迭代中,GPU都会将其中⼀个块发送到其右邻居,并从其左邻居接收⼀个块并累积到该块中。 每次迭代发送和接收的块都是不同的; 第n个GPU通过发送块n和接收块n-1开始,然后从那⾥向后进⾏,每次迭代发送它在前⼀次迭代中接收到的块。
例如,在第⼀次迭代中,上图中的五个GPU将发送和接收以下块:
GPU Send Receive
0Chunk0Chunk4中同社区
1Chunk1Chunk0
2Chunk2Chunk1
3Chunk3Chunk2
3Chunk4Chunk3
在scatter-reduce第⼀次迭代过程中的数据传输
在第⼀次发送和接收完成后,每个GPU将具有⼀个块,该块由两个不同GPU上的相同块的总和组成。 例如,第⼆个GPU上的第⼀组块将是来⾃第⼆GPU和第⼀GPU的该组块中的值的总和。
清蒸鲍鱼在scatter-reduce第⼀次迭代完成以后⽴刻求和
在接下来的迭代中,该过程继续,并且最后,每个GPU将具有⼀个块,该块包含所有GPU中该块中的所有值的总和。 下⾯的图像演⽰了所有数据传输和中间结果,从第⼀次迭代开始,⼀直持续到scatter-reduce完成。
有数据传输和中间结果,从第⼀次迭代开始,⼀直持续到scatter-reduce完成。
Scatter-reduce data transfers (iteration 1)
七律格律
新型经营主体
Scatter-reduce data transfers (iteration 2)