基本概念
- RANK:使用 os.environ[“RANK”] 获取进程的序号,一般是1个 gpu 对应一个进程。它是一个全局的序号,从 0 开始,最大值为所有 GPU 的数量减 1
- LOCAL_RANK:使用 os.environ[“LOCAL_RANK”] 获取每个进程在所在主机中的序号。从 0 开始,最大值为当前进程所在主机的 GPU 的数量减 1
- WORLD_SIZE:使用 os.environ[“WORLD_SIZE”] 获取当前启动的所有的进程的数量(所有机器的进程总和)
为了便于理解,我们举个例子来说明:假设我们使用了 2 台机器,每台机器 4 块 GPU。那么,RANK 取值为 [0, 7];每台机器上的 LOCAL_RANK 的取值为 [0, 3];WORLD_SIZE 的值为 8。
硬件相关
可以用过nvidia-smi topo -m
命令查看
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7 mlx5_0 mlx5_1 mlx5_2 mlx5_3 mlx5_4 mlx5_5 mlx5_6 mlx5_7 mlx5_8 mlx5_9 CPU Affinity NUMA Affinity
GPU0 X NV12 NV12 NV12 NV12 NV12 NV12 NV12 PXB PXB SYS SYS SYS SYS SYS SYS SYS SYS 48-63,176-191 3
GPU1 NV12 X NV12 NV12 NV12 NV12 NV12 NV12 PXB PXB SYS SYS SYS SYS SYS SYS SYS SYS 48-63,176-191 3
GPU2 NV12 NV12 X NV12 NV12 NV12 NV12 NV12 SYS SYS PXB PXB SYS SYS SYS SYS SYS SYS 16-31,144-159 1
GPU3 NV12 NV12 NV12 X NV12 NV12 NV12 NV12 SYS SYS PXB PXB SYS SYS SYS SYS SYS SYS 16-31,144-159 1
GPU4 NV12 NV12 NV12 NV12 X NV12 NV12 NV12 SYS SYS SYS SYS PXB PXB SYS SYS SYS SYS 112-127,240-255 7
GPU5 NV12 NV12 NV12 NV12 NV12 X NV12 NV12 SYS SYS SYS SYS PXB PXB SYS SYS SYS SYS 112-127,240-255 7
GPU6 NV12 NV12 NV12 NV12 NV12 NV12 X NV12 SYS SYS SYS SYS SYS SYS PXB PXB SYS SYS 80-95,208-223 5
GPU7 NV12 NV12 NV12 NV12 NV12 NV12 NV12 X SYS SYS SYS SYS SYS SYS PXB PXB SYS SYS 80-95,208-223 5
Legend:
X = Self
SYS = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
PXB = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
PIX = Connection traversing at most a single PCIe bridge
NV# = Connection traversing a bonded set of # NVLinks
communication primitive
通信方式在并行任务中通常被分为两大类:点对点通信(Point-to-point communication)和集体通信(Collective communication)。在P2P模式中,通信流程只涉及一个发送者和一个接收者,其实现过程相对较为简单。另一方面,集体通信涉及多个发送者和接收者,常见的通信方式包括 broadcast、gather、all-gather、scatter、reduce、all-reduce、reduce-scatter、all-to-all等操作。
Reduce:从多个sender那里接收数据,最终combine到一个节点上。
All-reduce:从多个sender那里接收数据,最终combine到每一个节点上。
常用库
一般用MPI和NCCL这俩库,在编译fastertransformer的时候:
-- Found NCCL (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libnccl.so.2.15.5)
-- Found MPI (include: , library: /opt/hpcx/ompi/lib/libmpi.so)
MPI只创建通信域,给所有计算进程编号,NCCL负责GPU聚合通信。
有了NCCL,还是要给进程编号,确定进程角色。这不在NCCL这个NVIDIA Collective Commulication Libraries职责范围中,所以要MPI来配合完成。
MPI
MPI,全称为消息传递接口(Message Passing Interface),是一个标准化和便携式的消息传递系统,设计用于并行计算中的进程间通信。MPI 提供了一种在分布式内存系统中进行进程间通信的方法,这是并行计算的一种常见模式。在这种模式中,每个进程都有自己的私有内存,进程之间的通信需要通过消息传递来完成。
NCCL
NVIDIA 的 NCCL(NVIDIA Collective Communications Library)是一种专门为 GPU 提供的集合通信库,它实现了类似于 MPI 的一些基本操作,如 all-gather、all-reduce、broadcast、reduce 和 reduce-scatter 等。这些操作在并行计算中非常常见,尤其是在需要在多个 GPU 或节点之间共享数据的情况下。Nvidia做了很多优化,以在PCIe、Nvlink、InfiniBand上实现较高的通信速度。
并行方式
DP
数据平行
TP
张量并行
值得注意的是, tensor parallel 会进行大量的通信, 不像 DP/PP 通信内容只是 per layer 的 gradient 或者 activation. TP 一个 layer 内部就要进行多次不同算子的 activation 的通信. 所以实践中 tp 一般会在机内进行, tp size 受此限制也不会超过8.
Tensor parallel can reduce the total end2end latency since the gemm size in the model becomes smaller than the full model version, but it need the cost time of communication to be small enough.
For devices which support nvlink,I do think tensor parallel is more efficient than pipeline parallel.
PP
由于模型过大,单机多卡满足模型的体积需求时,会使用多机多卡的方案,但是由于模型并行策略会带来大量网络通信,若在多机间使用模型并行会由于网络开销的增加降低整体的训练效率;因此,这时可以使用流水线的并行策略,将模型的不同Layer放到不同的node上进行训练,这时仅相邻的layer之间存在网络通信,可以大大的降低网络的通信量。