数据并行:提升训练吞吐的高效方法|深度学习分布式训练专题

百度大脑      2022-02-14     523

关键词:

数据并行是大规模深度学习训练中非常成熟和常用的并行模式。本文将介绍数据并行的原理和主流实现方案,使用数据并行加速训练过程中需要注意的问题,以及如何优化数据并行进一步提高训练速度。希望能帮助用户更好的理解和使用数据并行策略。

 什么是数据并行 

在近年来的深度学习模型训练中,使用更多的训练数据和更大的模型趋势未改。更大的模型和数据量意味着更多的计算量和存储需求,也意味着更久的训练时间。那么如何将计算和存储需求分布到多个训练设备来提升训练速度,是关键问题。

数据并行(data parallelism)是解决上述问题的的一种并行策略,其主要逻辑遵循Single Program Multiple Data的原则,即在数据并行的模型训练中,训练任务被切分到多个进程(设备)上,每个进程维护相同的模型参数和相同的计算任务,但是处理不同的数据(batch data)。通过这种方式,同一全局数据(global batch)下的数据和计算被切分到了不同的进程,从而减轻了单个设备上的计算和存储压力。
*Single Program Multiple Data:https://en.wikipedia.org/wiki/SPMD

在深度学习模型训练中,数据并行可作为通过增加并行训练设备来提高训练吞吐量(global batch size per second) 的方法。以常见的ResNet50 模型使用32GB V100卡训练为例。假设训练时单卡最大能支持的local batch size为256,训练一个step的耗时为1秒。则单卡训练时的吞吐为256 imgs/s。

如果我们使用32张V100做数据并行训练,假设没有损耗,那么理论上的训练吞吐可达到32 x 256 = 8192 imgs/。实际上由于数据并行时多机多卡的通信消耗等,实际加速效率会有折扣,但在加速效率为0.8时,训练吞吐也可达到32 x 256 x 0.8 = 6554 imgs/s。如果使用更多的GPU,并行训练的速度将会更高,大大减少训练需要的时间。

深度学习训练中数据并行的实现方式可以有多种,下文介绍的数据并行是基于Distributed Synchronous SGD的梯度同步数据并行,这是目前主流深度学习训练框架中数据并行的实现方式。此外,还会介绍数据并行实现所需要注意的问题以及如何优化来让数据并行实现更高的加速比,提升训练速度。
*Distributed Synchronous SGD:https://arxiv.org/pdf/1602.06709.pdf

在飞桨框架中进行数据并行训练的示例可以参考飞桨数据并行接口文档。
*飞桨数据并行接口文档:DataParallel-API文档-PaddlePaddle深度学习平台

 数据并行的过程 

相比其它的并行模式,数据并行的实现过程比较简单,关键是实现Single Program Multiple Data并行模式中的要求:

  • Single Program: 在深度学习训练中single program可以理解为每个进程上模型的组网和参数相同。
  • Multiple Data: 在深度学习训练中为每个进程上模型处理不同mini-batch的数据。

2.1输入数据切分
第二个条件 —— 输入数据切分实现上比较简单,一般有两种常用的实现方式:
方式一:在每个训练Epoch开始前,将整个训练数据集根据并行进程数划分,每个进程只读取自身切分的数据。
方式二: 数据的读取仅由具体某个进程负责(假设为rank0)。rank0在数据读取后同样根据并行进程数将数据切分成多块,再将不同数据块发送到对应进程上。

方式一相对方式二不需要进行数据通信,训练效率更高,飞桨框架中默认的数据并行使用方式一完成数据在不同进程上的切分。

2.2模型参数同步
数据并行实现的关键问题在于如何保证训练过程中每个进程上模型的参数相同。
因为训练过程的每一个step 都会更新模型参数,每个进程处理不同的数据会得到不同的Loss。由Loss计算反向梯度并更新模型参数后,如何保证进程间模型参数正确同步,是数据并行需要解决的最主要问题。根据下面中的梯度更新公式,只要保证以下两点就能解决这个问题:

保证每个进程模型参数初始相同有两种常用的实现方法:
方法一:所有进程在参数初始时使用相同的随机种子并以相同的顺序初始化所有参数。

方法二:通过个具体进程初始化全部模型参数,之后由该进程向其他所有进程广播模型参数。

基于上述任意一种方法使每个进程得到一份相同的模型初始化参数后,梯度同步的数据并行训练就可以进一步拆解为如下三个部分:

2.2.1 前向计算
每个进程根据自身得到的输入数据独立前向计算,因为输入数据不同每个进程会得到不同的Loss。

