最基础也是最好理解的大模型训练并行手段就是数据并行。
数据并行的发展史实际上目前看也经历了2个阶段:
- 1. DP Data Parallel
- 2. DDP Distributed Data Parallel
- 这两者特别容易被搞混,下面我们来看一下这两者的区别。
DP是在Pytorch中最早引入的分布式并行手段。
DP的通信和运行方式
DP是线程通信,只用于单机内部的多块GPU之间的通信,不会跨机器节点进行通信。
- 如图所示,DP从流程上看,是将整个minibatch的数据加载到主线上,然后再将更小批次的sub-minibatches的数据分散到整个机器的各块GPU中进行计算。
- 一般来讲DP的主GPU为GPU1,它负责持有模型,并且copy到其他的模型里,而且训练的mini-batch也是先给到GPU1,然后再通过Scatter的通信,将minibatch进一步打散成sub-minibatches,然后不同的ub-minibatches给到不同的GPU来进行训练处理。
- 在前向计算时,每个GPU自己计算自己得这一部分数据,然后GPU1通过gather来手机所有的输出,再进行统一的损失计算。
- 把损失在 GPU 之间 scatter,在各个GPU之上运行后向传播,计算参数梯度。
- 在 GPU1 之上归并梯度,进而更新梯度参数,更新GPU1上的模型权重由于模型参数仅在GPU1上更新,而其他从属GPU此时并不是同步更新的,所以需要将更新后的模型参数复制到剩余的从属 GPU中,以此来实现并行。
DP由于它的通信局限性和低效性,实际上现在正常的项目里,我们 会使用的主要是DDP。
既然DDP是先进生产力的代表,我们看一下它有哪些优势?
DDP的通信和运行方式
首先DDP是进程通信,所以它不必依赖主GPU(比如GPU1)就可以完成很多工作。
- 在加载模型的阶段,不同于DP的由主GPU来进行分发,DDP每个GPU都拥有模型的一个副本,所以不需要拷贝模型。rank为0的进程会将网络初始化参数broadcast到其它每个进程中,确保每个进程中的模型都拥有一样的初始化值,广播的也只是模型的权重而不是模型本身,大大降低了跨节点拷贝的带宽。
- 加载数据阶段。DDP 不需要广播数据,而是使用多进程并行加载数据。在 host 之上,每个GPU的worker进程都会把自己负责的数据从硬盘load到显存。DistributedSampler 保证每个进程加载到的数据是彼此不重叠的。这样就免除了一次Scatter的操作,进一步提升了效率。
- 前向传播阶段。在每个GPU之上运行前向传播,计算输出。每个GPU都执行同样的训练,所以不需要有主 GPU。计算损失,也都是在每个GPU之上独立计算损失。
- 反向传播阶段。运行后向传播来计算梯度,在计算梯度同时也对梯度执行all-reduce操作。
- 更新模型参数阶段。因为每个GPU都从完全相同的模型开始训练,并且梯度被all-reduced,因此每个GPU在反向传播结束时最终得到平均梯度的相同副本,所有GPU上的权重更新都相同,也就不需要模型同步了,又比DP节省了不少的带宽和时间。
综上,我们总结一下DP和DDP几个最重要的区别点:
- 线程和进程的区别。
- DP因为有主GPU的概念所以无法和模型并行技术一起工作,也就只能训练训练小模型了,一张GPU如果无法装载模型梯度Activation就无法用DP了,DDP,没这个限制。
- DP只能在单台机器上使用,DDP可以跨节点。
- DDP不需要用主GPU在每次迭代复制模型给其他的GPU,避免全局解释器锁定。
- 在训练时DP所有的GPU共用一个优化器,DDP阶段每个GPU自己运行优化器。
- DDP在反向求导的过程中,计算梯度的同时完成all-reduce的梯度同步,DP需要先gather所有的信息再broadcast出去。
分布式训练3