DP 与 DDP 的优缺点
DP 与 DDP 的优缺点
DP 的优势
nn.DataParallel
没有改变模型的输入输出,因此其他部分的代码不需要做任何更改,非常方便,一行代码即可搞定。
DP 的缺点
DP
进行分布式多卡训练的方式容易造成负载不均衡,第一块 GPU 显存占用更多,因为输出默认都会被 gather 到第一块 GPU 上,也就是后续的 loss 计算只会在cuda:0
上进行,没法并行。
除此之外DP
只能在单机上使用,且DP
是单进程多线程的实现方式,比DDP
多进程多线程的方式会效率低一些。
DDP 的优势
1. 每个进程对应一个独立的训练过程,且只对梯度等少量数据进行信息交换。
DDP
在每次迭代中,每个进程具有自己的 optimizer
,并独立完成所有的优化步骤,进程内与一般的训练无异。
在各进程梯度计算完成之后,各进程需要将梯度进行汇总平均,然后再由 rank=0
的进程,将其 broadcast
到所有进程。之后,各进程用该梯度来独立的更新参数。而 DP
是梯度汇总到主 GPU
,反向传播更新参数,再广播参数给其他的 GPU。
DDP
中由于各进程中的模型,初始参数一致 (初始时刻进行一次 broadcast
),而每次用于更新参数的梯度也一致,因此,各进程的模型参数始终保持一致。
而在DP
中,全程维护一个 optimizer
,对各 GPU
上梯度进行求和,而在主 GPU
进行参数更新,之后再将模型参数 broadcast
到其他 GPU
。
相较于**DP
,DDP
**传输的数据量更少,因此速度更快,效率更高。
2. 每个进程包含独立的解释器和 GIL。
一般使用的 Python
解释器 CPython
:是用 C
语言实现 Pyhon
,是目前应用最广泛的解释器。全局锁使 Python
在多线程效能上表现不佳,全局解释器锁(Global Interpreter Lock
)是 Python
用于同步线程的工具,使得任何时刻仅有一个线程在执行。
由于每个进程拥有独立的解释器和 GIL
,消除了来自单个 Python
进程中的多个执行线程,模型副本或 GPU
的额外解释器开销和 GIL-thrashing
,因此可以减少解释器和 GIL
使用冲突。这对于严重依赖 Python runtime
的 models
而言,比如说包含 RNN
层或大量小组件的 models
而言,这尤为重要。
DDP 的缺点
暂时来说,DDP
是采用多进程多线程的方式,并且训练速度较高,他的缺点主要就是,需要修改比较多的代码,比DP
的一行代码较为繁琐许多。