[源碼解析] PyTorch 分布式(4)------分布式應用基礎概念


[源碼解析] PyTorch 分布式(4)------分布式應用基礎概念

0x00 摘要

本文以 PyTorch 官方文檔 https://pytorch.org/tutorials/intermediate/dist_tuto.html 為基礎,對如何編寫分布式進行了介紹,並且加上了自己的理解。

PyTorch 的分布式包(即 torch.distributed)使研究人員和從業人員能夠輕松地跨進程和跨機器集群並行計算。它利用消息傳遞語義來允許每個進程與任何其他進程通信數據。與 multiprocessing ( torch.multiprocessing) 包相反,進程可以使用不同的通信后端,並且不限於在同一台機器上執行。

在這個簡短的教程中,我們將介紹 PyTorch 的分布式包。我們將看到如何設置分布式,使用不同的通信策略,並了解包的一些內部結構。

本系列其他文章如下:

深度學習利器之自動微分(1)

深度學習利器之自動微分(2)

[源碼解析]深度學習利器之自動微分(3) --- 示例解讀

[源碼解析]PyTorch如何實現前向傳播(1) --- 基礎類(上)

[源碼解析]PyTorch如何實現前向傳播(2) --- 基礎類(下)

[源碼解析] PyTorch如何實現前向傳播(3) --- 具體實現

[源碼解析] Pytorch 如何實現后向傳播 (1)---- 調用引擎

[源碼解析] Pytorch 如何實現后向傳播 (2)---- 引擎靜態結構

[源碼解析] Pytorch 如何實現后向傳播 (3)---- 引擎動態邏輯

[源碼解析] PyTorch 如何實現后向傳播 (4)---- 具體算法

[源碼解析] PyTorch 分布式(1)------歷史和概述

[源碼解析] PyTorch 分布式(2) ----- DataParallel(上)

[源碼解析] PyTorch 分布式(3) ----- DataParallel(下)

0x01 基本概念

我們首先介紹一些 torch.distributed 中的關鍵概念,這些概念在編寫程序時至關重要。

  • Node - 物理實例或容器。

  • Worker - 分布訓練環境中的worker。

  • Group(進程組):我們所有進程的子集,用於集體通信等。

    • 默認情況下,只有一個組,一個 job 即為一個組,也即一個 world。
    • 當需要進行更加精細的通信時,可以通過 new_group 接口,使用 world 的子集來創建新組。
  • Backend(后端):進程通信庫。PyTorch 支持NCCL,GLOO,MPI。

  • World_size :進程組中的進程數,可以認為是全局進程個數。

  • Rank :分配給分布式進程組中每個進程的唯一標識符。

    • 從 0 到 world_size 的連續整數,可以理解為進程序號,用於進程間通訊。
    • rank = 0 的主機為 master 節點。
    • rank 的集合可以認為是一個全局GPU資源列表。
  • local rank:進程內的 GPU 編號,非顯式參數,這個一般由 torch.distributed.launch 內部指定。例如, rank = 3,local_rank = 0 表示第 3 個進程內的第 1 塊 GPU。

0x02 設計思路

分布式訓練最主要的問題就是:worker 之間如何通信。為了解決通信問題,PyTorch 引入了幾個概念,我們先分析通信的需求,然后看看 PyTorch 如何通過這幾個概念來滿足需求的。

2.1 通信需求

我們總結一下分布式訓練的具體需求:

  • worker 之間如何互相發現?
  • worker 之間如何進行點對點通信?
  • worker 之間如何做集合通信?
  • 如何把訓練進程和集合通信聯系起來?

接下來圍繞這幾個問題和文檔內容進行分析。

2.2 概念

