本文首先介绍了分布式计算的基本概念,以及分布式计算如何用于深度学习。然后,列举了配置处理分布式应用的环境的标准需求。最后,本文从理论角度和实现的角度演示了一个用于训练深度学习模型的分布式算法。

详细来讲,本文首要介绍了分布式核算的根本概念,以及分布式核算怎么用于深度学习。然后,列举了装备处理分布式运用的环境的规范需求(硬件和软件)。***,为了供给亲自实践的经历,本文从理论视点和完结的视点演示了一个用于练习深度学习模型的分布式算法(同步随机梯度下降,synchronous SGD)。

深度学习 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练)  分布式 PyTorch GPU 第1张

何为分布式核算

分布式核算指的是一种编写程序的方法,它运用网络中多个衔接的不同组件。一般,大规划核算经过以这种方法安置核算机来完结,这些核算机可以并行地处理高密度的数值运算。在分布式核算的术语中,这些核算机一般被称为节点(node),这些节点的调集便是集群。这些节点一般是经过以太网衔接的,可是其他的高带宽网络也可以运用分布式架构的优势。

深度学习怎么从分布式核算中获益?

作为深度学习的主力,神经网络出现在文献中已经有一段时刻了,可是直到最近,才有人彻底运用它的潜力。神经网络异军突起的首要原因之一便是巨大的算力,这正是咱们在本文中要写的内容。深度学习需求根据很多数据练习深度神经网络,它包括很多的参数。分布式核算是可以充分运用现代硬件的***东西。下面是它的中心思维:

精心设计的分布式算法可以做到:

  • 为了衔接处理,在多个节点上「分配」核算(深度学习模型中的前向传达和反向传达)和数据。
  • 为了完结一致性,它可以在多个节点上树立一种有用的「同步」。

MPI:分布式核算规范

你还有必要习气另一个术语——音讯传递接口(MPI)。MPI 几乎是一切分布式核算的主力。MPI 是一个敞开规范,它界说了一系列关于节点相互通讯的规矩,MPI 也是一个编程模型/API。MPI 不是一款软件或许东西,它是一种规范。

1991 年夏天,一批来自学术界和产业界的安排和个人聚在一同,终究创立了 MPI 论坛(MPI Forum)。该论坛达成了一个雪中送炭,为一个库起草了语法和语义规范,为不同硬件供给商提出可移植/灵敏/优化的完结供给辅导。多家硬件供给商都有自己的 MPI 完结——OpenMPI、MPICH、MVAPICH、Intel MPI 等。

在这份教程中,咱们将会运用 Intel MPI,由于它十分高效,并且也针对 Intel 渠道做了优化。原始的 Intel MPI 是一个 C 鼓动库,并且等级十分低。

装备

对分布式体系而言,适宜的装备是十分重要的。假如没有适宜的硬件和网络安置,即便你对它的编程模型有着概念上的了解,也是没多大用的。下面是需求做的要害安置:

  • 一般需求由一系列经过通用网络互联构成集群的节点。引荐运用高端服务器作为节点,以及高带宽的网络,例如 InfiniBand。
  • 集群中的一切节点都需求具有彻底相同用户名的 Linux 体系。
  • 节点之间有必要具有无暗码 SSH 衔接,这对无缝衔接至关重要。
  • 有必要装置一种 MPI 完结。本文只聚集于 Intel MPI。
  • 需求一个一同的文件体系,它对一切的节点都是可见的,并且分布式运用有必要驻留在上面。网络文件体系(NFS,Network Filesystem)是完结此意图一种方法。

并行战略的类型

并行深度学习模型有两种盛行的方法:

  • 模型并行
  • 数据并行

1. 模型并行

模型并行指的是一个模型从逻辑上被分红了几个部分(例如,一些层在一部分,其他层在另一部分),然后把它们布置在不同的硬件/设备上。

虽然从履行时刻上来看,将模型的不同部分布置在不同设备上的确有优点,可是它一般是出于防止内存约束才运用。具有特别多参数的模型会获益于这种并行战略,由于这类模型需求很高的内存占用,很难适应到单个体系。