2.2.2 反向计算
每个进程根据自身的前向计算独立进行反向计算,因为每个进程上的Loss不同,每个进程上在反向中会计算出不同的梯度。这时一个关键的操作是要在后续的更新步骤之前,对所有进程上的梯度进行同步,保证后续更新步骤中每个进程使用相同的全局梯度更新模型参数。

这一个梯度同步过程是用一个Allreduce sum同步通信操作实现的,对梯度使用Allreduce sum操作后每个进程上得到的梯度是相同的,这时候的梯度值等于所有进程上梯度对应位置相加的和,然后每个进程用Allreduce后的梯度和除以数据并行中的进程数,这样得到的梯度是同步之前所有进程上梯度的平均值。如下图所示。

2.2.3 参数更新
每个进程经过上述步骤后得到相同全局梯度,然后各自独立地完成参数更新。因为更新前模型各进程间的参数是相同的,更新中所使用的梯度也是相同的,所以更新后各进程上的参数也是相同的。

上述是主流框架中数据并行的实现过程。和单卡训练相比,最主要的区别在于反向计算中的梯度需要在所有进程中进行同步,保证每个进程上最终得到的是所有进程上梯度的平均值。

 数据并行训练中的注意问题 

3.1 SyncBatchNorm
前面提到,一般情况下各进程前向计算是独立的,不涉及同步问题。但使用批归一化(Batch Normalization)技术的场景下有新的挑战。

批归一化通过对输入tensor 在batch size 维度做归一化来提升训练过程的数值稳定性。但是数据并行训练中global batch size 被切分到不同的进程之上,每个进程上只有部分的输入数据,这样批归一化在计算输入tensor batch维度的平均值(Mean)和方差(Variance) 时仅使用了部分的batch而非global batch,会导致部分对batch size 比较敏感的模型(e.g. 图像分割)的精度下降。

这类模型在数据并行训练中可以使用SyncBatchNorm策略来保证模型精度,该策略在模型训练前向BN层计算mean和variance时加入额外的同步通信,使用所有数据并行进程上的tensors而非自身进程上的tensor来计算tensor batch维度的mean和variance。具体过程如下图所示:

  1. 每个进程根据自己部分的数据计算batch维度上的local sum和local square sum值。
  2. 在所有卡间同步得到global sum和global square sum。
  3. 使用global sum和 global square sum计算global mean和global standard deviation。
  4. 最后使用global的mean和standard deviation对batch data进行归一化。

像语言类模型中主要使用的Layer Normalization,是在单个数据而非批数据的维度输入tensor 计算mean 和 variance,数据并行并不会影响其计算逻辑,不需要像Batch Normalization 一样做专门的调整。

3.2 数据切分均匀
目前主流训练框架数据并行训练中使用Allreduce同步通信操作来实现所有进程间梯度的同步,这要求数据在各进程间的切分要做到尽量均匀,这个问题看起来很简单,但在实际实现中也要特别注意以下两点:

1.要求所有进程每个训练step 输入的local batch size 大小相同。这是因为模型训练时需要的是所有样本对应梯度的全局平均值。如果每个进程的local batch size不相同,在计算梯度平均值时,除了要在所有进程间使用Allreduce同步梯度,还需要要同步每个进程上local batch size。

当限制所有进程上的local batch size相同时,各进程可以先在本地计算本进程上梯度的local平均值,然后对梯度在所有进程间做Allreduce sum同步,同步后的梯度除以进程数得到的值就是梯度的全局平均值。这样实现可以减少对local batch size同步的需求,提升训练速度。

2.要保证所有进程上分配到相同的batch 数量。因为Allreduce是同步通信操作,需要所有进程同时开始并同时结束一次通信过程。当有的进程的batch数量少于其它进程时,该进程会因为没有新的数据batch 而停止训练,但其他进程会继续进行下一batch的训练;当进入下一batch训练的进程执行到第一个Allreduce通信操作时,会一直等待其他所有进程到达第一个Allreduce一起完成通信操作。

但因为缺少batch的进程,已经停止训练不会执行这次allreduce操作,导致其它进程将会一直等待,呈现挂死态。数据并行中batch数量在进程的均匀切分通常是由data loader来保障的,如果训练数据集样本数无法整除数据并行进程数,那么有一种策略是部分拿到多余样本的进程可以通过抛弃最后一个batch来保证所有进程batch数量的一致。

 数据并行的优化技巧 

