分布式训练策略

1.模型并行


所谓模型并行指的是将模型部署到很多设备上(设备可能分布在不同机器上,下同)运行,比如多个机器的GPUs。当神经网络模型很大时,由于显存限制,它是难以在跑在单个GPU上,这个时候就需要模型并行。比如Google的神经机器翻译系统,其可能采用深度LSTM模型,如下图所示,此时模型的不同部分需要分散到许多设备上进行并行训练。深度学习模型一般包含很多层,如果要采用模型并行策略,一般需要将不同的层运行在不同的设备上,但是实际上层与层之间的运行是存在约束的:前向运算时,后面的层需要等待前面层的输出作为输入,而在反向传播时,前面的层又要受限于后面层的计算结果。所以除非模型本身很大,一般不会采用模型并行,因为模型层与层之间存在串行逻辑。但是如果模型本身存在一些可以并行的单元,那么也是可以利用模型并行来提升训练速度,比如GoogLeNet的Inception模块。




 

2.数据并行


深度学习模型最常采用的分布式训练策略是数据并行,因为训练费时的一个重要原因是训练数据量很大。数据并行就是在很多设备上放置相同的模型,并且各个设备采用不同的训练样本对模型训练。训练深度学习模型常采用的是batch
SGD方法,采用数据并行,可以每个设备都训练不同的batch,然后收集这些梯度用于模型参数更新。前面所说的Facebook训练Resnet50就是采用数据并行策略,使用256个GPUs,每个GPU读取32个图片进行训练,如下图所示,这样相当于采用非常大的batch(256
× 32 = 8192)来训练模型。




数据并行可以是同步的(synchronous),也可以是异步的(asynchronous)。所谓同步指的是所有的设备都是采用相同的模型参数来训练,等待所有设备的mini-batch训练完成后,收集它们的梯度然后取均值,然后执行模型的一次参数更新。这相当于通过聚合很多设备上的mini-batch形成一个很大的batch来训练模型,Facebook就是这样做的,但是他们发现当batch大小增加时,同时线性增加学习速率会取得不错的效果。同步训练看起来很不错,但是实际上需要各个设备的计算能力要均衡,而且要求集群的通信也要均衡,类似于木桶效应,一个拖油瓶会严重拖慢训练进度,所以同步训练方式相对来说训练速度会慢一些。异步训练中,各个设备完成一个mini-batch训练之后,不需要等待其它节点,直接去更新模型的参数,这样总体会训练速度会快很多。但是异步训练的一个很严重的问题是梯度失效问题(stale
gradients),刚开始所有设备采用相同的参数来训练,但是异步情况下,某个设备完成一步训练后,可能发现模型参数其实已经被其它设备更新过了,此时这个梯度就过期了,因为现在的模型参数和训练前采用的参数是不一样的。由于梯度失效问题,异步训练虽然速度快,但是可能陷入次优解(sub-optimal
training performance)。

异步训练和同步训练在TensorFlow中不同点如下图所示:



 

 

为了解决异步训练出现的梯度失效问题,微软提出了一种Asynchronous Stochastic Gradient
Descent方法,主要是通过梯度补偿来提升训练效果。应该还有其他类似的研究,感兴趣的可以深入了解一下。

 

分布式训练系统架构

系统架构层包括两种架构:

Parameter Server Architecture(就是常见的PS架构,参数服务器)

Ring-allreduce Architecture

1.Parameter server架构

在Parameter server架构(PS架构)中,集群中的节点被分为两类:parameter server和worker。其中parameter
server存放模型的参数,而worker负责计算参数的梯度。在每个迭代过程,worker从parameter
sever中获得参数,然后将计算的梯度返回给parameter server,parameter
server聚合从worker传回的梯度,然后更新参数,并将新的参数广播给worker。

 

PS架构是深度学习最常采用的分布式训练架构。采用同步SGD方式的PS架构如下图所示:



 

 

2.Ring-allreduce架构


在Ring-allreduce架构中,各个设备都是worker,并且形成一个环,如下图所示,没有中心节点来聚合所有worker计算的梯度。在一个迭代过程,每个worker完成自己的mini-batch训练,计算出梯度,并将梯度传递给环中的下一个worker,同时它也接收从上一个worker的梯度。对于一个包含N个worker的环,各个worker需要收到其它N-1个worker的梯度后就可以更新模型参数。其实这个过程需要两个部分:scatter-reduce和allgather,百度的教程对这个过程给出了详细的图文解释。百度开发了自己的allreduce框架,并将其用在了深度学习的分布式训练中。



 