針對通信需求,PyTorch 提供的幾個概念是:進程組,后端,初始化,Store。

  • 進程組 :DDP是真正的分布式訓練,可以使用多台機器來組成一次並行運算的任務。為了能夠讓 DDP 的各個worker之間通信,PyTorch 設置了進程組這個概念。組是我們所有進程的子集。
    • 看其本質,就是進行通信的進程們。
    • 從代碼來看,給每一個訓練的process 建立一個 通信thread,在后台做通信。比如對於 ProcessGroupMPI,在通信線程添加了一個 queue,做 buffer 和 異步處理。
  • 后端 :后端是一個邏輯上的概念。
    • 本質上后端是一種IPC通信機制。PyTorch 既然能夠在不同的進程間進行通信,那必然是依賴於一些IPC的通信機制,這些通信機制一般是由PyTorch之外的三方實現的,比如后端使用 ProcessGroupMPI 還是 ProcessGroupGloo 。
    • 后端 允許進程通過共享它們的位置來相互通信。對於用戶來說,就是采用哪種方式來進行集合通信,從代碼上看,就是走什么流程(一系列流程).....
  • 初始化 : 雖然有了后端和進程組的概念,但是如何讓 worker 在建立進程組之前發現彼此? 這就需要一種初始化方法來告訴大家傳遞一個信息:如何聯系到其它機器上的進程。目前DDP模塊支持3種初始化方法。
  • Store : 分布式包(distributed package)有一個分布式鍵值存儲服務,這個服務在組中的進程之間共享信息以及初始化分布式包 (通過顯式創建存儲來作為init_method的替代)。
  • 初始化 vs Store
    • 當 MPI 為后端時候, init_method 沒有用處。
    • 在非 MPI 后端時候,如果沒有 store 參數,則使用 init_method 構建一個store,所以最終還是落到了 store 之上

對於這些概念,我們用下圖來看看 DDP 是如何利用這些概念。

假設 DDP 包括兩個worker 做訓練,其中每個 worker 會:

  • 在 Main Thread 之中做訓練,在 Reducer 之中做 allreduce,具體是往 ProcessGroupMPI 的 workerThread_ 發送指令。

  • workerThread_ 會調用 MPI_Allreduce 進行 集合通信,使用的就是 MPI 后端。

0x03 設置

首先,我們需要能夠同時運行多個進程。如果您有權訪問計算集群,您應該咨詢您的本地系統管理員或使用您最喜歡的協調工具(例如, pdshclustershell其他)。本文我們將在一台機器之上使用以下模板來fork多個進程。

"""run.py:"""
#!/usr/bin/env python
import os
import torch
import torch.distributed as dist
import torch.multiprocessing as mp

def run(rank, size):
    """ Distributed function to be implemented later. """
    pass

def init_process(rank, size, fn, backend='gloo'):
    """ Initialize the distributed environment. """
    os.environ['MASTER_ADDR'] = '127.0.0.1'
    os.environ['MASTER_PORT'] = '29500'
    dist.init_process_group(backend, rank=rank, world_size=size)
    fn(rank, size)


if __name__ == "__main__":
    size = 2
    processes = []
    mp.set_start_method("spawn")
    for rank in range(size):
        p = mp.Process(target=init_process, args=(rank, size, run))
        p.start()
        processes.append(p)

    for p in processes:
        p.join()

上述腳本產生兩個進程,每個進程將設置分布式環境,初始化進程組 ( dist.init_process_group),最后執行給定的run 函數。

我們來看看init_process函數。它確保每個進程都能夠使用相同的 IP 地址和端口來與主節點進行協調。請注意,我們使用了gloo后端,但其他后端也可用。這本質上允許進程通過共享它們的位置來相互通信。

0x04 點對點通信

以下是點對點通信的一個示意圖 :發送和接收。

從一個進程到另一個進程的數據傳輸稱為點對點通信。這些是通過sendrecv函數或isendirecv 來實現的。

"""Blocking point-to-point communication."""

