Pytorch中的分布式神經網絡訓練

2021-01-07 deephub

隨著深度學習的多項進步,複雜的網絡(例如大型transformer 網絡,更廣更深的Resnet等)已經發展起來,從而需要了更大的內存空間。 經常,在訓練這些網絡時,深度學習從業人員需要使用多個GPU來有效地訓練它們。 在本文中,我將向您介紹如何使用PyTorch在GPU集群上設置分布式神經網絡訓練。

通常,分布式訓練會在有一下兩種情況。

在GPU之間拆分模型:如果模型太大而無法容納在單個GPU的內存中,則需要在不同GPU之間拆分模型的各個部分。跨GPU進行批量拆分數據。當mini-batch太大而無法容納在單個GPU的內存中時,您需要將mini-batch拆分到不同的GPU上。跨GPU的模型拆分

跨GPU拆分模型非常簡單,不需要太多代碼更改。 在設置網絡本身時,可以將模型的某些部分移至特定的GPU。 之後,在通過網絡轉發數據時,數據也需要移動到相應的GPU。 下面是執行相同操作的PyTorch代碼段。

from torch import nnclass Network(nn.Module):def __init__(self, split_gpus=False): super().__init__() self.module1 = ... self.module2 = ... self.split_gpus = split_gpus if split_gpus: #considering only two gpus self.module1.cuda(0) self.module2.cuda(1) def forward(self, x): if self.split_gpus: x = x.cuda(0) x = self.module1(x) if self.split_gpus: x = x.cuda(1) x = self.module2(x) return x

跨GPU的數據拆分

有3種在GPU之間拆分批處理的方法。

積累梯度使用nn.DataParallel使用nn.DistributedDataParallel積累梯度

在GPU之間拆分批次的最簡單方法是累積梯度。 假設我們要訓練的批處理大小為256,但是一個GPU內存只能容納32個批處理大小。 我們可以執行8(= 256/32)個梯度下降迭代而無需執行優化步驟,並繼續通過loss.backward()步驟添加計算出的梯度。 一旦我們累積了256個數據點的梯度,就執行優化步驟,即調用optimizer.step()。 以下是用於實現累積漸變的PyTorch代碼段。

TARGET_BATCH_SIZE, BATCH_FIT_IN_MEMORY = 256, 32accumulation_steps = int(TARGET_BATCH_SIZE / BATCH_FIT_IN_MEMORY)network.zero_grad() # Reset gradients tensorsfor i, (imgs, labels) in enumerate(dataloader):preds = network(imgs) # Forward pass loss = loss_function(preds, labels) # Compute loss function loss = loss / accumulation_steps # Normalize our loss (if averaged) loss.backward() # Backward pass if (i+1) % accumulation_steps == 0: # Wait for several backward steps optim.step() # Perform an optimizer step network.zero_grad() # Reset gradients tensors

優點: 不需要多個GPU即可進行大批量訓練。 即使使用單個GPU,此方法也可以進行大批量訓練。

缺點: 比在多個GPU上並行訓練要花費更多的時間。

使用nn.DataParallel

如果您可以訪問多個GPU,則將不同的批處理拆分分配給不同的GPU,在不同的GPU上進行梯度計算,然後累積梯度以執行梯度下降是很有意義的。

多GPU下的forward和backward

基本上,給定的輸入通過在批處理維度中分塊在GPU之間進行分配。 在前向傳遞中,模型在每個設備上複製,每個副本處理批次的一部分。 在向後傳遞過程中,將每個副本的梯度求和以生成最終的梯度,並將其應用於主gpu(上圖中的GPU-1)以更新模型權重。 在下一次迭代中,主GPU上的更新模型將再次複製到每個GPU設備上。

在PyTorch中,只需要一行就可以使用nn.DataParallel進行分布式訓練。 該模型只需要包裝在nn.DataParallel中。

model = torch.nn.DataParallel(model)......loss = ...loss.backward()

