6.5-分布式训练的通信协调
通信协调在分布式训练的整体性能中起到了举足轻重的作用。众多软硬件技术在深度学的发展过程中被提出和应用。本节以 GPU为例,介绍目前深度学习中所采用的主流通信技术。
按照方式,通信可分为:机器内通信和机器间通信。前者包含:共享内存、GPUDirect P2P over PCIe、GPUDirect P2P over NVLink [8],而后者包含:TCP/IP网络、 RDMA网络和GPUDirect RDMA网络。
6.5.1 通信协调的硬件
图示了两种常见的GPU硬件形式(上)以及连接方式(下):NVLink (300GB/s) vs. PCIe 4.0 (32GB/s)[1]。二者的链路带宽差距高达约10倍。众多实际训练表明,高带宽链路极大地提高了并行训练的总体性能。因此,我们可以看到无论是节点内的多设备以及节点间的网络,链路带宽近些年都取得了大幅提升。
除了NVIDIA之外,其它加速器硬件厂商也提出了类似的高速数据链路。下图分别是AMD和隧原科技[6]设计的加速器互联硬件。
而依据GPU的硬件互联结构,可以绘制出互联拓扑。目前的互联结构存在多种不同的拓扑。如下图所示,最为常见的 PCI only 连结仅使用标准的PCI/PCIe接口将加速卡与系统的其它部分连接起来。受限于PCIe的带宽限制(例如PCIe 4.0 x16 单向传输带宽为 31.508 GB/s)以及树形的连接拓扑,PCIe在设备互联上具有天然的障碍。因此,在GPU高性能计算中常配备专用高速链路实现高带宽的卡间互联,包括DGX-1/P9中的卡间直连,以及DGX-2/3中采用交换机形式的NVSwitch。
除了通信拓扑,通信的协议也在不断迭代。如下图的GPUDirect P2P[7],GPU可以直接访问另一GPU的显存,无需CPU介入或系统内存中转,从而实现“零拷贝(zero-copy)”。 开启这项功能的对于GPU以及之间的连接方式等硬件条件均有要求:GPU属于Tesla / Quadra 专业级别,并且GPU之间通过NVLink互联或者属于同一PCIe root(例如,不允许跨NUMA node)。
而在跨节点网络中也有类似的协议GPUDirect RDMA [8],实现了GPU中的数据通过网络直接发送,无需系统内存中转,也实现了“零拷贝(zero-copy)”。但这里网络操作仍需CPU发起,因此与GPUDirect P2P的纯GPU操作有所区别。
开启这项功能的条件,除了满足GPUDirect的基本条件之外,还需满足RDMA网卡与GPU也属于同一PCIe root。
6.5.2 通信协调的软件
分布式训练系统 通信库
为了更好地服务深度学习等GPU任务,NVIDIA提出了针对其GPU等硬件产品的通信库 NCCL: NVIDIA Collective Communication Library[12]。
NCCL提供类似MPI的通信接口,包含集合式通信(collective communication)all-gather、 all-reduce、 broadcast、 reduce、reduce-scatter 以及点对点(point-to-point)通信send 和receive。
拓扑感知的通信 NCCL这样的通信库中目前能够提供的通信算法主要针对已有的标准硬件,相对比较有限的,而有研究工作(例如: SCCL )根据连接拓扑和带宽延迟等信息,可以综合设计性能更为优化的通信算法。
除了NVIDIA之外,其它的厂商也发布了针对自身产品的高效通信库,例如AMD的RCCL以及intel的OneCCL。
随着硬件的快速发展,带来了更高的性能和更大的优化机遇,因此软件研究方面的迭代,尤其是支持分布式深度学习训练的算法硬件协同设计的研究,依然存在这巨大的潜力。
6.5.3 课后实验:AllReduce的实现和优化
实验目的
- 理解并行训练的原理和实现
- 定制一个新的并行训练的通信压缩算法
实验环境(参考)
- Ubuntu 18.04
- PyTorch==1.5.0 (务必安装CPU版本)
- OpenMPI
- Horovod==0.19.4
实验原理:深度学习中,分布式训练算法和分布式训练系统的基本知识
实验内容
实验流程图:
具体步骤:
安装依赖支持:OpenMPI, Horovod
编写程序,使用Horovod库,增加数据并行训练支持
- 参照Horovod with PyTorch参考文档,修改
mnist_basic.py
文件, 另存为pytorch_mnist_horovod.py
,使用Horovod库实现数据并行- mnist_basic.py原始文件地址:https://github.com/pytorch/examples/blob/master/mnist/main.py
- Horovod with PyTorch文档地址:https://github.com/horovod/horovod/blob/master/docs/pytorch.rst
- 记录每个step的运行时间和正确率(accuracy)
- 参照Horovod with PyTorch参考文档,修改
理解Horovod的执行逻辑,利用Numpy实现float8(8bit), float16(16bit)编码方案的压缩/解压缩
- 克隆GitHub上Horovod库
- 修改
/horovod/torch/compression.py
文件,增加Bit8Compressor和Bit16Compressor类,实现compress和decompress函数。(提示:torch.Tensor没有8-bit float类型支持,所以Bit8Compressor还需实现float32和float8类型的相互转化)
修改Horovod库中代码,增加对float8(8bit), float16(16bit)格式的压缩
- 修改
/horovod/torch/mpi_ops.py
文件,利用Horovod内嵌的AllGather通信和压缩接口,增加对float8(8bit), float16(16bit)格式的压缩代码的调用。 - 重新build Horovod库。
- 修改
修改MNIST样例代码,增加压缩功能。
测试代码正确性,比较原始代码、数据并行、加入压缩算法三者的性能差别。
[选做项目] 利用C++/CUDA API实现更为高效的压缩/解压缩编码
实验报告
实验环境:
硬件环境 | 服务器数目 | |
网卡型号、数目 | ||
GPU型号、数目 | ||
GPU连接方式 | ||
软件环境 | OS版本 | |
GPU driver、(opt. NIC driver) | ||
深度学习框架 python包名称及版本 | ||
CUDA版本 | ||
实验结果:
比较原始串行训练,用Horovod并行训练,加入压缩算法三者,在同样epoch条件下的训练时间和结果正确率。
Epoch size: ___________
训练算法 | 训练时间 | 结果正确率 | |
串行训练 | |||
用Horovod并行 | Device# == 2 | ||
Device# == 4 | |||
float8(8bit)压缩 | Device# == 2 | ||
Device# == 4 | |||
float16(16bit)压缩 | Device# == 2 | ||
Device# == 4 | |||
参考代码
安装Horovod
安装OpenMPI:
sudo apt install openmpi-bin
安装Horovod:
python3 -m pip install horovod==0.19.4 --user
利用Horovod并行化pytorch MNIST模型训练 2.1. Device# == 1
运行命令:
python3 pytorch_mnist_horovod.py
2.2. Device# == N (e.g., N == 2, 4, 6, 8)
运行命令:
horovodrun -n 2 python3 pytorch_mnist_horovod.py –hvd True
参考代码: https://github.com/horovod/horovod/blob/master/examples/pytorch_mnist.py
基于Horovod(v0.19.4)库增加bit-16和bit-8的并行训练的通信压缩算法
Build Horovod
运行命令:
HOROVOD_WITHOUT_MXNET=1 HOROVOD_WITHOUT_GLOO=1 HOROVOD_WITHOUT_TENSORFLOW=1 HOROVOD_WITH_PYTORCH=1 python setup.py build
在horovod库中需要修改的文件和代码片段: bit8,bit16.git_diff
执行压缩算法进行训练
mpirun -n 2 python pytorch_mnist_compress.py --bit8-allreduce mpirun -n 2 python pytorch_mnist_compress.py --bit16-allreduce
小结与讨论
思考题:为什么模型训练通常需要分布式进行,而分布式模型预测并不常见?
计算模式不同:预测任务占用存储更小,更容易放在单个设备中
训练需要各个工作节点(Worker)保持通信,从而协调统一地更新模型参数;
预测中的模型参数是固定的,各个工作节点分别使用只读副本,无需相互通信协调