def run(rank, size):
    tensor = torch.zeros(1)
    if rank == 0:
        tensor += 1
        # Send the tensor to process 1
        dist.send(tensor=tensor, dst=1)
    else:
        # Receive tensor from process 0
        dist.recv(tensor=tensor, src=0)
    print('Rank ', rank, ' has data ', tensor[0])

在上面的例子中,兩個進程都以零張量開始,然后進程 0 遞增張量並將其發送到進程 1,這樣它們都以 1.0 結束。請注意,進程 1 需要分配內存以存儲它將接收的數據。

還要注意send/recv阻塞實現:兩個進程都停止,直到通信完成。另一方面,isendirecv非阻塞的,在非阻塞情況下腳本繼續執行,方法返回一個Work對象,我們可以選擇在其之上進行 wait()

"""Non-blocking point-to-point communication."""

def run(rank, size):
    tensor = torch.zeros(1)
    req = None
    if rank == 0:
        tensor += 1
        # Send the tensor to process 1
        req = dist.isend(tensor=tensor, dst=1)
        print('Rank 0 started sending')
    else:
        # Receive tensor from process 0
        req = dist.irecv(tensor=tensor, src=0)
        print('Rank 1 started receiving')
    req.wait()
    print('Rank ', rank, ' has data ', tensor[0])

使用isendirecv 時,我們必須小心使用。由於我們不知道數據何時會傳送到其他進程,因此我們不應在req.wait()完成之前修改發送的張量或訪問接收的張量。換句話說,

  • dist.isend()之后寫入tensor,將導致未定義的行為。
  • dist.irecv()之后讀取tensor,將導致未定義的行為。

但是,在req.wait() 執行之后,我們可以保證通信發生了,並且可以保證存儲的tensor[0]值為 1.0。

當我們想要對進程的通信進行細粒度控制時,點對點通信很有用。它們可用於實現復雜巧妙的算法,例如在百度的 DeepSpeechFacebook 的大規模實驗中使用的算法

0x05 集合通信

以下是集合通信的示意圖。

ScatterScatter ScatterGather
ReduceReduce 全減All-Reduce
播送Broadcast 全聚All-Gather

與點對點通信相反,集合是允許一個組中所有進程進行通信的模式。組是我們所有進程的子集。要創建一個組,我們可以將一個rank列表傳遞給dist.new_group(group)。默認情況下,集合通信在所有進程上執行,"所有進程"也稱為world。例如,為了獲得所有過程中所有張量的總和,我們可以使用dist.all_reduce(tensor, op, group)

""" All-Reduce example."""
def run(rank, size):
    """ Simple collective communication. """
    group = dist.new_group([0, 1])
    tensor = torch.ones(1)
    dist.all_reduce(tensor, op=dist.ReduceOp.SUM, group=group)
    print('Rank ', rank, ' has data ', tensor[0])

由於我們想要組中所有張量的總和,因此我們將其 dist.ReduceOp.SUM用作歸約運算符。一般來說,任何可交換的數學運算都可以用作運算符。PyTorch 帶有 4 個這樣開箱即用的運算符,它們都在元素級別工作:

  • dist.ReduceOp.SUM,
  • dist.ReduceOp.PRODUCT,
  • dist.ReduceOp.MAX,
  • dist.ReduceOp.MIN.

除了 dist.all_reduce(tensor, op, group)之外,目前在 PyTorch 中總共實現了以下集合操作。

  • dist.broadcast(tensor, src, group):從 src復制tensor到所有其他進程。
  • dist.reduce(tensor, dst, op, group):施加op於所有 tensor,並將結果存儲在dst.
  • dist.all_reduce(tensor, op, group): 和reduce操作一樣,但結果保存在所有進程中。
  • dist.scatter(tensor, scatter_list, src, group): 復制張量列表scatter_list[i]中第 $ i^{\text{th}}$ 個張量到 第$ i^{\text{th}}$ 個進程。
  • dist.gather(tensor, gather_list, dst, group): 從所有進程拷貝tensor dst
  • dist.all_gather(tensor_list, tensor, group): 在所有進程之上,執行從所有進程拷貝tensor tensor_list的操作。
  • dist.barrier(group):阻止組內所有進程,直到每一個進程都已經進入該function。