4.1 通信融合(Fuse Allreduce)
从上文我们知道数据并行中需要同步每一个模型梯度,这是通过进程间的Allreduce 通信实现的。如果一个模型有非常多的参数,则数据并行训练的每一个step 中会有非常多次的Allreduce 通信。

通信的耗时可以从通信延迟(lantency)和数据传输时间消耗两方面考虑。单次通信延迟时间相对固定,而传输时间由通信的数据量和带宽决定。减少总的通信消耗,可以通过减少通信频率来实现,通信融合是一个可行的手段,通过将N个梯度的Allreduce 通信合并成一次Allreduce 通信,可以减少N-1 次通信延迟时间。

常用的Allreduce 融合实现方式是在通信前将多个梯度tensors 拼接成一个内存地址连续的大tensor,梯度同步时仅对拼接后的大tensor 做一次Allreduce 操作。参数更新时将大tensor切分还原回之前的多个小tensors, 完成每个梯度对应参数的更新。

4.2 通信计算重叠(Overlapping)
除了降低绝对的通信耗时,还可以从降低整体训练耗时角度来优化,可以考虑通信和计算的异步流水实现。数据并行中的梯度同步Allreduce通信是在训练的反向过程中进行的,而Allreduce 后得到的同步梯度是在训练的更新过程中才被使用,在反向中并没有被使用。也就是说上一个梯度的通信和下一个梯度的计算间并没有依赖,通信和计算可以并行,让两者的耗时相互重叠掩盖,减少反向的耗时。

通信和计算的重叠通常是将通信和计算算子调度到不同的流(stream)上实现的。通信算子调度到通信流,计算算子调度到计算流,同一个流上的算子间是顺序执行的,不同流上的算子可以并行执行,从而实现反向中梯度通信和计算的并行重叠。需要注意的是,当通信和计算被调度在不同的流上执行时,需要考虑两个流之间依赖和同步关系。

在梯度同步的数据并行场景中,开发者需要需要通过stream间的同步功能保证:

  • 某个梯度Allreduce通信进行前,该梯度的反向计算已经完成。
  • 某个梯度对应参数的更新计算开始前,该梯度的Allreduce 通信已经完成。

以上两个方法是数据并行中常用的减少通信时间消耗,提高并行加速比的优化策略。如果能做到通信和计算的重叠程度越高,那么数据并行的加速比越接近100%,多卡并行对训练吞吐提升的效率也就越高。

 总结与结论 

本文介绍了深度学习训练中的数据并行,介绍了基于distributed synchronous SGD 的梯度同步数据并行实现方式和训练前向、反向、更新的过程;另外还介绍了使用数据并行中批归一化结合使用时需要注意的问题和常用的数据并行训练速度优化技巧。这些都是工程上实现数据并行时需要考虑的主要问题,希望能帮助读者在工程实现角度更进一步理解数据并行。

但是在另一方面,数据并行在增大训练的global batch size 后,虽然增加了模型的训练吞吐,但模型的收敛可能会受到影响。这是数据并行在算法层面需要解决的大batch size 收敛问题。针对这类算法问题,感兴趣的读者可以参考LARS 和 LAMB 等 layer-wise-lr-adaptive 优化算法。

 百度AI开发者社区百度AI开发者社区 ,为全国各地开发者提供一个交流、分享、答疑解惑的平台,让开发者在研发路上不再“孤军奋战”,通过不断地交流与探讨找出更好的技术解决方案。如果你想尝试各种人工智能技术、开拓应用场景,赶快加入百度AI社区,你对 AI 的所有畅想,在这里都可以实现!

corr2018|horovod:fastandeasydistributeddeeplearningintensorflow(代码片段)

...改少量代码就可以实现多GPU训练。TensorFlow中提供了一些分布式训练的API,这些API适用于不同的环境。这就导致用户往往不知道如何更改代码以进行分布式训练,而且debug也很困难。再者,TensorFlow的分布式训练性能与理想的性能... 查看详情

深度学习-数据加载优化-训练速度提升一倍(代码片段)

1,介绍数据加载深度学习的训练,简单的说就是将数据切分成batch,丢入模型中,并计算loss训练。其中比较重要的一环是数据打batch部分(数据加载部分)。训练时间优化:深度学习训练往往需要大量... 查看详情

分布式机器学习系统笔记——模型并行,数据并行,参数平均,asgd

欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld。技术交流QQ群:433250724,欢迎对算法、技术、应用感兴趣的同学加入。文章索引::”机器学习方法“,”深度学习方法”,“三十分钟理解”原... 查看详情

数据与模型并行

