PyTorch分布式训练

PyTorch切分模型和数据两种方法:

  1. DataParallel是单进程多线程的,只用于单机情况;

  1. DistributedDataParallel支持模型并行,同时适用于单机和多机情况。多进程,每个进程都有独立的优化器,执行自己的更新过程,梯度通过通信传递到每个进程(GPU之间只传递梯度),所有执行的内容是相同的。

DistributedDataParallel内部机制

https://pytorch.org/docs/stable/notes/ddp.html

大致流程

Figure 1. 多机多卡并行训练流程

  1. 初始化进程组。

  1. 创建分布式并行模型,每个进程都会有相同的模型和参数。

  1. 创建数据分发Sampler,使每个进程加载一个Batch中不同部分的数据。

  1. 每个进程前向传播并各自计算梯度。

  1. 模型某一层的参数得到梯度后会马上进行通讯并进行梯度平均

  1. 各GPU更新模型参数。

初始化
# 初始化分布式环境
dist.init_process_group(                                   
        backend='nccl',                                         
        init_method='env://',                                   
        world_size=args.world_size,                              
        rank=rank                                               
    )

其中backend参数指定通信后端,包括mpi, gloo, nccl。nccl是Nvidia提供的官方多卡通信框架,相对比较高效;mpi也是高性能计算常用的通信协议,不过需要自己安装MPI实现框架,比如OpenMPI;gloo是内置通信后端,但是不够高效。init_method指的是如何初始化,以完成刚开始的进程同步;这里设置的env://指的是环境变量初始化方式,需要在环境变量中配置4个参数:MASTER_PORT,MASTER_ADDR,WORLD_SIZE,RANK。

初始化即建立一个默认的分布式进程组 (distributed process group),这个group同时会初始化Pytorch的torch.distributed包,后续可以直接用torch.distributed的API进行分布式的基本操作。

import torch.distributed as dist
模型侧
torch.cuda.set_device(opt.local_rank)
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[opt.local_rank])
rank = dist.get_rank()
device = torch.device(f'cuda:{opt.local_rank}')

dist.barrier()  # synchronizes all processes

rank是全局的进程序号,要根据这个参数来设置每个进程所使用的device设备。

local_rank是指的训练进程在当前节点的序号,即所采用的GPU编号。对于local_rank的获取有两种方式,方式一是在训练脚本添加一个命令行参数,程序启动时会对其自动赋值;方式二是采用torch.distributed.launch启动时加上--use_env=True,该情况下会设置LOCAL_RANK这个环境变量。

# 方式一
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--local_rank", type=int)
args = parser.parse_args()
local_rank = args.local_rank

# 方式二
local_rank=int(os.environ["LOCAL_RANK"])
数据侧
data_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset, shuffle=True)
dataloader = torch.utils.data.DataLoader(
        train_dataset,
        batch_size=opt.batchSize,
        shuffle=False,
        num_workers=int(opt.nThreads),
        drop_last=True,
        sampler=data_sampler
        )

注意训练循环过程的每个epoch开始时调用data_sampler.set_epoch(epoch),主要是为了保证每个epoch的划分是不同的,其它的训练代码都保持不变。

有效batch_size其实是batch_size_per_gpu * world_size (world_size为节点总数nnodes乘以每个节点的GPU数nproc_per_node)。

启动方式
python -m torch.distributed.launch --nproc_per_node=NUM_GPUS_YOU_HAVE_PER_NODE
           --nnodes=2 --node_rank=0 --master_addr="192.168.1.1" --master_port=1234
           YOUR_TRAINING_SCRIPT.py (--arg1 --arg2 --arg3
           and all other arguments of your training script)

所有的进程需要知道进程0的IP地址以及端口,这样所有进程可以在开始时同步,一般情况下称进程0是master进程,通常在进程0中打印信息或者保存模型。

参考链接

https://github.com/pytorch/examples/tree/main/imagenet

https://zhuanlan.zhihu.com/p/113694038

https://support.huaweicloud.com/intl/zh-cn/develop-modelarts/modelarts-distributed-0008.html

https://blog.csdn.net/ytusdc/article/details/122091284

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值