0x06 分布式訓練

注意:您可以在此 GitHub 存儲庫中找到本節的示例腳本。

現在我們了解了分布式模塊的工作原理,讓我們用它寫一些有用的東西。我們的目標是復制DistributedDataParallel的功能 。當然,這將是一個教學示例,在實際情況下,您應該使用上面鏈接的經過充分測試和優化的官方版本。

我們想要實現隨機梯度下降的分布式版本。我們的腳本將讓所有進程在他們本地擁有的一批數據上計算本地模型的梯度,然后平均他們的梯度。為了在改變進程數量時確保類似的收斂結果,我們首先必須對我們的數據集進行分區(您也可以使用 tnt.dataset.SplitDataset,而不是下面的代碼段)。

""" Dataset partitioning helper """
class Partition(object):

    def __init__(self, data, index):
        self.data = data
        self.index = index

    def __len__(self):
        return len(self.index)

    def __getitem__(self, index):
        data_idx = self.index[index]
        return self.data[data_idx]

class DataPartitioner(object):

    def __init__(self, data, sizes=[0.7, 0.2, 0.1], seed=1234):
        self.data = data
        self.partitions = []
        rng = Random()
        rng.seed(seed)
        data_len = len(data)
        indexes = [x for x in range(0, data_len)]
        rng.shuffle(indexes)

        for frac in sizes:
            part_len = int(frac * data_len)
            self.partitions.append(indexes[0:part_len])
            indexes = indexes[part_len:]

    def use(self, partition):
        return Partition(self.data, self.partitions[partition])

使用上面的代碼片段,我們現在可以使用以下幾行簡單地對任何數據集進行分區:

""" Partitioning MNIST """
def partition_dataset():
    dataset = datasets.MNIST('./data', train=True, download=True,
                             transform=transforms.Compose([
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.1307,), (0.3081,))
                             ]))
    size = dist.get_world_size()
    bsz = 128 / float(size)
    partition_sizes = [1.0 / size for _ in range(size)]
    partition = DataPartitioner(dataset, partition_sizes)
    partition = partition.use(dist.get_rank())
    train_set = torch.utils.data.DataLoader(partition,
                                         batch_size=bsz,
                                         shuffle=True)
    return train_set, bsz

假設我們有 2 個副本,那么每個進程擁有的train_set 將包括 60000 / 2 = 30000 個樣本。我們還將批量大小除以副本數,以保持整體批量大小為 128。

我們現在可以編寫常見的前向后向優化訓練代碼,並添加一個函數調用來平均我們模型的梯度(以下內容主要受PyTorch MNIST官方示例的啟發)。

""" Distributed Synchronous SGD Example """
def run(rank, size):
    torch.manual_seed(1234)
    train_set, bsz = partition_dataset()
    model = Net()
    optimizer = optim.SGD(model.parameters(),
                          lr=0.01, momentum=0.5)

    num_batches = ceil(len(train_set.dataset) / float(bsz))
    for epoch in range(10):
        epoch_loss = 0.0
        for data, target in train_set:
            optimizer.zero_grad()
            output = model(data)
            loss = F.nll_loss(output, target)
            epoch_loss += loss.item()
            loss.backward()
            average_gradients(model)
            optimizer.step()
        print('Rank ', dist.get_rank(), ', epoch ',
              epoch, ': ', epoch_loss / num_batches)

它仍然需要實現該average_gradients(model)函數,該函數只是接收一個模型並在整個世界(所有訓練進程)中平均其梯度。

""" Gradient averaging. """
def average_gradients(model):
    size = float(dist.get_world_size())
    for param in model.parameters():
        dist.all_reduce(param.grad.data, op=dist.ReduceOp.SUM)
        param.grad.data /= size

