共计 4559 个字符,预计需要花费 12 分钟才能阅读完成。
1. 为什么须要分布式训练
随着人工智能与深度学习的倒退,大规模和超大规模的模型越来越受到业界的推崇。以 NLP 行业为例,从最开始的 Bert-base 只有 1 亿左右的参数量,到千亿级别的 GPT-3,再到往年 6 月公布的目前寰球最大预训练模型“悟道 2.0”,参数规模达到惊人的 1.75 万亿,整个业界都由一种向更大模型倒退的趋势。面对如此宏大的模型,必然也须要宏大的数据量能力进行训练,如果没有分布式训练的大算力加持,一个 Epoch 可能就要训练到天荒地老。抛开业界淬炼超大模型的场景,对于一个 AI 行业的一般算法工程师,面对日常的工作,分布式训练也能够大大减速模型的训练、调参的节奏、以及版本的迭代更新,在工夫如此宝贵的当下,置信没有工程师会抗拒分布式训练带来的收益。因而,咱们明天就聊聊深度学习中对于分布式训练的那些事儿。
2. 分布式训练策略
分布式训练策略依照并行形式不同,能够简略的分为数据并行和模型并行两种形式。
2.1 数据并行
数据并行是指在不同的 GPU 上都 copy 保留一份模型的正本,而后将不同的数据调配到不同的 GPU 上进行计算,最初将所有 GPU 计算的后果进行合并,从而达到减速模型训练的目标。因为数据并行会波及到把不同 GPU 的计算结果进行合并而后再更新模型,依据跟新形式不同,又能够分为同步更新和异步更新。在数据并行中,每个 GPU 只计算一个 batch 中的一部分数据,同步更新指的就是在期待所有的 GPU 都计算实现之后,而后再对立合并和更新网络的权重,并播送到所有的 GPU 中,随后进行下一轮的计算。而异步跟新不同,异步更新中每个 GPU 在独立计算实现之后,都无需期待其余 GPU,能够立刻更新整体权重,而后播送到其余 GPU 中,随后马上进入下一轮的计算。由此可见,同步更新须要期待所有的 GPU 都计算实现能力更新,如果集群中某一个 GPU 训练慢了,或者集群中的通信呈现抖动,都会影响到整个网络的训练速度,相似木桶效应,最短板决定了最大的容量。而异步更新因为不必期待其余 GPU 节点,因而总体训练速度会快一些,然而会有一个重大的梯度生效的问题。即在异步的状况下,每一个节点实现训练之后,都会马上去更新,这会造成其余节点当初的模型参数和这一轮训练前采纳的模型参数可能不统一,从而导致此时的梯度过期。因而,异步更新尽管快,然而因为梯度生效问题,模型往往会陷入到次优解中。
2.2 模型并行
与数据并行不同,分布式训练中的模型并行是指将整个神经网络模型拆解散布到不同的 GPU 中,不同的 GPU 负责计算网络模型中的不同局部。这通常是在网络模型很大很大、单个 GPU 的显存曾经齐全装不下整体网络的状况下才会采纳。因为深度学习的模型通常蕴含很多层,层与层之间的运行有先后训练,前向流传和反向梯度计算的时候,后面的层和前面的层都会彼此依赖作为输入输出,因而这种串行的逻辑对减速造成了肯定的限度。然而相比起来,咱们也算能够通过模型并行的形式把一个超大模型训练起来,不然对于一个单 GPU 的话,超大模型是齐全没方法 work 的。
因而,比照起来,模型并行因为各个 GPU 只加载了模型的一部分网络结构,存在肯定的依赖关系,造成了规模的伸缩性比拟差,不能随便的增减 GPU 的数量,因而在理论中使用的并不多。而数据并行的形式,因为各个 GPU 互相独立,不便 GPU 的扩缩容,同时减速成果好,因而在理论中使用较多,然而在某些时候,咱们也能够同时联合数据并行和模型并行两种形式。
3. 基于 Pytorch 的分布式训练方法
在 Pytorch 中为咱们提供了两种多 GPU 的分布式训练计划:torch.nn.DataParallel(DP)和 torch.nn.parallel.Distributed Data Parallel(DDP)。
3.1 Data Parallel
DP 模式应用起来非常容易,只须要对单 GPU 的代码批改其中一行就能够运行了,因为 DP 模式采纳的是 PS 架构,存在负载不平衡问题,主卡往往会成为训练的瓶颈,因而训练速度会比 DDP 模式慢一些。而且 DP 只反对单机多卡的形式,个别一台机器只能装置最多 8 张卡,当咱们要训练特地大型的工作时,8 卡就会显得特地吃紧,因而会有肯定的限度。
# use DataParallel
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(),"GPUs!")
model = torch.nn.DataParallel(model)
model.to(device)
3.2 DistributedDataParallel
与 DP 模式不同,DDP 模式自身是为多机多卡设计的,当然在单机多卡的状况下也能够应用。DDP 采纳的是 all-reduce 架构,根本解决了 PS 架构中通信老本与 GPU 的数量线性相关的问题。尽管在单机多卡状况下,能够应用 DP 模式,然而应用 DDP 通常会比 DP 模式快一些,因而 DDP 模式也是官网举荐大家应用的形式。革新现有的代码应用 DDP 也十分不便,通过上面几个步骤就能够轻松搞定。
# 1. init backend nccl
torch.distributed.init_process_group(backend='nccl')
# 2. config gpu
local_rank = torch.distributed.get_rank()
torch.cuda.set_device(local_rank)
device = torch.device("cuda", local_rank)
# 3. use DistributedSampler
training_loader = DataLoader(training_set, batch_size=TRAIN_BATCH_SIZE, sampler=DistributedSampler(training_set))
# 4. move model to gpu
model.to(device)
# 5. use DistributedDataParallel
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(),"GPUs!")
model = DistributedDataParallel(model, device_ids=[local_rank], output_device=local_rank)
3.3 Horovod
除了 Pytorch 原生提供的 DP 和 DDP 形式以外,也有很多优良的由第三方提供的分布式训练工具,其中 Horovod 就是比拟罕用的一款。Horovod 是 Uber 开源的跨平台分布式训练框架(horovod 名字来源于俄罗斯一种民间舞蹈,舞者手拉手站成一个圆圈跳舞,类比了 GPU 设施之间的通信模式,如果该框架是中国人或者华人开发的话,我预计可能就叫“锅庄”了吧 ^-^),从名字能够看进去,Horovod 采纳 all-reduce 架构来进步分布式设施的通信效率。同时,Horovod 不仅反对 Pytorch,也反对 TensorFlow 等其余深度学习框架。训练中如果想应用 Horovod 的话,其实对代码的改变也比拟少,如下所示。
import horovod.torch as hvd
# 1. init horovod
hvd.init()
# 2. Pin GPU to be used to process local rank (one GPU per process)
torch.cuda.set_device(hvd.local_rank())
# 3. Partition dataset among workers using DistributedSampler
train_sampler = DistributedSampler(training_set, num_replicas=hvd.size(), rank=hvd.rank())
training_loader = DataLoader(training_set, batch_size=TRAIN_BATCH_SIZE, sampler=train_sampler)
# 4. Add Horovod Distributed Optimizer
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
# 5. Horovod: broadcast parameters from rank 0 to all other processes.
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
另外,字节跳动也开源了一款高性能的分布式深度学习训练框架 BytePS(我的项目 github 地址:https://github.com/bytedance/…),该框架没有采纳热门的 all-reduce,反而采纳了 PS 架构,通过利用额定的 CPU 资源作为 Parameter Server 等措施,晋升了通信性能,据说成果能够优于 Horovod。而在几天之前,快手联结苏黎世理工也发表开源了一款分布式训练框架 Bagua(八卦),Bagua 专门针对分布式场景设计了特定的优化算法,实现了算法和零碎层面的联结优化,性能较同类晋升 60%。感兴趣的同学也能够关注一下。我的项目 github 地址:https://github.com/BaguaSys/b…
4. 试验比照
这里咱们比照了 Pytorch 原生的 DP 和 DDP 模式,同时也抉择了第三方插件 Horovod 进行比照。试验抉择了基于 bert-base 的预训练语言模型进行文本分类的工作。具体试验参数如下:GPU 型号: V100, learning_rate: 2e-5, batch_size: 128, max_len: 128, epochs: 1, train_set_size: 48w
因为 DDP 和 Horovod 都是采纳 all-reduce 架构,因而性能相当,可见 Pytorch 原生的 DDP 模式也曾经做得十分不错了。而 DP 相比其余模式性能就会差一些。因而在理论工作中,还是比拟举荐应用 DDP 或者 Horovod 进行分布式训练。
总结
本文探讨了深度学习中模型并行和数据并行的分布式策略,并基于 Pytorch 框架介绍了原生的 DP 和 DDP 模式,以及第三方 Horovod 分布式训练框架。从前面的试验比照能够看出,平时工作中比拟举荐应用 DDP 或者 Horovod 的形式。分布式训练是深度学习中十分重要的一环,除了 Horovod,其余各大厂商也相继开源了本人的分布式训练框架,比方 BytePS、DeepSpeed、Bagua 等等,这些框架的开源也将进一步推动这个畛域的倒退,为深度学习提供更优良的工具。
作者简介
Hongyu OPPO 高级 NLP 算法工程师
次要从事 NLP、常识图谱及相干畛域的工作
获取更多精彩内容,扫码关注 [OPPO 数智技术] 公众号