DDP(DistributedDataParallel)自用笔记

DDP 的工作原理——数据并行

当一张GPU可以存储一个model时,可以通过每张GPU都复制一份模型,在不同的GPU上运行不同的数据,即将一个批次的数据送入各个模型进行并行训练,通过对并行的GPUs上的数据和模型结果进行运算(求平均梯度...)来实现增大batch、提高速度的效果。

训练过程是多进程的,每一块GPU都对应一个进程,除非我们手动实现相应代码,不然各个进程的数据都是不互通的。

如果要用DDP来进行训练,我们通常需要修改三个地方的代码:数据读取器dataloader,日志输出print,指标评估evaluate。

1. DDP的训练过程

DDP的训练过程可以总结为如下步骤:

1)在训练开始时,整个数据集被均等分配到每个GPU上。每个GPU独立地对其分配到的数据进行前向传播(计算预测输出)和反向传播(计算梯度)。

2)通过Ring-All-Reduce算法同步各个GPU上的梯度,以确保模型更新的一致性。

3)一旦所有的GPU上的梯度都同步完成,每个GPU使用这些聚合后的梯度来更新他的模型副本参数,也就是step的过程。因为每个GPU都使用相同的更新梯度,所以所有的模型副本在任何时间点上都是相同的。

2.DDP的名词定义

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的数量。

master_addr与master_port:主节点的地址以及端口,供init_method 的tcp方式使用。 因为pytorch中网络通信建立是从机去连接主机,运行ddp只需要指定主节点的IP与端口,其它节点的IP不需要填写。 这个两个参数可以通过环境变量或者init_method传入。

3. DDP是如何分布式的并行的运行代码的:

分布式训练通过启动多个进程,每个进程负责不同的 GPU 或部分计算任务。

--use_env 会自动设置分布式训练所需的环境变量,主要包括:

  • RANK:全局进程 ID。
  • WORLD_SIZE:总进程数。
  • LOCAL_RANK:当前进程对应的 GPU 索引(在本地节点上的 GPU 编号)。
  • MASTER_ADDR:主节点地址。
  • MASTER_PORT:主节点通信端口。

例如,假设你使用两张 GPU(nproc_per_node=2),会启动两个进程,分别负责 GPU 0 和 GPU 1。每个进程都会独立执行 main(args)。

## init_distributed_mode:
#给每个进程分配local rank序号,指导gpu的device序号
args.gpu = int(os.environ['LOCAL_RANK'])   

这时,init_distributed_mode会根据环境变量进行初始化,比如说,上面两个进程,会分别得到:

arg.gpu=0和arg.gpu=1

Rank: 0, Local Rank: 0, World Size: 2
Rank: 1, Local Rank: 1, World Size: 2

还有一个问题:

获得多gpu方法:

logging.info(f'GPU is available:{torch.cuda.is_available()}')
    if torch.cuda.is_available():
        gpus = torch.cuda.device_count()
        for i in range(gpus):
            print(f'\t GPU{i}.:{torch.cuda.get_device_name(i)}')

如果要想高效的处理并行运算:

可以使用nn.parallel.DataParallel或nn.parallel.DistributedDataParallel,如:

从其他文章中学习的第一版(个人感觉不太符合我的需求):

在指定gpu的时候,如果device='cuda',并且是ddp多卡运行,那么xx.to(device)默认选择第一个卡作为选中的gpu,这意味着,即使系统中有多块 GPU,这条命令也只会指向默认的一块。比如:

device = torch.device(args.device)  # args.device='cuda'
model.to(device)

model 会在“cuda:0”上。

下面这种一次性输入多个device给ddp,不符合我一张gpu处理一个进程的需求,(不考虑):
#指定多个GPU
from torch.nn import DataParallel
#上面这一行一定要加,因为没加一直报错都开始怀疑torch版本是不是有问题了哈哈
import os
os.environ['CUDA_VISIBLE_DEVICES']='0,2,3,4'#代表使用的第一块,第三块,第四块和第五块卡
device_ids = [0,2,3,4]
model  = torch.nn.Dataparallel(model, device_ids =device_ids)
model = model.cuda()

或:

model = torch.nn.Dataparallel(model)  
# 默认适用所有gpu(这种可以通过CUDA_VISIBLE_DEVICES在命令行中指定使用的gpu)

二改:

DDP单机多卡的gpu定义问题

torch.nn.parallel.DistributedDataParallel (简称 DDP) 时,device_ids参数指定的是 每个进程负责的设备列表,而不是整个系统的所有设备。

torch.nn.parallel.DistributedDataParallel的作用是copy model给每个进程。所以,该函数中的device_ids参数告诉 DDP 当前进程应该使用哪些设备(通常是一个或多个 GPU),并且这些设备是该进程独占的。
对于单机多卡训练,device_ids通常是每个进程对应的单个 GPU 的设备 ID 列表,如 [0], [1]。
如果一个进程负责多个 GPU,则 device_ids可以是一个列表,如 [0, 1]。(但通常不这样)

所以,正确代码:

torch.cuda.set_device(args.local_rank)  # 设置当前进程使用的 GPU
model = DistributedDataParallel(model, device_ids=[args.local_rank])

这样的话,每个model使用的device_ids就是当前进程分配的gpu id:例 [0]。

参考:Pytorch DistributedDataParallel(DDP)教程一:快速入门理论篇_distributeddataparallel教程-优快云博客PyTorch分布式训练基础--DDP使用 - 知乎

PyTorch 源码解读之 DP & DDP:模型并行和分布式训练解析_runtimeerror: distributeddataparallel is not neede-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值