zoukankan      html  css  js  c++  java
  • pytorch分布式训练

    第一篇 pytorch分布式训练[1]

    在pytorch 1.6.0,torch.distributed中的功能可以分为三个主要的组件:

    • Distributed Data-Parallel Training(DDP)是一个广泛采用的单程序多数据训练方法。使用DDP,模型会被复制到每个进程,然后每个模型副本会被输入数据样本的不同子集。DDP负责梯度通信以保持模型副本的同步,并将其与梯度计算重叠以加快训练速度。
    • RPC-Based Distributed Training(RPC)是为了支持那些不适用数据并行训练的通用训练架构,比如分布式管道并行,参数服务器范式,以及DDP和其他训练方法的结合。它越过机器边界来帮助管理远程对象生命周期和扩展自动梯度引擎。
    • Collective Communication(c10d)库支持在组内进程之间发送张量,它同时提供了聚合通信(collective communication)接口(比如all_reduce和all_gather)和点对点通信(P2P)接口(比如send和isend)。在1.6.0中DDP和RPC(ProcessGroup Backend)都是基于c10d构建的,前者使用了聚合通信,而后者使用了P2P通信。一般地,开发者不需要直接使用这个原生通信接口,因为上面的DDP和RPC功能可以服务于很多分布式训练场景。然而,对于有些使用案例这些接口还是有用的。一个例子就是分布式参数均化(distributed parameter averaging),应用希望在反向传播后不适用DDP来计算梯度,而是计算模型所有参数的均值。这将把通信从计算中解耦出来,并允许更加细粒度地控制交流的内容。但是另一方面,这也将放弃DDP提供的性能优化。

    数据分布式训练

    pytorch为数据分布式训练提供了多种选择。随着应用从简单到复杂,从原型到产品,常见的开发轨迹可以是:

    • 如果数据和模型能放入单个GPU,使用单设备训练,此时不用担心训练速度;
    • 如果服务器上有多个GPU,并且你在代码修改量最小的情况下加速训练,使用单个机器多GPU DataParallel;
    • 如果你想进一步加速训练并且愿意写一点代码来启动,使用单个机器多个GPU DistributedDataParallel;
    • 如果应用程序跨机器边界扩展,使用多机器DistributedDataParallel和启动脚本;
    • 如果预期有错误(比如OOM)或者资源在训练过程中可以动态连接和分离,使用torchelastic来启动分布式训练。

    数据分布式训练也可以和AMP(自动混合精度)协作。

    torch.nn.DataParallel

    单机器多GPU并行机制,对代码的改动很少

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    if torch.cuda.device_count()>1:
        model = nn.DataParallel(model)
    model.to(device)
    

    但是需要提醒的是:尽管DataParallel使用简单,它一般无法提供最好的性能。这是因为DataParallel的实现在每个前向传播中复制了模型,并且它的单进程多线程并行自然存在GIL冲突。为了获取更好的性能,请考虑使用DistributedDataParallel.

    torch.nn.parallel.DistributedDataParallel

    和DataParallel相比,DistributedDataParallel需要额外一个称为init_process_group的步骤启动,DDP使用多进程并行,因此在模型副本之间不存在GIL冲突。另外,模型在DDP构建时广播(而不是在每次前向传播),这有助于加速训练。DDP配备了若干个性能优化技术。

    有以下几个资料可供参考:

    • DDP notes:提供初学者样例和一些设计实现的简要描述;
    • Getting Started with Distributed Data Parallel:解释一些DDP训练的常见问题,包括不均衡负载、checkpointing、多设备模型。注意,DDP可以简单地和单机器多设备模型并行结合,在Single-Machine Model Parallel Best Practices会有介绍;
    • Launching and configuring distributed data parallel applications会展示如何使用DDP启动脚本。
    • Pytorch Distributed Trainer with Amazon AWS会示范如何在AWS使用DDP

    这里的多设备指的是GPU。

    接下来进入Getting Started with Distributed Data Parallel。

    第二篇 Getting Started with Distributed Data Parallel[2]

    DDP实现了模块级的数据并行,从而在多个机器上运行。使用DDP的应用会生成多个进程,每个进程对应一个DDP实例。DDP使用torch.distributed包中聚合通信来同步梯度和缓存(buffer)。更具体地说,DDP给model.parameters()指定的每个参数注册一个autograd的hook,在对应梯度在反向传播中完成计算后这些hook会被销毁。然后DDP使用这个信号来触发进程间的梯度同步。

    使用DDP的推荐方法是给每个模型副本生成一个进程,进程可以放置在单个机器或者多个机器上,一个模型副本可以跨越多个GPU,但是进程间不能共享GPU。

    基础使用案例

    为了常见DDP模块,首先启动进程组。

    from torch.nn.parallel import DistributedDataParallel as DDP
    import torch.distributed as dist
    import os
    
    def setup(rank, world_size):
        os.environ['MASTER_ADDR'] = 'localhost'
        os.environ['MASTER_PORT'] = '12355'
        
        # initialize the process group
        dist.init_process_group("gloo", rank=rank, world_size=world_size)
    
    def cleanup():
        dist.destroy_process_group()
    

    考虑到时效性,这里删去了原教程中关于32位电脑的进程组启动方法。

    接下来创建玩具模块,用DDP包起来,并喂一些假输入数据。请注意,由于DDP会从rank 0进程广播模型状态到DDP构造器中的所有其他进程,所以你无需担心不同DDP进程中模型的参数初始值不同。

    class ToyModel(nn.Module):
        def __init__(self):
            super(ToyModel, self).__init__()
            self.net1 = nn.Linear(10, 10)
            self.relu = nn.ReLU()
            self.net2 = nn.Linear(10, 5)
    
        def forward(self, x):
            return self.net2(self.relu(self.net1(x)))
    

    接下来是DDP的使用:

    def demo_basic(rank, world_size):
        print(f"Running basic DDP example on rank {rank}.")
        setup(rank, world_size)
    
        # create model and move it to GPU with id rank
        model = ToyModel().to(rank)
        ddp_model = DDP(model, device_ids=[rank])
        
        loss_fn = nn.MSELoss()
        optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
        
        optimizer.zero_grad()
        outputs = ddp_model(torch.randn(20, 10))
        labels = torch.randn(20, 5).to(rank)
        loss_fn(outputs, labels).backward()
        optimizer.step()
    
        cleanup()
    

    后面有空再继续更。


    1. https://pytorch.org/tutorials/beginner/dist_overview.html ↩︎

    2. https://pytorch.org/tutorials/intermediate/ddp_tutorial.html ↩︎

  • 相关阅读:
    ubuntu install gobgp
    ubunut install golang
    Using GoBGP as an IXP connecting router
    400 行 C 代码实现一个虚拟机
    IPv6 Segment Routing (SRv6)
    How to Install VPP in ubuntu x86 or arm64
    mpls + sr + bgp
    ospf sr
    520了,用32做个简单的小程序
    FPGA设计经验总结
  • 原文地址:https://www.cnblogs.com/YoungF/p/13937784.html
Copyright © 2011-2022 走看看