pytorch中的分布式训练

本文详细介绍了PyTorch中的数据并行处理,包括DataParallel(DP)和DistributedDataParallel(DDP)。DP适用于单机多卡,而DDP则支持单机多卡和多机多卡,能更有效地利用资源。DP中,0号卡承担较多操作,可能导致内存不平衡;而DDP则通过分布式通信,实现了更均衡的负载。实现DDP时,需要初始化进程、创建分布式数据加载器,并使用DistributedDataParallel包装模型。启动方式包括单机多卡和多机多卡的命令行参数。
部署运行你感兴趣的模型镜像

1.简介

Pytorch的数据分为两种,torch.nn.parallel.DataParallel(DP)和torch.nn.parallel.DistributedDataParallel(DDP).

使用场景:

  • DP模式用于单机多卡
  • DDP模式可以用于单机多卡、多机多卡以及模型并行。

2. DP模式

DP模式用于单机多卡的情况。实现起来较为简单,只需要用torch.nn.parallel.DataParallel包装模型即可,其余与单机单卡的情况相同。

1.1 流程

  1. master(一般是GPU0)从磁盘或者合页内存中取数据。
  2. master将数据分到其他GPU上
  3. master将模型复制到其他GPU上
  4. 每块GPU单独进行前向计算,得到输出
  5. master收集每块GPU上的输出,计算损失
  6. master将损失分到其他卡上,每块卡单独进行反向传播,计算梯度
  7. master收集每块GPU上的梯度,汇总以后,进行reduce操作,结果分发到每块卡上。
  8. 每块GPU根据梯度,单独更新模型

1.2 图示流程在这里插入图片描述

可以看出DP模型比较多的操作是在0号卡上进行的。分数据、将模型的副本传到其他模型,收集每块卡的输出、计算loss,将loss传到每块卡上,在每块卡上进行反向传播得到梯度后,收集每块卡上的梯度,进行reduce上操作后,传到其他卡上。这样使得0号卡所占的内存比较多,使得内存使用不均衡,而且会经常出现其他卡等待0好卡计算的情形。

2. Distributed Data Parallel

2.1 处理流程

  1. 从master(一般是GPU0)从磁盘或者合页内存中取数据。
  2. 所有GPU同时去取数据,不需要GPU0去分
  3. 每块GPU单独进行前向计算
  4. 每块GPU单计算loss
  5. 每块GPU单独进行反向过程,计算出参数的梯度,并进行参数之间的传递(计算和参数传递间存在交叉过程)
  6. 在GPU0上进行梯度的allreduce操作,然后将梯度传递到其他GPU上。
  7. 每个GPU单独地进行参数更新
    在这里插入图片描述
    可以看出DDP只有在梯度收集的时候,存在GPU间的通信,其余的操作都是在各自的GPU上进行的,这样可以均衡负载,也可以节省时间。

1.3 实现

  1. 进程初始化
    backend 可选nccl,gloo和mpi模式,表示不同的collective communication方式。使用英伟达显卡,运行比较快的是nccl方式
local_rank= os.getenv('LOCAL_RANK', -1)
    if local_rank != -1:
        torch.cuda.set_device(local_rank)
        device = torch.device("cuda", local_rank)
        torch.distributed.init_process_group(backend="nccl", init_method='env://')
  1. 数据集创建
def create_dataloader(...):

    train_datasets= torchvision.datasets.MNIST(
        root='./mnist',
        train=True,
        transform=torchvision.transforms.ToTensor(),  # (0,255) -->(0,1)
        download=False
    )

    train_sampler = DistributedSampler(train_datasets) ## 防止不同进程交叉取数据
    train_dataloader = DataLoader(train_datasets, sampler=train_sampler, batch_size=int(args.test_batch_size/args.world_size),
                                  num_workers=args.num_workers, pin_memory=True)
    ...
    ....

train_sampler,train_dataloader,test_sampler,test_dataloader = create_dataloader(args,main_process)
  1. 使用DDP模型对模型进行包装
model = ...
model.to(device)
num_gpus = torch.cuda.device_count()
if num_gpus > 1:
   print('use {} gpus!'.format(num_gpus))
   model = nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank],
                                                    output_device=args.local_rank)

  1. 模型训练
    for epoch in range(EPOCH):
        # 步骤五:打乱数据顺序
    train_sampler.set_epoch(epoch)
    model.train()
    start= time()        
    ### train
    for step, (b_x, b_y) in enumerate(train_dataloader):
        predit_y = model(b_x)
        loss = loss_func(predit_y, b_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
  1. 启动方式
  • 单机多卡 python -m torch.distributed.run --nproc_per_node 2 --master_port 2393 ddp_train.py
  • 多机多卡
    在机器0上运行python -m torch.distributed.launch --nproc_per_node=4 --nnodes=2 --node_rank=0 --master_addr="192.0.0.1" --master_port=1234 ddp.py
    在机器1上运行python -m torch.distributed.launch --nproc_per_node=4 --nnodes=2 --node_rank=1 --master_addr="192.0.0.1" --master_port=1234 ddp.py
    不同机器上的node_rank不同,其余相同

TODO

参考

[1] pytorch(分布式)数据并行个人实践总结——DataParallel/DistributedDataParallel
[2] PyTorch Distributed: Experiences on Accelerating Data Parallel Training
[3] 多机多卡

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

### PyTorch DataParallel 分布式训练 #### 使用 `DataParallel` 实现多GPU训练 为了利用多个GPU加速神经网络的训练,在PyTorch中可以采用`torch.nn.DataParallel`类[^1]。该方法会自动分割输入数据,并将其分配给不同的GPU上的模型副本处理;当所有子任务完成后,它还会收集各个部分的结果并将它们合并成完整的输出。 下面是一个简单的例子展示怎样设置一个基于`DataParallel`接口的应用程序: ```python import torch import torch.nn as nn from torchvision import models, transforms from torch.utils.data import DataLoader class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() resnet = models.resnet18(pretrained=True) self.backbone = nn.Sequential(*list(resnet.children())[:-1]) self.fc = nn.Linear(512, 10) def forward(self, x): with torch.no_grad(): features = self.backbone(x).flatten(start_dim=1) out = self.fc(features) return out def prepare_data(batch_size_per_gpu): transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ]) train_loader = DataLoader( dataset, batch_size=batch_size_per_gpu * torch.cuda.device_count(), # 总batch size为每张卡上batch size之和 shuffle=True, num_workers=4 ) return train_loader if __name__ == '__main__': model = SimpleCNN().cuda() if torch.cuda.device_count() > 1: print(f"Using {torch.cuda.device_count()} GPUs!") model = nn.DataParallel(model) optimizer = torch.optim.Adam(model.parameters()) criterion = nn.CrossEntropyLoss() dataloader = prepare_data(batch_size_per_gpu=32) for epoch in range(num_epochs): running_loss = 0.0 for i, (inputs, labels) in enumerate(dataloader): inputs, labels = inputs.to('cuda'), labels.to('cuda') outputs = model(inputs) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() running_loss += loss.item() ``` 这段代码展示了如何创建一个多GPU版本的卷积神经网络,并对其进行训练。注意这里定义了一个辅助函数`prepare_data()`用于准备数据集加载器,其中指定了总的批量大小等于每个GPU上的批次数乘以GPU数量[^3]。 需要注意的是虽然`DataParallel`易于使用,但它也有一些局限性,比如只适合于单台机器内的多GPU环境,并且由于其内部机制的原因可能导致性能不如更先进的分布式训练方案如`DistributedDataParallel`。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值