2. 数据并行

另一方面,数据并行指的是,经过坐落不同硬件/设备上的同一个网络的多个副原本处理数据的不同批(batch)。不同于模型并行,每个副本或许是整个网络,而不仅仅是一部分。

正如你或许猜到的,这种战略跟着数据的间谍可以很好地扩展。可是,由于整个网络有必要布置在一个设备上,因而或许无法协助到具有高内存占用的模型。下图应该可以说清楚这个问题。

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第2张

模型并行 VS 数据并行

实际上,在大安排里,为了履行出产质量的深度学习练习算法,数据并行愈加盛行也愈加常用。所以,本教程首要介绍数据并行。

torch.distributed API

PyTorch供给了一个十分大名并且易于运用的 API,作为用 C 鼓动写的底层 MPI 库的接口。PyTorch 需求从源码编译,并且有必要与装置在体系中的 Intel MPI 进行链接。咱们现在就看一下 torch.distributed 的根本用法,以及怎么履行它。

  1. #filename'ptdist.py'
  2. importtorch
  3. importtorch.distributedasdist
  4. defmain(rank,world):
  5. ifrank==0:
  6. x=torch.tensor([1.,-1.])#Tensorofinterest
  7. dist.send(x,dst=1)
  8. print('Rank-0hassentthefollowingtensortoRank-1')
  9. print(x)
  10. else:
  11. z=torch.tensor([0.,0.])#Aholderforrecievingthetensor
  12. dist.recv(z,src=0)
  13. print('Rank-1hasrecievedthefollowingtensorfromRank-0')
  14. print(z)
  15. if__name__=='__main__':
  16. dist.init_process_group(backend='mpi')
  17. main(dist.get_rank(),dist.get_world_size())

点对点通讯

用 mpiexec 履行上面的代码,可以得到一个分布式进程调度器,根据任何规范 MPI 完结都可以,成果如下:

  1. cluster@miriad2a:~/nfs$mpiexec-n2-ppn1-hostsmiriad2a,miriad2bpythonptdist.py
  2. Rank-0hassentthefollowingtensortoRank-1
  3. tensor([1.,-1.])
  4. Rank-1hasrecievedthefollowingtensorfromRank-0
  5. tensor([1.,-1.])
  • ***行要被履行的是 dist.init_process_group(backend),它根本上设置了参加节点之间的内部通讯通道。它运用了一个参数来指定运用哪个后端(backend)。由于咱们彻底运用 MPI,所以在咱们的比如中 backend='mpi'。也有其他的后端(例如 TCP、Gloo、NCCL)。
  • 需求检索的两个参数——world size 和 rank。World 指的是在特定 mpiexec 调用环境中一切节点的调集(拜见 mpiexec 中的 -hosts flag)。rank 是由 MPI 闻风丧胆时为每一个进程分配的仅有整数。它从 0 开端。它们在 -hosts 中被指定的鸡飞蛋打用于分配数值。所以,在这个比如中,节点「miriad2a」上的进程会被赋值 Rank 0,节点「miriad2b」上的进程会被赋值为 Rank 1.
  • x 是 Rank 0 计划发送到 Rank 1 的张量,经过 dist.send(x, dst=1) 完结。
  • z 是 Rank 1 在接纳到张量之前就创立的东西。咱们需求一个早就创立好的同维度的张量作为接纳传送来的张量的占位符。z 的值终究会被 x 两端。
  • 与 dist.send(..) 相似,危殆接纳的对应函数是 dist.recv(z, src=0),它将张量接纳到 z。

通讯团体

咱们在上一部分看到的是一个「点对点」通讯的比如,在给定的环境中,rank(s) 将数据发送到特定的 rank(s)。虽然这种通讯是有用的,由于它对通讯供给了细粒度的操控,可是还有其他被常常运用的规范通讯形式,叫作团体(collectives)。下面介绍了 Synchronous SGD 算法中咱们感兴趣的一个团体——all-reduce 团体。

1. ALL-REDUCE 团体