優點:並行化多個GPU上的NN訓練,因此與累積梯度相比,它減少了訓練時間。因為代碼更改很少,所以適合快速原型製作。

缺點:nn.DataParallel使用單進程多線程方法在不同的GPU上訓練相同的模型。 它將主進程保留在一個GPU上,並在其他GPU上運行不同的線程。 由於python中的線程存在GIL(全局解釋器鎖定)問題,因此這限制了完全並行的分布式訓練設置。

使用DistributedDataParallel

與nn.DataParallel不同,DistributedDataParallel在GPU上生成單獨的進程進行多重處理,並利用GPU之間通信實現的完全並行性。但是,設置DistributedDataParallel管道比nn.DataParallel更複雜,需要執行以下步驟(但不一定按此順序)。

將模型包裝在torch.nn.Parallel.DistributedDataParallel中。

設置數據加載器以使用distributedSampler在所有GPU之間高效地分配樣本。 Pytorch為此提供了torch.utils.data.Distributed.DistributedSampler。設置分布式後端以管理GPU的同步。 torch.distributed.initprocessgroup(backend ='nccl')。

pytorch提供了用於分布式通訊後端(nccl,gloo,mpi,tcp)。根據經驗,一般情況下使用nccl可以通過GPU進行分布式訓練,而使用gloo可以通過CPU進行分布式訓練。在此處了解有關它們的更多信息https://pytorch.org/tutorials/intermediate/dist_tuto.html#advanced-topics

在每個GPU上啟動單獨的進程。同樣使用torch.distributed.launch實用程序功能。假設我們在群集節點上有4個GPU,我們希望在這些GPU上用於設置分布式培訓。可以使用以下shell命令來執行此操作。

python -m torch.distributed.launch --nproc_per_node=4 --nnodes=1 --node_rank=0--master_port=1234 train.py <OTHER TRAINING ARGS>

在設置啟動腳本時,我們必須在將運行主進程並用於與其他GPU通信的節點上提供一個空閒埠(在這種情況下為1234)。

以下是涵蓋所有步驟的完整PyTorch要點。

import argparseimport torchfrom torch.utils.data.distributed import DistributedSamplerfrom torch.utils.data import DataLoader#prase the local_rank argument from command line for the current processparser = argparse.ArgumentParser()parser.add_argument("--local_rank", default=0, type=int)args = parser.parse_args()#setup the distributed backend for managing the distributed trainingtorch.distributed.init_process_group('nccl')#Setup the distributed sampler to split the dataset to each GPU.dist_sampler = DistributedSampler(dataset)dataloader = DataLoader(dataset, sampler=dist_sampler)#set the cuda device to a GPU allocated to current process .device = torch.device('cuda', args.local_rank)model = model.to(device)model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank],output_device=args.local_rank)#Start training the model normally.for inputs, labels in dataloader: inputs = inputs.to(device) labels = labels.to(device) preds = model(inputs) loss = loss_fn(preds, labels) loss.backward() optimizer.step()

請注意,上述實用程序調用是針對GPU集群上的單個節點的。 此外,如果要使用多節點設置,則必須在選擇啟動實用程序時選擇一個節點作為主節點,並提供master_addr參數,如下所示。 假設我們有2個節點,每個節點有4個GPU,第一個IP位址為「 192.168.1.1」的節點是主節點。 我們必須分別在每個節點上啟動啟動腳本,如下所示。

在第一個節點上運行

python -m torch.distributed.launch --nproc_per_node=4 --nnodes=1 --node_rank=0--master_addr="192.168.1.1" --master_port=1234 train.py <OTHER TRAINING ARGS>

在第二個節點上,運行

python -m torch.distributed.launch --nproc_per_node=4 --nnodes=1 --node_rank=1--master_addr="192.168.1.1" --master_port=1234 train.py <OTHER TRAINING ARGS>

其他實用程序功能:

在評估模型或生成日誌時,需要從所有GPU收集當前批次統計信息,例如損失,準確率等,並將它們在一臺機器上進行整理以進行日誌記錄。 PyTorch提供了以下方法,用於在所有GPU之間同步變量。