現在,我們成功實現了分布式同步 SGD,並且可以在大型計算機集群上訓練任何模型。

注意:雖然最后一句在技術上是正確的,但實現同步 SGD 的生產級實現需要更多技巧。再次使用經過測試和優化的內容

0x07 Ring-Allreduce

作為額外的挑戰,假設我們想要實現 DeepSpeech 的高效 ring allreduce。使用點對點集合可以很容易地實現這一點。

""" Implementation of a ring-reduce with addition. """
def allreduce(send, recv):
   rank = dist.get_rank()
   size = dist.get_world_size()
   send_buff = send.clone()
   recv_buff = send.clone()
   accum = send.clone()

   left = ((rank - 1) + size) % size
   right = (rank + 1) % size

   for i in range(size - 1):
       if i % 2 == 0:
           # Send send_buff
           send_req = dist.isend(send_buff, right)
           dist.recv(recv_buff, left)
           accum[:] += recv_buff[:]
       else:
           # Send recv_buff
           send_req = dist.isend(recv_buff, right)
           dist.recv(send_buff, left)
           accum[:] += send_buff[:]
       send_req.wait()
   recv[:] = accum[:]

在上面的腳本中, allreduce(send, recv) 函數的簽名與 PyTorch 中 函數的簽名略有不同。它接受一個recv 張量並將所有send張量的總和存儲在其中。作為留給讀者的練習,我們的版本與 DeepSpeech 中的版本之間仍有一個區別:它們的實現將梯度張量分成,以便最佳地利用通信帶寬(提示: torch.chunk)。

0x08 高級主題

由於要涵蓋的內容很多,因此本節分為兩個小節:

  1. 通信后端:我們學習如何使用 MPI 和 Gloo 進行 GPU-GPU 通信。
  2. 初始化方法:我們了解在dist.init_process_group()之中如何建立初始協調階段。

8.1 通信后端

torch.distributed最優雅的方面之一是它能夠在不同的后端之上抽象和構建。如前所述,目前在 PyTorch 中實現了三個后端:Gloo、NCCL 和 MPI。它們每個都有不同的規格和權衡,具體取決於所需的用例。可在此處找到支持功能的比較表 。

以下信息來自 https://pytorch.org/docs/stable/distributed.html。

8.1.1 后端種類

torch.distributed支持三個內置后端,每個后端都有不同的功能。下表顯示了哪些函數可用於 CPU / CUDA 張量。

Backend gloo mpi nccl
Device CPU GPU CPU GPU CPU GPU
send ?
recv ?
broadcast ?
all_reduce ?
reduce ?
all_gather ?
gather ?
scatter ?
reduce_scatter
all_to_all ?
barrier ?

PyTorch 分布式包支持 Linux(穩定)、MacOS(穩定)和 Windows(原型)。對於 Linux,默認情況下,Gloo 和 NCCL 后端包含在分布式 PyTorch 中(僅在使用 CUDA 構建時才支持NCCL)。MPI是一個可選的后端,只有從源代碼構建PyTorch時才能包含它(例如,在安裝了MPI的主機上編譯PyTorch)。

8.1.2 使用哪個后端?

過去,人們經常會問:“我應該使用哪個后端"?下面是答案:

  • 經驗法則
    • 使用 NCCL 后端進行分布式GPU訓練
    • 使用 Gloo 后端進行分布式CPU訓練。
  • 如果 GPU 主機 具有 InfiniBand 互連
    • 使用 NCCL,因為它是目前唯一支持 InfiniBand 和 GPUDirect 的后端。
  • 如果 GPU 主機 具有以太網互連
    • 使用 NCCL,因為它目前提供了最好的分布式 GPU 訓練性能,特別是對於多進程單節點或多節點分布式訓練。如果您在使用 NCCL 時遇到任何問題,請使用 Gloo 作為后備選項。(請注意,對於 GPU訓練,Gloo 目前的運行速度比 NCCL 慢。)
  • 具有 InfiniBand 互連的 CPU 主機
    • 如果您的 InfiniBand 已啟用 IP over IB,請使用 Gloo,否則,請改用 MPI。我們計划在即將發布的版本中添加對 Gloo 的 InfiniBand 支持。
  • 具有以太網互連的 CPU 主機
    • 使用 Gloo,除非您有特定原因一定需要使用 MPI。