相比PS架构,Ring-allreduce架构是带宽优化的,因为集群中每个节点的带宽都被充分利用。此外,在深度学习训练过程中,计算梯度采用BP算法,其特点是后面层的梯度先被计算,而前面层的梯度慢于前面层,Ring-allreduce架构可以充分利用这个特点,在前面层梯度计算的同时进行后面层梯度的传递,从而进一步减少训练时间。在百度的实验中,他们发现训练速度基本上线性正比于GPUs数目(worker数)。


一般的多卡gpu训练有一个很大的缺陷,就是因为每次都需要一个gpu(cpu)从其他gpu上收集训练的梯度,然后将新的模型分发到其他gpu上。这样的模型最大的缺陷是gpu
0的通信时间是随着gpu卡数的增长而线性增长的。

所以就有了ring-allreduce,如下图:

 


该算法的基本思想是取消Reducer,让数据在gpu形成的环内流动,整个ring-allreduce的过程分为两大步,第一步是scatter-reduce,第二步是allgather。


先说第一步:首先我们有n块gpu,那么我们把每个gpu上的数据(均等的)划分成n块,并给每个gpu指定它的左右邻居(图中0号gpu的左邻居是4号,右邻居是1号,1号gpu的左邻居是0号,右邻居是2号……),然后开始执行n-1次操作,在第i次操作时,gpu
j会将自己的第(j - i)%n块数据发送给gpu j+1,并接受gpu j-1的(j - i -
1)%n块数据。并将接受来的数据进行reduce操作,示意图如下:



当n-1次操作完成后,ring-allreduce的第一大步scatter-reduce就已经完成了,此时,第i块gpu的第(i + 1) %
n块数据已经收集到了所有n块gpu的第(i + 1) % n块数据,那么,再进行一次allgather就可以完成算法了。

第二步allgather做的事情很简单,就是通过n-1次传递,把第i块gpu的第(i + 1) % n块数据传递给其他gpu,同样也是在i次传递时,gpu
j把自己的第(j - i - 1)%n块数据发送给右邻居,接受左邻居的第(j - i - 2) %
n数据,但是接受来的数据不需要像第一步那样做reduce,而是直接用接受来的数据代替自己的数据就好了。

最后每个gpu的数据就变成了这样: 



 

首先是第一步,scatter-reduce:



然后是allgather的例子: 
 



 

分布式TensorFlow

gRPC (google remote procedure call)

分布式TensorFlow由高性能gRPC库底层技术支持, gRPC首先是一个RPC,即远程过程调用,通俗的解释是:假设你在本机上执行一段代码
num=add(a,b),它调用了一个过程 call,然后返回了一个值num,你感觉这段代码只是在本机上执行的, 但实际情况是,本机上的add
方法是将参数打包发送给服务器,然后服务器运行服务器端的add方法,返回的结果再将数据打包返回给客户端.

 

单机多GPU训练

先简单介绍下单机的多GPU训练,然后再介绍分布式的多机多GPU训练。
单机的多GPU训练, tensorflow的官方已经给了一个cifar的例子,已经有比较详细的代码和文档介绍,
这里大致说下多GPU的过程,以便方便引入到多机多GPU的介绍。
单机多GPU的训练过程:

*
假设你的机器上有3个GPU;

*
在单机单GPU的训练中,数据是一个batch一个batch的训练。 在单机多GPU中,数据一次处理3个batch(假设是3个GPU训练),
每个GPU处理一个batch的数据计算。

*
变量,或者说参数,保存在CPU上

*
刚开始的时候数据由CPU分发给3个GPU, 在GPU上完成了计算,得到每个batch要更新的梯度。

*
然后在CPU上收集完了3个GPU上的要更新的梯度, 计算一下平均梯度,然后更新参数。

*
然后继续循环这个过程。

通过这个过程,处理的速度取决于最慢的那个GPU的速度。如果3个GPU的处理速度差不多的话,
处理速度就相当于单机单GPU的速度的3倍减去数据在CPU和GPU之间传输的开销,实际的效率提升看CPU和GPU之间数据的速度和处理数据的大小。


Cluster Job Task

Cluster是Job的集合,    Job是Task的集合. 

为什么要分成Cluster Job和Task

首先,我们介绍一下Task:Task就是主机上的一个进程,在大多数情况下,一个机器上只运行一个Task.

