最近由于有模型训练的任务,老板对已有的单机单卡模型训练的时间不满意,觉得炼丹周期太长,让我用单机多卡来对模型训练进行优化加速。这两天看了点知乎、csdn、stackoverflow上面相关的文章和问题,发现里面的坑还不少。
今天,我就给大家排排坑,介绍一下如何将已有的模型训练转成单机多卡的形式,来进行分布式训练。
1、总分
分布式训练分为这几类:
l按照并行方式来分:模型并行 vs 数据并行
l按照更新方式来分:同步更新 vs 异步更新
l按照分布式训练系统架构来分:Parameter Server Architecture (PS 架构) vs Ring-allreduce Architecture
2、模型并行 vs 数据并行
- 模型并行:不同的GPU输入相同的数据,运行模型的不同部分,比如多层网络的不同层;
- 数据并行:不同的GPU输入不同的数据,运行相同的完整的模型。
如何选择?
当模型非常大,一张GPU已经存不下的时候,可以使用模型并行,把模型的不同部分交给不同的机器负责,但是这样会带来很大的通信开销,而且模型并行各个部分存在一定的依赖,规模伸缩性差。因此,通常一张可以放下一个模型的时候,会采用数据并行的方式,各部分独立,伸缩性好。
3、同步更新 vs 异步更新
对于数据并行来说,由于每个GPU负责一部分数据,那就涉及到如果更新参数的问题,分为同步更新和异步更新两种方式。
同步更新
异步更新
- 同步更新:每次梯度更新,要等所有分发出去的数据计算完成后,返回回来结果之后,把梯度累加算了均值之后,再更新参数。这样的好处是loss的下降比较稳定, 但是这个的坏处也很明显, 处理的速度取决于最慢的那个分片计算的时间。
- 异步更新:所有的计算节点,各自算自己的, 更新参数也是自己更新自己计算的结果, 这样的优点就是计算速度快,计算资源能得到充分利用,但是缺点是loss的下降不稳定,抖动大。
如何选择?
在数据量小的情况下,各个节点的计算能力比较均衡的情况下,推荐使用同步模式。数据量很大,各个机器的计算性能掺差不齐的情况下,推荐使用异步的方式。
4、Parameter Server Architecture vs Ring-allreduce Architecture
Parameter Server Architecture (PS 架构) vs Ring-allreduce Architecture
两种架构的主要区别在于不同架构所采用的参数同步算法不同,所以也可以理解为 Parameter Server算法 vs Ring AllReduce算法的区别。
在Parameter server架构(PS架构)中,集群中的节点被分为两类:parameter server和worker。其中parameter server存放模型的参数,而worker负责计算参数的梯度。在每个迭代过程,worker从parameter sever中获得参数,然后将计算的梯度返回给parameter server,parameter server聚合从worker传回的梯度,然后更新参数,并将新的参数广播给worker。
PS架构是深度学习最常采用的分布式训练架构。采用同步SGD方式的PS架构如下图所示:
在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架构可以充分利用这个特点,在前面层梯度计算的同时进行后面层梯度的传递,从而进一步减少训练时间。
Ring AllReduce分为两个步骤:Scatter Reduce和All Gather。
Scatter Reduce过程:首先,我们将参数分为N份,相邻的GPU传递不同的参数,在传递N-1次之后,可以得到每一份参数的累积(在不同的GPU上)。
Scatter Reduce过程
All Gather:得到每一份参数的累积之后,再做一次传递,同步到所有的GPU上。
All Gather过程
通过Ring Allreduce的方式,基本上可以实现当GPU并行卡数的增加,实现计算性能的线性增长。
根据这两个过程,我们可以计算到All Reduce的通信成本为:可以看到通信成本T与GPU数量无关。
如何选择?
Parameter Service最大的问题就是通信成本和GPU的数量线性相关。而Ring AllReduce的通信成本与GPU数量无关。
至此,简单的分布式训练的一些概念就讲解到这里,后续会结合相关的代码讲解如何搭建分布式训练框架。
参考:Bringing HPC Techniques to Deep Learning