8.1.3 Gloo 后端

到目前為止,Gloo 后端 已經得到了廣泛使用。它作為開發平台非常方便,因為它包含在預編譯的 PyTorch 二進制文件中,並且適用於 Linux(自 0.2 起)和 macOS(自 1.3 起)。它支持 CPU 上的所有點對點和集合操作,以及 GPU 上的所有集合操作。但是其針對 CUDA 張量集合運算的實現不如 NCCL 后端所優化的那么好。

您肯定已經注意到,如果您的模型使用 GPU ,我們的分布式 SGD 示例將不起作用。為了使用多個GPU,我們也做如下修改:

  1. device = torch.device("cuda:{}".format(rank))
  2. model = Net() \(\rightarrow\) model = Net().to(device)
  3. data, target = data.to(device), target.to(device)

通過上述修改,我們的模型現在可以在兩個 GPU 上進行訓練,您可以使用.watch nvidia-smi來監控使用情況。

8.1.4 MPI后端

消息傳遞接口 (MPI) 是來自高性能計算領域的標准化工具。它允許進行點對點和集體通信,並且是 torch.distributed 的主要靈感來源。目前存在多種 MPI 實現(例如 Open-MPIMVAPICH2Intel MPI),每一種都針對不同目的進行了優化。使用 MPI 后端的優勢在於 MPI 在大型計算機集群上的廣泛可用性和高度優化。最近的一些 實現還能夠利用 CUDA IPC 和 GPU Direct 技術,這樣可以避免通過 CPU 進行內存復制。

不幸的是,PyTorch 的二進制文件不能包含 MPI 實現,我們必須手動重新編譯它。幸運的是,這個過程相當簡單,因為在編譯時,PyTorch 會自行 尋找可用的 MPI 實現。以下步驟通過從源碼安裝 PyTorch安裝 MPI 后端。

  1. 創建並激活您的 Anaconda 環境,依據 the guide 安裝所有繼先決需求,但 運行python setup.py install
  2. 選擇並安裝您最喜歡的 MPI 實現。請注意,啟用 CUDA-aware MPI 可能需要一些額外的步驟。在我們的例子中,我們將使用沒有GPU 支持的Open-MPI : conda install -c conda-forge openmpi
  3. 現在,轉到您克隆的 PyTorch 存儲庫並執行 .python setup.py install

為了測試我們新安裝的后端,需要進行一些修改。

  1. if __name__ == '__main__': 替換為init_process(0, 0, run, backend='mpi')
  2. 運行 mpirun -n 4 python myscript.py

這些更改的原因是 MPI 需要在生成進程之前創建自己的環境。MPI 還將產生自己的進程並執行初始化方法中描述的握手操作,從而使init_process_groupranksize 參數變得多余。這實際上非常強大,因為您可以傳遞額外的參數來mpirun為每個進程定制計算資源(例如每個進程的核心數、將機器手動分配到特定rank等等)。這樣做,您應該獲得與其他通信后端相同的熟悉輸出。

8.1.5 NCCL后端

NCCL后端提供了一個優化的,針對對CUDA張量實現的集合操作。如果您僅將 CUDA 張量用於集合操作,請考慮使用此后端以獲得最佳性能。NCCL 后端包含在具有 CUDA 支持的預構建二進制文件中。

