深度学习中的分布式训练

1. 为何须要分布式训练

随着人工智能与深度学习的发展,大规模和超大规模的模型愈来愈受到业界的推崇。以NLP行业为例,从最开始的Bert-base只有1亿左右的参数量,到千亿级别的GPT-3,再到今年6月发布的目前全球最大预训练模型“悟道2.0”,参数规模达到惊人的1.75万亿,整个业界都由一种向更大模型发展的趋势。面对如此庞大的模型,必然也须要庞大的数据量才能进行训练,若是没有分布式训练的大算力加持,一个Epoch可能就要训练到天荒地老。抛开业界淬炼超大模型的场景,对于一个AI行业的普通算法工程师,面对平常的工做,分布式训练也能够大大加速模型的训练、调参的节奏、以及版本的迭代更新,在时间如此珍贵的当下,相信没有工程师会抗拒分布式训练带来的收益。所以,咱们今天就聊聊深度学习中关于分布式训练的那些事儿。 图片1.pnggit

2. 分布式训练策略

分布式训练策略按照并行方式不一样,能够简单的分为数据并行和模型并行两种方式。 图片2.pnggithub

2.1 数据并行

数据并行是指在不一样的GPU上都copy保存一份模型的副本,而后将不一样的数据分配到不一样的GPU上进行计算,最后将全部GPU计算的结果进行合并,从而达到加速模型训练的目的。因为数据并行会涉及到把不一样GPU的计算结果进行合并而后再更新模型,根据跟新方式不一样,又能够分为同步更新和异步更新。在数据并行中,每一个GPU只计算一个batch中的一部分数据,同步更新指的就是在等待全部的GPU都计算完成以后,而后再统一合并和更新网络的权重,并广播到全部的GPU中,随后进行下一轮的计算。而异步跟新不一样,异步更新中每一个GPU在独立计算完成以后,都无需等待其余GPU,能够当即更新总体权重,而后广播到其余GPU中,随后立刻进入下一轮的计算。因而可知,同步更新须要等待全部的GPU都计算完成才能更新,若是集群中某一个GPU训练慢了,或者集群中的通讯出现抖动,都会影响到整个网络的训练速度,相似木桶效应,最短板决定了最大的容量。而异步更新因为不用等待其余GPU节点,所以整体训练速度会快一些,可是会有一个严重的梯度失效的问题。即在异步的状况下,每个节点完成训练以后,都会立刻去更新,这会形成其余节点如今的模型参数和这一轮训练前采用的模型参数可能不一致,从而致使此时的梯度过时。所以,异步更新虽然快,可是因为梯度失效问题,模型每每会陷入到次优解中。 图片3.png算法

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/byteps),该框架没有采用热门的all-reduce,反而采用了PS架构,经过利用额外的CPU资源做为Parameter Server等措施,提高了通讯性能,听说效果能够优于Horovod。而在几天以前,快手联合苏黎世理工也宣布开源了一款分布式训练框架Bagua(八卦),Bagua专门针对分布式场景设计了特定的优化算法,实现了算法和系统层面的联合优化,性能较同类提高60%。感兴趣的同窗也能够关注一下。项目github地址:https://github.com/BaguaSys/bagua工具

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 图片4.png 因为DDP和Horovod都是采用all-reduce架构,所以性能至关,可见Pytorch原生的DDP模式也已经作得很是不错了。而DP相比其余模式性能就会差一些。所以在实际工做中,仍是比较推荐使用DDP或者Horovod进行分布式训练。性能

总结

本文探讨了深度学习中模型并行和数据并行的分布式策略,并基于Pytorch框架介绍了原生的DP和DDP模式,以及第三方Horovod分布式训练框架。从后面的实验对比能够看出,平时工做中比较推荐使用DDP或者Horovod的方式。分布式训练是深度学习中很是重要的一环,除了Horovod,其余各大厂商也相继开源了本身的分布式训练框架,好比BytePS、DeepSpeed、Bagua等等,这些框架的开源也将进一步推进这个领域的发展,为深度学习提供更优秀的工具。

做者简介

Hongyu OPPO高级NLP算法工程师

主要从事NLP、知识图谱及相关领域的工做

获取更多精彩内容,扫码关注[OPPO数智技术]公众号 qrcode_for_gh_7bc48466f080_258.jpg

相关文章
相关标签/搜索