并行计算简介
Network partitioning
网络结构分布到不同的设备中(Network partitioning),在刚开始做模型并行的时候,这个方案使用的比较多。其中主要的思路是,将一个模型的各个部分拆分,然后将不同的部分放入到 GPU 来做不同任务的计算。其架构如下:

这里遇到的问题就是,不同模型组件在不同的 GPU 上时,GPU 之间的传输就很重要,对于 GPU 之间的通信是一个考验。但是 GPU 的通信在这种密集任务中很难办到,所以这个方式慢慢淡出了视野。
Layer-wise partitioning
同一层的任务分布到不同数据中(Layer-wise partitioning),第二种方式就是,同一层的模型做一个拆分,让不同的 GPU 去训练同一层模型的部分任务。其架构如下:

这样可以保证在不同组件之间传输的问题,但是在我们需要大量的训练,同步任务加重的情况下,会出现和第一种方式一样的问题。
数据并行Data parallelism
不同的数据分布到不同的设备中,执行相同的任务(Data parallelism),第三种方式有点不一样,它的逻辑是,我不再拆分模型,我训练的时候模型都是一整个模型。但是我将输入的数据拆分。所谓的拆分数据就是,同一个模型在不同 GPU 中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出的数据做一个汇总,然后再反传。因为求导以及加和都是线性的,数据并行在数学上也有效。
假设我们一个 batch 有
架构如下:

这种方式可以解决之前模式遇到的通讯问题。现在的主流方式是数据并行的方式(Data parallelism)。
使用 CUDA 加速训练
单卡训练
在 PyTorch 框架下,CUDA 的使用变得非常简单,我们只需要显式的将数据和模型通过.cuda()
方法转移到 GPU 上就可加速我们的训练。如下:
model = Net()
model.cuda() # 模型显示转移到CUDA上
for image,label in dataloader:
# 图像和标签显示转移到CUDA上
image = image.cuda()
label = label.cuda()
2
3
4
5
6
7
多卡训练
PyTorch 提供了两种多卡训练的方式,分别为DataParallel
和DistributedDataParallel
(以下我们分别简称为 DP 和 DDP)。这两种方法中官方更推荐我们使用DDP
,因为它的性能更好。但是DDP
的使用比较复杂,而DP
只需要改变几行代码就可以实现。
多卡训练评测
pytorch-distributed (opens new window) 作者使用 PyTorch 编写了不同加速库在 ImageNet 上的使用示例(单机多卡),需要的同学可以当作 quickstart 将需要的部分 copy 到自己的项目中(Github 请点击下面链接):
- nn.DataParallel (opens new window) 简单方便的 nn.DataParallel
- torch.distributed (opens new window) 使用 torch.distributed 加速并行训练
- torch.multiprocessing (opens new window) 使用 torch.multiprocessing 取代启动器
- apex (opens new window) 使用 apex 再加速
- horovod (opens new window) horovod 的优雅实现
- slurm (opens new window) GPU 集群上的分布式
- 补充:分布式 evaluation (opens new window)
这里,作者记录了使用 4 块 Tesla V100-PICE 在 ImageNet 进行了运行时间的测试,测试结果发现 Apex 的加速效果最好,但与 Horovod/Distributed 差别不大,平时可以直接使用内置的 Distributed。Dataparallel 较慢,不推荐使用。

← PyTorch计算图 DP→