...器学习算法更好地从大数据中训练出性能优良的大模型是分布式机器学习的目标。为了实现这个目标,一般需要根据硬件资源与数据/模型规模的匹配情况,考虑到计算任务、训练数据和模型进行划分,分布式存储、分布式训练... 查看详情

喜马拉雅基于hybridbackend的深度学习模型训练优化实践

...,我们发现计算资源利用不足主要来自于稀疏数据访问和分布式训练两方面:稀疏数据访问:我们使用经典机器学习中常用的libsvm数据格式来 查看详情

机器学习——提升方法adaboost算法,推导过程

...器,构成一个强分类器。大多数的提升方法都是改变训练数据集的概率分布(训练数据的权值分布),针对不同的训练数据分布调用弱学习算法学习一系列弱分类器。  这样,对于提 查看详情

深度学习-数据加载优化-训练速度提升一倍(代码片段)

1,介绍数据加载深度学习的训练,简单的说就是将数据切分成batch,丢入模型中,并计算loss训练。其中比较重要的一环是数据打batch部分(数据加载部分)。训练时间优化:深度学习训练往往需要大量... 查看详情

ctr预估中,可以有哪些深度模型,深度方法?

...据量显著上升,目前工业界的大多数场景都需要使用分布式的方式进行模型训练。今天来跟大家聊聊Tensorflow、Pytorch分布式训练的底层实现逻辑。有的算法同学可能会想,我只要深入研究模型就可以了,为什么还要了... 查看详情

####好好好###图神经网络系统介绍与总结分析

...网络的能力,并且现有框架一般采用数据/模型并行来分布式训练深度神经网络,这种并行计算方法难以直接应用于图神经网络,因 查看详情

中公的深度学习培训怎么样?有人了解吗?

...GAN的训练过程GAN用于图片生成的实现第五阶段深度学习的分布式处理及项目实战多GPU并行实现分布式并行的环境搭建分布式并行实现第六阶段深度强化学习及项目实战强化学习介绍智能体Agent的深度决策机制(上)智能体Agent的... 查看详情

深度学习基础:6.batchnormalization简介/作用(代码片段)

数据标准化由于BatchNormalization包含数据标准化的操作,因此在了解BN前,首先要对数据标准化有个简单认识。数据标准化通常包括两种:0-1标准化和Z-score标准化,深度学习中的标准化往往指代的是后者。0-1标准化0... 查看详情

tensorflow中使用batchnormalization(代码片段)

...pout,后来SergeyIoffe等人提出BatchNormalization方法,可以防止数据分布的变化,影响神经网络需要重新学习分布带来的影响,会降低学习速率,训练时间等问题。提出使用batchnormalization方法,使输入数据分布规律保持一致。实验证明... 查看详情

深度学习中的分布式训练

1.为什么需要分布式训练随着人工智能与深度学习的发展,大规模和超大规模的模型越来越受到业界的推崇。以NLP行业为例,从最开始的Bert-base只有1亿左右的参数量,到千亿级别的GPT-3,再到今年6月发布的目前全球最大预训练模... 查看详情

gpu—分布式训练

目录文章目录目录分布式训练的挑战算法挑战工程挑战NCCLMPI分布式训练的挑战算法挑战数据并行或模型并行同步或异步批量较大,影响模型精度热身,调整学习速率(线性上升,LARC/LARS)给渐变添加噪声优化器的选择(SGD,Momen... 查看详情

分布式机器学习——模型并行训练

首先还是来介绍一下分布式系统中的并行方式,分为数据并行和模型并行,其实还有一种并行方式:Pipeline并行。Pipeline并行方式有的时候会单独存在,有的时候又归为模型并行。这篇文章重点就介绍一下模型并行... 查看详情

深度学习的并行化策略

...用于例如TensorFlow、PyTorch或MXNet。培训据我所知,在大型数据集上训练大型神经网络时,至 查看详情

深度学习tensorflow如何使用多gpu并行模式?

...的训练过程,但要利用更多的GPU或者机器,需要了解如何并行化地训练深度学习模型。常用的并行化深度学习模型训练方式有两种:同步模式和异步模式。下面将介绍这两种模式的工作方式及其优劣。如下图,深度学习模型的训... 查看详情

提升算法

...组合弱分类器构成强分类器。大多数提升法都是改变训练数据的概率分布(训练数据的权值分布),针对不同的训练数据分布调用弱学习算法学习一系列弱分类器。关于AdaBoost的做法是,1、提高前一轮弱分类器错误分类样本的权... 查看详情