PyTorch分布式DPP涉及的基本概念与问题
本篇主要讲解DDP的一些概念和问题,主要涵盖如下:
1、参数rank、local_rank、node、gpu的含义,以及它们之间的关系?一个rank/local_rank是否就是对应一个gpu?
2、checkpoint保存与加载有什么不一样?
3、单卡到分布式,有些什么地方能帮助提速?
如果需要了解DDP使用请看上一篇
PyTorch分布式DPP启动方式(包含完整用例)
1 分布式引入的参数
1.1 rank、local_rank、node等的概念
- rank:用于表示进程的编号/序号(在一些结构图中rank指的是软节点,rank可以看成一个计算单位),每一个进程对应了一个rank的进程,整个分布式由许多rank完成。
- node:物理节点,可以是一台机器也可以是一个容器,节点内部可以有多个GPU。
rank与local_rank: rank是指在整个分布式任务中进程的序号;local_rank是指在一个node上进程的相对序号,local_rank在node之间相互独立。 - nnodes、node_rank与nproc_per_node: nnodes是指物理节点数量,node_rank是物理节点的序号;nproc_per_node是指每个物理节点上面进程的数量。
- word size : 全局(一个分布式任务)中,rank的数量。
上一个运算题: 每个node包含16个GPU,且nproc_per_node=8,nnodes=3,机器的node_rank=5,请问word_size是多少?
答案:word_size = 3*8 = 24
为了方便理解举个例子,比如分布式中有三台机器,每台机器起4个进程,每个进程占用1个GPU,如下图所示:
图中:一共有12个rank,nproc_per_node=4,nnodes=3,每个节点都一个对应的node_rank。
Group:进程组,一个分布式任务对应了一个进程组。只有用户需要创立多个进程组时才会用到group来管理,默认情况下只有一个group。
注意:
1、rank与GPU之间没有必然的对应关系,一个rank可以包含多个GPU;一个GPU也可以为多个rank服务(多进程共享GPU)。
这一点在理解分布式通信原理的时候比较重要。因为很多资料里面对RingAllReduce、PS-WorK 等模式解释时,习惯默认一个rank对应着一个GPU,导致了很多人认为rank就是对GPU的编号。
2、“为什么程序里面的进程用rank表示而不用proc表示?”
这是因为pytorch是在不断迭代中开发出来的,有些名词或者概念并不是一开始就设计好的。所以,会发现node_rank 跟软节点的rank没有直接关系。
1.2 通信参数与模式
通信过程主要是完成模型训练过程中参数信息的传递,主要考虑通信后端和通信模式选择,后端与模式对整个训练的收敛速度影响较大,相差可达2~10倍。 在DDP中支持了几个常见的通信库,而数据处理的模式写在PyTorch底层,供用户选择的主要是后端。 在初始化时需要设置:
-
backend :通信后端,可选的包括:nccl(NVIDIA推出)、gloo(Facebook推出)、mpi(OpenMPI)。从测试的效果来看,如果显卡支持nccl,建议后端选择nccl,,其它硬件(非N卡)考虑用gloo、mpi(OpenMPI)。
-
master_addr与master_port:主节点的地址以及端口,供init_method 的tcp方式使用。 因为pytorch中网络通信建立是从机去连接主机,运行ddp只需要指定主节点的IP与端口,其它节点的IP不需要填写。 这个两个参数可以通过环境变量或者init_method传入。
# 方式1:
os.environ['MASTER_ADDR'] = 'localhost'
os.environ['MASTER_PORT'] = '12355'
dist.init_process_group("nccl",
rank=