目录
- 1. 前言
- 2.分布式训练的分类
- 3.不并行(单机单卡)
- 4. 数据并行 DP和DDP
- 4.1 异同点
- 4.2 原理
- 4.3 DP 实现(单机多卡)
- 4.4 DDP 实现(单机多卡,多机分布式)
- 4.4.1DDP 基本概念
- 4.4.2 DDP之单机多卡
- 4.4.4 DDP之多机分布式
- 参考文献
1. 前言
最近开始上手进行分布式训练,于是在网上开始搜各种教程和资料,看到了许多写得很好的文章,但是有些文章又不是特别的全面,于是决定对这些文章进行归纳和总结,方便后来者的学习和查阅。这里友情提醒一下,大家查资料的时候不要仅仅局限于百度,有时候在百度上查半天,不如去官方文档或者google搜一下,立马就能看到很多优质的解答。
2.分布式训练的分类
关于分布式训练的分类,网上的分类方法五花八门,目前看的这么多文章中最为清晰的要属这篇文章了大模型LLM之分布式训练,简单来讲,分布式训练方法可以分为以下几类:
- 数据并行
- 模型并行(包含
流水线并行
和张量并行
) - 混合并行
关于分布式训练分类大家也可以去看一下Hugging Face上的一篇文章Efficient Training on Multiple GPUs,它的分类方式和我们上面提到的有些不同。
接下来的内容主要来自这篇文章:分布式并行训练(DP、DDP、DeepSpeed、Accelerate、Trainer)
3.不并行(单机单卡)
判断GPU是否可用:device = "cuda" if torch.cuda.is_available() else "cpu"
模型拷贝:model.to(device)
数据拷贝:data.to(device)
模型加载:torch.load(xx.pt, map_location=device)
模型保存:torch.save(model, "model.pt")
4. 数据并行 DP和DDP
Pytorch提供的分布式数据并行有两种Data Parallel(DP)和Distributed Data Parallel(DDP) 目前pytorch官网更推荐大家使用的是DDP模式,详见官方文档Data Parallel 和官方文档Distributed Data Parallel
4.1 异同点
DP 和DDP在工作模式上有着共同点和差异,这里博采众长,做一下梳理和总结:
-
共同点:都是
数据并行
,都是即插即用 -
不同点:
- DP:仅支持单机多卡, 显存负载不均衡(device[0]负载大),不支持Apex混合精度训练,GPU利用不均衡,因Python GIL争用影响 仅支持单进程多线程,训练速率低。
- DDP:支持单机多卡&多机多卡,数据分配均衡,支持Apex混合精度训练,借助All-Reduce的数据交换方式提高GPU的通讯效率,支持多进程,训练速率高,
如果模型特别大,DDP也可以和模型并行一起工作,这个在官方教程中有提到
关于DP和DDP的区别还可以看一下这篇有深度的文章:Distributed data parallel training using Pytorch on AWS
4.2 原理
DP原理
- 将模型权重从主卡(默认GPU:0)复制到所有GPU上,输入的bacth大小的数据会分散到各个GPU上(每张卡上输入batch / 4,假设有四张卡)。
- 之后独自在各张卡上执行前向过程,每张卡的输出结果会被聚合到主卡上,然后在主卡上计算总的损失,总损失是一个标量,一般可以求平均值,再通过损失函数求导,得到损失的梯度,分发到各个GPU上。
- 在每个GPU根据链式法则继续计算各个参数的梯度,再将所有设备上的梯度回传到主卡上进行梯度累加并求梯度均值。在主卡上通过平均梯度更新模型权重。最后将更新后的模型参数 广播 到其余 GPU 中进行下一轮的前向传播。
DDP 原理
DDP背后的实现是依靠Ring-AllReduce 具体细节可以参考这两篇文章:
Pytorch 分布式训练DDP(torch.distributed)详解-原理-代码
分布式训练(中)——DP、DDP模式
4.3 DP 实现(单机多卡)
在Pytorch中torch.nn.DataParallel()
包含三个参数:
module:参数传入具体的模型,比如ResNet,Unet等
device_ids:传入gpu编号例如:[0,1,2,3],默认为None即使用所有GPU
output_device:指定中心设备(参数服务器),用于汇总梯度的 GPU 是哪个,默认device_ids[0]
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2" #设置可见的gpu
net=Unet() #初始化一个模型
device_ids=[2,0,1] #gpu编号,这里故意写成2,0,1而不是0,1,2是为了方便大家理解特殊请情况
net.to(device_ids[0]) #设置中心设备,注意是device_ids[0] 这一行不能少
net = torch.nn.DataParallel(net, device_ids=[2, 0, 1])
batch_data.to(device_ids[0]) #
output = net(batch_data)
模型的加载和保存,为了和单机单卡保持一致
,可以这样写:
保存
if isinstance(net,torch.nn.DataParallel):
torch.save(net.module.state_dict(), "model.pth")
else:
torch.save(net.state_dict(), "model.pth")
加载
if isinstance(self.model, torch.nn.DataParallel):
net.module.load_state_dict(torch.load("model.pth"), strict=False)
else:
net.load_state_dict(torch.load("model.pth"), strict=False)
注:
- os.environ[“CUDA_VISIBLE_DEVICES”] = “0,1,2” 设置可见的GPU
- 在上述的代码中
net.to(device_ids[0])
设置的是中心设备,这一行不能少,这里device_ids=[2,0,1]是为了方便大家理解device_ids[0]不代表一定是cuda:0。 - torch.nn.DataParallel() 是对模型进行包裹
- 关于使用中的一些详细的细节可以看这两篇博客torch.nn.DataParallel使用细节和pytorch GPU torch.nn.DataParallel (DP)多卡并行
4.4 DDP 实现(单机多卡,多机分布式)
DDP相比于DP要复杂得多,这里首先推荐官网的教程,教程很详细,一定要认真看,官方的教程看明白了再看接下来的内容!!!
官方教程 Tutorials
官方API DistributedDataParallel
4.4.1DDP 基本概念
-
WORLD:
- world 表示包含所有进程的组(所有gpu的集合)。
- 每个进程通常对应一个 GPU, world 中的进程可以相互通信,这使得使用分布式数据并行(Distributed Data Parallel, DDP)进行训练成为可能。
-
WORLD_SIZE(gpu个数/进程个数):
- world_size 表示分布式训练环境中的总进程数/gpu数。
- 每个进程都会被分配一个唯一的标识符(rank),从 0 到 world_size-1。
-
RANK(进程标识符):
- rank 是分配给world中每个进程的唯一标识符,用于标识每个进程在分布式训练中的角色。
-
LOCAL RANK:
- local rank是分配个单个node中每个进程的标识符,world中可能有多个node。每个进程的local_rank都不一样。 判断master GPU:if local_rank == 0:
-
NODE(节点):
- node 可以理解为一个服务器,代表着物理设备上的一个实体。
- 在多机分布式训练中,每台机器被视为一个节点,节点之间需要进行通信。例如,如果有2 个node/server,每个 node/server/machine 各有4张卡(4 gpus)。total_world_size = 2(节点数) * 4(每个节点的 GPU 数量)= 8, rank 的取值范围为 [0, 1, 2, 3, 4, 5, 6, 7], local_rank 的取值范围为 [0, 1, 2, 3],[0, 1, 2, 3] 分别对应着不同的节点上的进程。
这里可以参考这篇博客中的例子,如图所示,有三个node,每个node有4个GPU(则每个node会有四个进程,一个进程对应一个GPU)
4.4.2 DDP之单机多卡
Pytorch支持的分布式框架的后端主要有 Gloo、MPI 和 NCCL 三种。PyTorch 官方的规则是:如果是分布式 GPU 训练,优先推荐 NCCL:如果是分布式 CPU 训练,优先推荐 Gloo,其次是 MPI。
三种方式:torch.distributed.launch,torch.multiprocessing,torchrun
https://zhuanlan.zhihu.com/p/681694092
https://zhuanlan.zhihu.com/p/561218626
https://blog.csdn.net/m0_46294481/article/details/130608283
https://blog.csdn.net/weixin_54338498/article/details/133308570
【深度学习实战(27)】「分布式训练」DDP单机多卡并行指南
Multi-GPU Training in PyTorch with Code (Part 3): Distributed Data Parallel
这部分以后有空再补,实在没时间写了。
CUDA_VISIBLE_DEVICES : 环境变量,用于指定哪些GPU设备可见。0,1表示设备编号为0和1的两个GPU将被使用。如果你有多个GPU,但只想使用其中一部分,可以通过设置CUDA_VISIBLE_DEVICES来限制使用的GPU。
torchrun: 分布式训练的工具。它是PyTorch提供的用于启动和管理分布式训练的命令。
standalone:指定使用独立的分布式训练方式,即在单个节点上进行多卡训练。(所谓的节点是指训练服务器的数量)。如果我想在多个节点训练,需要讲这个参数改为multinode
nnodes:指定节点的数量,即参与训练的节点数。在这里,设置为1表示只有一个节点。
nproc_per_node:每个节点使用的GPU数量,即每个节点上的GPU数目。在这里,设置为2表示每个节点上会使用两个GPU进行训练。
node_rank:物理节点的序号,每个电脑的序号,在多机分布式中使用
在训练过程中难免会遇到一些问题,这时候需要调试,可以参考这篇文章:pycharm进行torchrun的调试
4.4.4 DDP之多机分布式
一般情况下不会用到这种情况所以,我们这里不做讲解,感兴趣的可以看这篇博客:PyTorch分布式训练基础–DDP使用
参考文献
大模型LLM之分布式训练
A Survey of Large Language Models
Pytorch 分布式训练DDP(torch.distributed)详解-原理-代码
Efficient Training on Multiple GPUs
分布式训练(中)——DP、DDP模式
torch.nn.DataParallel使用细节
pytorch GPU torch.nn.DataParallel (DP)多卡并行
DistributedDataParallel
Tutorials
pycharm进行torchrun的调试
PyTorch分布式训练基础–DDP使用
Distributed data parallel training using Pytorch on AWS
DDP
分布式并行训练(DP、DDP、DeepSpeed、Accelerate、Trainer)
Pytorch多卡训练
分布式训练(上)——rank local_rank node