All-reduce 是一种同步通讯方法,一切的 ranks 都被履行了一个 reduction 运算,并且得到的成果对一切的 ranks 都是可见的。下图介绍了这个思维(将求和作为 reduction 运算)。

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第3张

all-reduce 团体

  1. defmain(rank,world):
  2. ifrank==0:
  3. x=torch.tensor([1.])
  4. elifrank==1:
  5. x=torch.tensor([2.])
  6. elifrank==2:
  7. x=torch.tensor([-3.])
  8. dist.all_reduce(x,op=dist.reduce_op.SUM)
  9. print('Rank{}has{}'.format(rank,x))
  10. if__name__=='__main__':
  11. dist.init_process_group(backend='mpi')
  12. main(dist.get_rank(),dist.get_world_size())

PyTorch 中 all-reduce 团体的根本用法

在 world of 3 环境中发动时,成果如下:

  1. cluster@miriad2a:~/nfs$mpiexec-n3-ppn1-hostsmiriad2a,miriad2b,miriad2cpythonptdist.py
  2. Rank1hastensor([0.])
  3. Rank0hastensor([0.])
  4. Rank2hastensor([0.])
  • if rank == … elif 是咱们在分布式核算中屡次遇到的形式。在这个比如中,它被用来在不同的 rank 上创立张量。
  • 它们一同履行了 all-reduce(可以看见,dist.all_reduce(..) 在 if … elif block 逻辑块的外部),求和 (dist.reduce_op.SUM) 作为 reduction 运算。
  • 将来自每个 rank 的 x 求和,再把得到的求和成果放置在每个 rank 的 x 内。

转向深度学习

假定读者熟知规范的随机梯度下降算法(SGD),该算法常用于练习深度学习模型。咱们现在看到的是 SGD 的一个变体——同步 SGD(synchronous SGD),它运用 all-reduce collective 来进行扩展。咱们先从规范 SGD 的数学公式开端吧。

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第4张

雁足传书 D 是一个样本调集(mini-batch),θ 是一切参数的调集,λ 是学习率,Loss(X, y) 是某个丢失函数在 D 中一切样本上的均值。

同步 SGD 所依靠的中心技巧是将更新规矩中的求和在更小的 (mini)batch 子集上进行切割。D 被切割成 R 个子集 D₁, D₂, . .(引荐每个子集具有相同数量的样本),所以 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第5张将规范的 SGD 更新公式中的求和进行切割,得到:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第6张

现在,由于梯度算子在求和算子上是分布式的,所以咱们得到:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第7张

咱们从中得到了什么?

看一下上面方程中独自的梯度项(方括号里边)。它们现在可以被独登时核算,然后加起来得到原始的梯度,并且没有任何丢失/近似。这便是数据并行。下面是整个进程:

  • 将整个数据集分红 R 个等大的数据块(子集)。这儿的字母 R 代表的是 replica(副本)。
  • 运用 MPI 发动 R 个进程/rank,将每个进程绑定到一个数据块上。
  • 让每个 rank 运用巨细为 B 的 mini-batch(dᵣ)(dᵣ来自该 rank 分配到的数据块 D_r)核算梯度,即 rank r 核算 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第8张
  • 将一切 rank 的梯度进行求和,然后将得到的梯度对每个 rank 可见,再进跋涉一步处理。

***一点便是 all-reduce 算法。所以,每次在一切 rank 运用巨细为 B 的 mini-batch(dᵣ)核算完梯度今后,都有必要履行 all-reduce。需求留意的一点是,将悉数 R 个 rank(运用巨细为 B 的 mini-batch 核算出)的梯度相加之后会得到一个有用的批巨细:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第9张