为什么Job是Task的集合呢? 在分布式深度学习框架中,我们一般把Job划分为Parameter和Worker,Parameter Job
是管理参数的存储和更新工作.Worker Job是来运行ops.如果参数的数量太大,一台机器处理不了,这就要需要多个Tasks.

Cluster 是 Jobs 的集合: Cluster(集群),就是我们用的集群系统了

参数服务器


当计算模型越来越大,模型的参数越来越多,多到模型参数的更新,一台机器的性能都不够时,我们需要将参数分开到不同的机器去存储和更新。参数服务器可以是多台机器组成的集群,类似于分布式的存储结构。主要用来解决参数存储和更新的性能问题。

in-graph模式


In-graph模式和单机多GPU模型有点类似。in-graph模式下数据分发在一个节点上。这种方式配置简单,其他结算节点只需join操作,暴露一个网络接口,等在那里接受任务就好。但坏处就是训练数据的分发在一个节点上,要把训练数据分到不同的机器上,严重影响了并发的训练速度。

In-graph模式, 把计算已经从单机多GPU,已经扩展到了多机多GPU了, 不过数据分发还是在一个节点。 这样的好处是配置简单,
其他多机多GPU的计算节点,只要起个join操作, 暴露一个网络接口,等在那里接受任务就好了。
这些计算节点暴露出来的网络接口,使用起来就跟本机的一个GPU的使用一样, 只要在操作的时候指定tf.device("/job:worker/task:N"),
就可以向指定GPU一样,把操作指定到一个计算节点上计算,使用起来和多GPU的类似。 但是这样的坏处是训练数据的分发依然在一个节点上,
要把训练数据分发到不同的机器上, 严重影响并发训练速度。在大数据训练的情况下, 不推荐使用这种模式。

 

between-graph模式


between-graph模式下,训练的参数保存在参数服务器,数据不用分发,数据分片的保存在各个计算节点,各个计算节点自己算自己的,算完后把要更新的参数告诉参数服务器,参数服务器更新参数。这种模式的优点是不用进行训练数据的分发,尤其数据量在TB级的时候,节省了大量的时间,所以大数据深度学习推荐使用between-graph模式。

 

同步更新和异步更新

in-graph和between-graph模式都支持同步更新和异步更新。


在同步更新的时候,每次梯度更新,要等所有分发的数据计算完成,返回结果,把梯度累加算了均值之后,再更新参数。这样的好处是loss的下降比较稳定,但这个的坏处也比较明显,处理的速度取决于最慢的那个分片的计算时间。


在异步更新时,所有的计算节点,自己算自己的,更新参数也是自己更新自己的计算结果,这样的优点是计算速度快,计算资源能得到充分利用,但是缺点是loss的下降不稳定,抖动大。

在数据量小的情况下,各个节点的计算能力比较均衡的情况下,推荐使用同步模式;数据量很大,各个机器的计算性能参差不齐的情况下,推荐使用异步的方式。

 

Horovod

Horovod 是 Uber 开源的又一个深度学习工具 <https://github.com/uber/horovod>,它的发展吸取了
Facebook「一小时训练 ImageNet 论文」与百度 Ring Allreduce
的优点,可为用户实现分布式训练提供帮助。本文将简要介绍这一框架的特性。

随着 Uber 在 TensorFlow 上训练越来越多的机器学习模型,项目的数据和计算能力需求正在急剧增加。在大部分情况下,模型是可以在单个或多 GPU
平台的服务器上运行的,但随着数据集的增大和训练时间的增长,有些时候训练需要一周甚至更长时间。因此,Uber 的工程师们不得不寻求分布式训练的方法。

Uber 开始尝试部署标准分布式 TensorFlow
技术,在试验了一些方法之后,开发者意识到原有方法需要进行一些调整:首先,在遵循文档和代码示例之后,我们并不总是清楚哪些功能对应着哪些模型训练代码的分布式计算。标准分布式
TensorFlow 引入了很多新的概念:工作线程、参数服务器、tf.Server()、tf.ClusterSpec()、
tf.train.SyncReplicasOptimizer() 以及 tf.train.replicas_device_setter()
等等。它们在某些情况下能起到优化作用,但也让我们难以诊断拖慢训练速度的 bug。

第二个问题有关 Uber 规模的计算性能。在进行了一些基准测试之后,我们发现标准的分布式 TensorFlow 机制无法满足需求。例如,在使用 128 个
GPU 进行训练时,我们因为低效率损失了一半的计算资源。

 

 


链接
https://www.jianshu.com/p/9c462bbb6628
https://www.jianshu.com/p/bf17ac9e6357
 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信