[pytorch]單多機下多GPU下分布式負載均衡訓練


說明

在前面講模型加載和保存的時候,在多GPU情況下,實際上是挖了坑的,比如在多GPU加載時,GPU的利用率是不均衡的,而當時沒詳細探討這個問題,今天來詳細地討論一下。

問題

在訓練的時候,如果GPU資源有限,而數據量和模型大小較大,那么在單GPU上運行就會極其慢的訓練速度,此時就要使用多GPU進行模型訓練了,在pytorch上實現多GPU訓練實際上十分簡單:

只需要將模型使用nn.DataParallel進行裝飾即可。

model = nn.DataParallel(model,device_ids=range(torch.cuda.device_count()))

但是問題在於這樣直接處理后的模型的負載可能是不均衡的,因為在不同的GPU上進行運算,而最后的loss計算過程是要合並到主GPU上,這樣主GPU的的占用率將比較高,而其余GPU的利用率則沒有那么高。

解決思路

  1. 一種比較簡單的解決方法是將模型計算loss的過程封裝在model里,這樣每個GPU forward的時候就會計算到對應的loss,當然缺陷在於這樣每次得到的loss都是一個數組,需要另外mean或者sum處理一下。
class FullModel(nn.Module):
  def __init__(self, model, loss):
    super(FullModel, self).__init__()
    self.model = model
    self.loss = loss

  def forward(self, targets, *inputs):
    outputs = self.model(*inputs)
    loss = self.loss(outputs, targets)
    return torch.unsqueeze(loss,0),outputs

在上述的代碼中,構建了另外一個包含model和loss的殼,在殼里計算loss的值,需要注意的是,在進行DataParallel時,也需要對這個並行,而到了收集loss的時候,則使用loss的和:

loss,_ = model(gt,input)
loss = loss.sum()
optimizer.zero_grad()
loss.backward()
optimizer.step()

已經有人造了這個輪子,並開源了出來,可以參考:https://github.com/zhanghang1989/PyTorch-Encoding 代碼庫,整個寫法依然沒有太大的變化:

from utils.encoding import DataParallelModel, DataParallelCriterion
model = DataParallelModel(model)
criterion = DataParallelCriterion(criterion)
  1. 通過distributedDataparallel來實現

實際上官方考慮過負載不均衡的問題,在文檔中也推薦使用distributedDataparallel(ddp)進行訓練,盡管ddp是用來解決不同機器的分布式訓練問題的。

This is the highly recommended way to useDistributedDataParallel, with multiple processes, each of which operates on a single GPU. This is currently the fastest approach to do data parallel training using PyTorch and applies to both single-node(multi-GPU) and multi-node data parallel training. It is proven to be significantly faster thantorch.nn.DataParallelfor single-node multi-GPU data parallel training.

ddp使用起來比DataParallel更快,數據也更均衡,但是缺點是配置起來相對要麻煩一些。

# 初始化使用的后端
torch.distributed.init_process_group(backend="nccl")

# 對數據進行划分
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)
test_sampler = torch.utils.data.distributed.DistributedSampler(test_dataset)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=n_worker, pin_memory=True, sampler=train_sampler)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=n_worker, pin_memory=True, sampler=test_sampler) # sampler和shuffle不能同時使用

model=torch.nn.parallel.DistributedDataParallel(model)

注意:需要注意的是,盡量設定pin_memory參數為true,該參數是鎖存操作,使用會加快數據讀取速度,但是此時要限定內存的大小是要使用顯存的兩倍
以上就配置好了,經過測試,使用ddp的訓練時間比DataParallel快一倍。
在運行的時候,使用以下命令進行分布式訓練: python -m torch.distributed.launch --nproc_per_node=NUM_GPUS_YOU_HAVE yourscript.py

引用

  1. https://discuss.pytorch.org/t/dataparallel-imbalanced-memory-usage/22551/20
  2. https://zhuanlan.zhihu.com/p/95700549


免責聲明!

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



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