NCCL 的全稱為 Nvidia 聚合通信庫(NVIDIA Collective Communications Library),是一個可以實現多個 GPU、多個結點間聚合通信的庫,在 PCIe、Nvlink、InfiniBand 上可以實現較高的通信速度。

NCCL 高度優化和兼容了 MPI,並且可以感知 GPU 的拓撲,促進多 GPU 多節點的加速,最大化 GPU 內的帶寬利用率,所以深度學習框架的研究員可以利用 NCCL 的這個優勢,在多個結點內或者跨界點間可以充分利用所有可利用的 GPU。

NCCL 對 CPU 和 GPU 均有較好支持,且 torch.distributed 對其也提供了原生支持。

對於每台主機均使用多進程的情況,使用 NCCL 可以獲得最大化的性能。每個進程內,不許對其使用的 GPUs 具有獨占權。若進程之間共享 GPUs 資源,則可能導致 deadlocks。

8.2 初始化方法

為了完成本教程,讓我們談談我們調用的第一個函數 dist.init_process_group(backend, init_method)。我們將介紹負責每個進程之間初始協調步驟的不同初始化方法。這些方法允許您定義如何完成這種協調。根據您的硬件設置,這些方法之一自然應該比其他方法更合適。除了以下部分,您還應該查看官方文檔

環境變量

在本教程中,我們一直在使用環境變量初始化方法 。此方法將從環境變量中讀取配置,允許完全自定義獲取信息的方式。通過在所有機器上設置以下四個環境變量,所有進程都可以正常連接到master(就是 rank 0 進程),獲取其他進程的信息,並最終與它們握手。

  • MASTER_PORT:承載等級 0 進程的機器上的一個空閑端口。
  • MASTER_ADDR:承載等級 0 進程的機器上的 IP 地址。
  • WORLD_SIZE: 進程總數,因此master知道要等待多少worker。
  • RANK: 每個進程的rank,所以他們會知道自己是否是master。

共享文件系統

共享文件系統要求所有進程都可以訪問共享文件系統,並將通過共享文件協調它們。這意味着每個進程都將打開文件,寫入其信息,並等待每個人都這樣做。之后,所有所需的信息都將可供所有流程使用。為了避免競爭條件,文件系統必須通過fcntl支持鎖定 。

dist.init_process_group(
    init_method='file:///mnt/nfs/sharedfile',
    rank=args.rank,
    world_size=4)

TCP

TCP 初始化方式是通過提供rank 0進程的IP和端口來實現的,在這里,所有worker都可以連接到等級為 0 的進程並交換有關如何相互聯系的信息。

dist.init_process_group(
    init_method='tcp://10.1.1.20:23456',
    rank=args.rank,
    world_size=4)

0xFF 參考

https://pytorch.org/docs/stable/distributed.html

https://pytorch.org/tutorials/intermediate/rpc_param_server_tutorial.html

https://m.w3cschool.cn/pytorch/pytorch-me1q3bxf.html

https://pytorch.org/tutorials/beginner/dist_overview.html

https://pytorch.org/tutorials/intermediate/model_parallel_tutorial.html

https://pytorch.org/tutorials/intermediate/ddp_tutorial.html

https://pytorch.org/tutorials/intermediate/dist_tuto.html

https://pytorch.org/tutorials/intermediate/rpc_tutorial.html

https://pytorch.org/tutorials/intermediate/dist_pipeline_parallel_tutorial.html

https://pytorch.org/tutorials/intermediate/rpc_async_execution.html

https://pytorch.org/tutorials/advanced/rpc_ddp_tutorial.html

https://pytorch.org/tutorials/intermediate/pipeline_tutorial.html

https://pytorch.org/tutorials/advanced/ddp_pipeline.html

https://pytorch.org/docs/master/rpc/distributed_autograd.html#distributed-autograd-design

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

https://pytorch.org/tutorials/intermediate/dist_tuto.html


免責聲明!

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



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