torch.distributed.gather(inputtensor,collectlist,dst):從所有設備收集指定的inputtensor並將它們放置在collectlist中的dst設備上。torch.distributed.allgather(tensorlist,inputtensor):從所有設備收集指定的inputtensor並將其放置在所有設備上的tensor_list變量中。torch.distributed.reduce(inputtensor,dst,reduceop = ReduceOp.SUM):收集所有設備的input_tensor並使用指定的reduce操作(例如求和,均值等)進行縮減。最終結果放置在dst設備上。torch.distributed.allreduce(inputtensor,reduce_op = ReduceOp.SUM):與reduce操作相同,但最終結果被複製到所有設備。有關參數和方法的更多詳細信息,請閱讀torch.distributed軟體包。 https://pytorch.org/docs/stable/distributed.html

例如,以下代碼從所有GPU提取損失值,並將其減少到主設備(cuda:0)。

#In continuation with distributedDataParallel.py abovedef get_reduced_loss(loss, dest_device):loss_tensor = loss.clone() torch.distributed.reduce(loss_tensor, dst=dest_device) return loss_tensorif args.local_rank==0: loss_tensor = get_reduced_loss(loss.detach(), 0) print(f'Current batch Loss = {loss_tensor.item()}'

優點:相同的代碼設置可用於單個GPU,而無需任何代碼更改。 單個GPU設置僅需要具有適當設置的啟動腳本。

缺點: BatchNorm之類的層在其計算中使用了整個批次統計信息,因此無法僅使用一部分批次在每個GPU上獨立進行操作。 PyTorch提供SyncBatchNorm作為BatchNorm的替換/包裝模塊,該模塊使用跨GPU劃分的整個批次計算批次統計信息。 請參閱下面的示例代碼以了解SyncBatchNorm的用法。

network = .... #some network with BatchNorm layers in itsync_bn_network = nn.SyncBatchNorm.convert_sync_batchnorm(network)ddp_network = nn.parallel.DistributedDataParallel(sync_bn_network, device_ids=[args.local_rank], output_device=args.local_rank)

總結

要在GPU之間拆分模型,請將模型拆分為submodules,然後將每個submodule推送到單獨的GPU。要在GPU上拆分批次,請使用累積梯度nn.DataParallel或nn.DistributedDataParallel。為了快速進行原型製作,可以首選nn.DataParallel。為了訓練大型模型並利用跨多個GPU的完全並行訓練,應使用nn.DistributedDataParallel。在使用nn.DistributedDataParallel時,用nn.SyncBatchNorm替換或包裝nn.BatchNorm層。作者:Nilesh Vijayrania

deephub翻譯組

相關焦點

  • Pytorch中的分布式神經網絡訓練|pytorch|bat|拆分|調用_網易訂閱
    隨著深度學習的多項進步,複雜的網絡(例如大型transformer 網絡,更廣更深的Resnet等)已經發展起來,從而需要了更大的內存空間。 經常,在訓練這些網絡時,深度學習從業人員需要使用多個GPU來有效地訓練它們。 在本文中,我將向您介紹如何使用PyTorch在GPU集群上設置分布式神經網絡訓練。
  • 用PyTorch對Leela Zero進行神經網絡訓練
    代碼:https://github.com/yukw777/leela-zero-pytorchLeela Zero第一步是找出Leela Zero神經網絡的內部工作原理。我大量引用了Leela Zero的文檔和它的Tensorflow訓練管道。
  • 用PyTorch對Leela Zero進行神經網絡訓練
    代碼:https://github.com/yukw777/leela-zero-pytorchLeela Zero第一步是找出Leela Zero神經網絡的內部工作原理。我大量引用了Leela Zero的文檔和它的Tensorflow訓練管道。
  • PyTorch 0.2發布:更多NumPy特性,高階梯度、分布式訓練等
    這一版本引入了NumPy風格的Broadcasting、Advanced Indexing,增加了高階梯度和分布式PyTorch。PyTorch的GitHub新版發布說明中介紹了0.2版的以下新特性:NumPy風格的Tensor BroadcastingBroadcasting是NumPy在算數運算中處理不同形狀數組的一種方式,在特定條件下,比較小的數組會通過比較大的數組進行「廣播」,來獲得相應的形狀。
  • 使用PyTorch Lightning自動訓練深度神經網絡
    如果你想知道我的原因,看看下面這篇文章:https://medium.com/swlh/why-i-switch-from-keras-to-pytorch-e48922f5846。由於我一直在使用PyTorch,所以我需要犧牲在Keras中只用幾行簡單的行代碼就可以進行訓練的樂趣,而編寫自己的訓練代碼。
  • PyTorch1.7發布,支持CUDA11分布式訓練
    該版本增添了很多新特性,如支持 CUDA 11、Windows 分布式訓練、增加了支持快速傅立葉變換(FFT)的新型 API 等。(DDP)和基於遠程過程調用(RPC)的分布式訓練的重要更新。此外,一些特性也更新為穩定版,包括自定義 C++ 類、內存分析器、通過自定義類張量對象進行擴展、RPC 中的用戶異步函數,以及 torch.distributed 中的許多其他特性(如 Per-RPC 超時、DDP dynamic bucketing、RRef helper)。
  • 在PyTorch中使用進行多GPU分布式模型訓練
    分布式訓練是使用多個GPU和/或多個機器訓練深度學習模型的技術。 分布式訓練作業使您能夠克服單GPU內存瓶頸,通過同時利用多個GPU來開發更大,功能更強大的模型。這篇文章是使用torch.nn.parallel.DistributedDataParallel API在純PyTorch中進行分布式訓練的簡介。 我們會:1.
  • PyTorch 1.7發布,支持CUDA 11、Windows分布式訓練
    該版本增添了很多新特性,如支持 CUDA 11、Windows 分布式訓練、增加了支持快速傅立葉變換(FFT)的新型 API 等。的分布式訓練的重要更新。此外,一些特性也更新為穩定版,包括自定義 C++ 類、內存分析器、通過自定義類張量對象進行擴展、RPC 中的用戶異步函數,以及 torch.distributed 中的許多其他特性(如 Per-RPC 超時、DDP dynamic bucketing、RRef helper)。
  • PyTorch 1.7發布,支持CUDA 11、Windows分布式訓練
    該版本增添了很多新特性,如支持 CUDA 11、Windows 分布式訓練、增加了支持快速傅立葉變換(FFT)的新型 API 等。PyTorch 1.7 版本包含很多新的 API,如支持 NumPy 兼容的 FFT 操作、性能分析工具,以及對基於分布式數據並行(DDP)和基於遠程過程調用(RPC)的分布式訓練的重要更新。
  • 在PyTorch中建立神經網絡的三種方法
    這裡的關鍵是,您需要告訴PyTorch在您的網絡中什麼是可變的或可優化的,以便PyTorch知道如何在您的網絡中執行梯度下降。讓我們看看在低層PyTorch中人們是如何處理這個問題的:2.擴展torch.nn.Model類在實踐中,我們大多數人可能會使用預定義的層和激活函數來訓練我們的網絡。如果這樣則有兩種方法。
  • PyTorch中使用DistributedDataParallel進行多GPU分布式模型訓練
    雖然GPT是一個比較極端的例子但是各種SOTA模型正在推動越來越大的模型進入生產應用程式,這裡的最大挑戰是使用GPU卡在合理的時間內完成模型訓練工作的能力。為了解決這些問題,從業者越來越多地轉向分布式訓練。 分布式訓練是使用多個GPU和/或多個機器訓練深度學習模型的技術。
  • 初學AI神經網絡應該選擇Keras或是Pytorch框架?
    keras是神經網絡的一個模型計算框架,嚴格來說不是神經網絡框架。本身沒有重量級計算,它使用其他AI框架作為計算後臺,傻瓜式的使用。它的計算後臺還支持 Theano、CNTK(微軟的一個AI計算後臺)等,也就是說keras是多個計算後臺的門面。官方設計哲學為Simple. Flexible.
  • 分布式入門,怎樣用PyTorch實現多GPU分布式訓練
    這篇文章旨在闡述訓練大規模深度學習模型時的分布式計算思想。具體來講,本文首先介紹了分布式計算的基本概念,以及分布式計算如何用於深度學習。然後,列舉了配置處理分布式應用的環境的標準需求(硬體和軟體)。最後,為了提供親身實踐的經驗,本文從理論角度和實現的角度演示了一個用於訓練深度學習模型的分布式算法(同步隨機梯度下降,synchronous SGD)。
  • PyTorch 1.4 發布:支持 Java 和分布式模型並行訓練
    更新日誌顯示,此版本包含了 1500 多次提交,並在 JIT、ONNX、分布式、性能和 Eager 前端等方面進行了改進,以及對於移動版本和量化方面的實驗領域也進行了改進。1.4 還增加了新的實驗性功能,其中包括基於 RPC 的分布式模型並行訓練以及對 Java 的語言綁定。
  • 代碼詳解:用Pytorch訓練快速神經網絡的9個技巧
    估計你還在用32位精度或*GASP(一般活動仿真語言)*訓練,甚至可能只在單GPU上訓練。如果市面上有99個加速指南,但你可能只看過1個?(沒錯,就是這樣)。但這份終極指南,會一步步教你清除模型中所有的(GP模型)。不要讓你的神經網絡變成這樣。(圖片來源:Monsters U)這份指南的介紹從簡單到複雜,一直介紹到你可以完成的大多數PITA修改,以充分利用你的網絡。
  • PyTorch上也有Keras了,訓練模型告別Debug,只需專注數據和邏輯
    魚羊 發自 凹非寺量子位 報導 | 公眾號 QbitAI在開始一個新的機器學習項目時,難免要重新編寫訓練循環,加載模型,分布式訓練……然後在Debug的深淵裡看著時間譁譁流逝,而自己離項目核心還有十萬八千裡。
  • PyTorch可視化理解卷積神經網絡
    如今,機器已經能夠在理解、識別圖像中的特徵和對象等領域實現99%級別的準確率。生活中,我們每天都會運用到這一點,比如,智慧型手機拍照的時候能夠識別臉部、在類似於谷歌搜圖中搜索特定照片、從條形碼掃描文本或掃描書籍等。造就機器能夠獲得在這些視覺方面取得優異性能可能是源於一種特定類型的神經網絡——卷積神經網絡(CNN)。
  • PyTorch 1.0 正式版發布了!
    完整課程可在 Udacity 網站上免費獲取,之後開發者可以在更高級的 AI 納米學位項目中繼續 PyTorch 學習。除了在線教育課程,fast.ai 等組織還提供過軟體庫,支持開發者學習如何使用 PyTorch 構建神經網絡。
  • 在AWS上使用GPU實現分布式神經網絡
    他們使用強大而廉價的GPU代替大型集群的CPU,使用此體系結構僅用3臺機器在幾天內就訓練出比原來大6.5倍的模型。在另一項研究中,Schwenk等人表明,在GPU上訓練這些模型可以大大提高性能,即使和高端的多核CPU相比。 考慮到我們在雲計算領域的技術和領導能力,我們利用GPU和AWS的優勢,實現大規模神經網絡訓練系統。
  • 未雨綢繆:隨手保存 PyTorch 訓練模型
    >     我們都知道,訓練一個深度神經網絡是需要挺長的時間的  教你如何將未訓練完成的 PyTorch 模型保存下來,而且不只是模型,訓練過程中的優化器(optimizer),迭代數(epochs),以及正確率(score)等等,都可以以文件的形式保存下來,並在未來繼續加載訓練。  好  下面重點來啦!