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 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM