共计 5423 个字符,预计需要花费 14 分钟才能阅读完成。
数据并行是大规模深度学习训练中十分成熟和罕用的并行模式。本文将介绍数据并行的原理和支流实现计划,应用数据并行减速训练过程中须要留神的问题,以及如何优化数据并行进一步提高训练速度。心愿能帮忙用户更好的了解和应用数据并行策略。
什么是数据并行
在近年来的深度学习模型训练中,应用更多的训练数据和更大的模型趋势未改。更大的模型和数据量意味着更多的计算量和存储需要,也意味着更久的训练工夫。那么如何将计算和存储需要散布到多个训练设施来晋升训练速度,是关键问题。
数据并行 (data parallelism) 是解决上述问题的的一种并行策略,其次要逻辑遵循 Single Program Multiple Data 的准则,即在数据并行的模型训练中,训练任务被切分到多个过程 (设施) 上, 每个过程保护雷同的模型参数和雷同的计算工作,然而解决不同的数据 (batch data)。通过这种形式,同一全局数据(global batch) 下的数据和计算被切分到了不同的过程,从而加重了单个设施上的计算和存储压力。\
*Single Program Multiple Data:https://en.wikipedia.org/wiki…
在深度学习模型训练中,数据并行可作为通过减少并行训练设施来进步训练吞吐量(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.06…
在飞桨框架中进行数据并行训练的示例能够参考飞桨数据并行接口文档。\
* 飞桨数据并行接口文档:https://www.paddlepaddle.org….
数据并行的过程
相比其它的并行模式,数据并行的实现过程比较简单,要害是实现 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。具体过程如下图所示:
- 每个过程依据本人局部的数据计算 batch 维度上的 local sum 和 local square sum 值。
- 在所有卡间同步失去 global sum 和 global square sum。
- 应用 global sum 和 global square sum 计算 global mean 和 global standard deviation。
- 最初应用 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 开发者社区 https://ai.baidu.com/forum?&h…,为全国各地开发者提供一个交换、分享、答疑解惑的平台,让开发者在研发路上不再“孤军奋战”,通过一直地交换与探讨找出更好的技术解决方案。如果你想尝试各种人工智能技术、开辟利用场景,赶快退出百度 AI 社区,你对 AI 的所有畅想,在这里都能够实现!
扫描下方二维码,增加小助手微信「京东卡、小度定制周边、神秘礼盒、行李箱」等更多福利你来拿~