下面是完结的要害部分(没有展现样板代码):

  1. model=LeNet()
  2. #firstsynchronizationofinitialweights
  3. sync_initial_weights(model,rank,world_size)
  4. optimoptimizer=optim.SGD(model.parameters(),lr=1e-3,momentum=0.85)
  5. model.train()
  6. forepochinrange(1,epochs+1):
  7. fordata,targetintrain_loader:
  8. optimizer.zero_grad()
  9. output=model(data)
  10. loss=F.nll_loss(output,target)
  11. loss.backward()
  12. #Theall-reduceongradients
  13. sync_gradients(model,rank,world_size)
  14. optimizer.step()
  15. defsync_initial_weights(model,rank,world_size):
  16. forparaminmodel.parameters():
  17. ifrank==0:
  18. #Rank0issendingit'sownweight
  19. #toallit'ssiblings(1toworld_size)
  20. forsiblinginrange(1,world_size):
  21. dist.send(param.data,dst=sibling)
  22. else:
  23. #Siblingsmustrecievetheparameters
  24. dist.recv(param.data,src=0)
  25. defsync_gradients(model,rank,world_size):
  26. forparaminmodel.parameters():
  27. dist.all_reduce(param.grad.data,op=dist.reduce_op.SUM)
  • 悉数 R 个 rank 都运用随机权重创立自己的模型副本。
  • 单个具有随机权重的副本或许导致在初始的时分不同步。引荐在一切的副本上同步初始权重,sync_initial_weights(..) 便是在做这件事。让任何一个 rank 将自己的权重发送到它的兄弟 rank,兄弟 rank 有必要接纳这些权重并用来初始化它们本身。
  • 从每个 rank 对应的数据部分取出一个 mini-batch(巨细为 B),核算前向和反向传递(梯度)。作为装备的一部分,这儿需求要点留意的一点是:一切的进程/rank 应该让自己那部分数据可见(一般是在自己的硬盘上或许在同享文件体系中)。
  • 把求和作为 reduction 运算,对每一个副本上的梯度履行 all-reduce 团体。sync_gradients(..) 会完结梯度同步。
  • 梯度同步之后,每个副本可以在自己的权重上独登时履行规范的 SGD 更新。optimizer.step() 正常闻风丧胆。

现在问题来了:咱们怎么确保独立的更新坚持同步?

咱们看一下更新方程的***更新:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第10张

上面的第 2 点和第 4 点确保每个初始权重和梯度都是同步的。明显,它们的线性组合也是同步的(λ 是常数)。今后的一切更新都是相似的逻辑,因而也是同步的。

功能比照

一切分布式算法的***瓶颈便是同步。只有当同步时刻明显小于核算时刻的时分,分布式算法才是打扫的。让咱们在规范 SGD 和同步 SGD 之间做一个简略的比照,来看一下什么时分后者是比较好的。

界说:咱们假定整个数据集的规划为 N。网络处理巨细为 B 的 mini-batch 需求花费时刻 Tcomp。在分布式情况下,all-reduce 同步花费的时刻为 Tsync。

关于非分布式(规范)SGD,每个 epoch 花费的时刻为:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第11张

关于同步 SGD,每个 epoch 花费的时刻为:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第12张

因而,关于分布式环境,为了与非分布式环境比较有明显的优势,咱们需求满意:

 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练) 分布式 PyTorch GPU 深度学习 第13张

咱们可以调整影响上述不等式的三个因子,从分布式算法中得到更多的优点。

  • 经过以高带宽的快速网络衔接节点,来减小 Tsync。
  • 经过间谍批巨细 B,来间谍 Tcomp。
  • 经过衔接更多的节点和具有更多的副原本间谍 R。

本文明晰地介绍了深度学习环境中的分布式核算的中心思维。虽然同步 SGD 很盛行,可是也有其他被频频运用的分布式算法(如异步 SGD 及其变体)。但是,更重要的是可以以并行的方法来考虑深度学习方法。请留意,不是一切的算法都可以开箱即用地并行化,有的需求做一些近似处理,这破坏了原算法给出的理论确保。能否高效处理这些近似,取决于算法的设计者和完结者。

原文地址:

https://medium.com/intel-student-ambassadors/distributed-training-of-deep-learning-models-with-PyTorch-1123fa538848

【本文是51CTO专栏殴伤“机器之心”的原创译文,微信大众号“机器之心( id: almosthuman2014)”】

戳这儿,看该作者更多好文

转载请说明出处
知优网 » 分布式入门,怎样用PyTorch完成多GPU分布式练习(pytorch 多gpu并行训练)

发表评论

您需要后才能发表评论