pytorch 分散式訓練初探

pytorch 分散式訓練初探

來自專欄 NeuronTalk神經雜談6 人贊了文章

pytorch 分散式訓練初探

為什麼需要分散式

眾所周知,深度神經網路發展到現階段,離不開GPU和數據。經過這麼多年的積累,GPU的計算能力越來越強,數據也積累的越來越多,大家會發現在現有的單機單卡或者單機多卡上很難高效地復現模型,甚至對於有些新的數據集來講,單機訓練簡直就是噩夢。

DatasetImagesMS COCO115,000Open Image dataset v41,740,000

為什麼單機8卡也會是噩夢呢?我們拿COCO和Google最近Release出來的Open Image dataset v4來做比較,訓練一個resnet152的檢測模型,在COCO上大概需要40個小時,而在OIDV4上大概需要40天,這還是在各種超參數正確的情況下,如果加上調試的時間,可能一個模型調完就該過年了吧。

所以這個時候我們需要分散式。

pytorch 分散式簡介

PyTorch分散式功能在0.4版本中得到大幅完善,它允許在多台機器之間交換Tensors,這樣就可以通過多台機器和更大的minibatch擴展網路訓練。

torch.distributed provides an MPI-like interface for exchanging tensor data across multi-machine networks. It supports a few different backends and initialization methods.

Currently torch.distributed supports four backends, each with different capabilities. The table below shows which functions are available for use with CPU / CUDA tensors. MPI supports cuda only if the implementation used to build PyTorch supports it.

pytorch文檔里有這麼一段介紹,但其實可選的只有Gloo。它是一個類似MPI的通信庫,你不需要考慮內存數據的拷貝,只需要實現邏輯就可以。

這裡引入了一個新的函數model = torch.nn.parallel.DistributedDataParallel(model)為的就是支持分散式模式

不同於原來在multiprocessing中的model = torch.nn.DataParallel(model,device_ids=[0,1,2,3]).cuda()函數,這個函數只是實現了在單機上的多GPU訓練,根據官方文檔的說法,甚至在單機多卡的模式下,新函數表現也會優於這箇舊函數。

這裡要提到兩個問題:

  • 每個進程都有自己的Optimizer同時每個迭代中都進行完整的優化步驟,雖然這可能看起來是多餘的,但由於梯度已經聚集在一起並跨進程平均,因此對於每個進程都是相同的,這意味著不需要參數廣播步驟,從而減少了在節點之間傳輸張量tensor所花費的時間。
  • 另外一個問題是Python解釋器的,每個進程都包含一個獨立的Python解釋器,消除了來自單個Python進程中的多個執行線程,模型副本或GPU的額外解釋器開銷和「GIL-thrashing」。 這對於大量使用Python運行時的模型尤其重要。

初始化

torch.distributed.init_process_group(backend, init_method=env://, **kwargs)

參數說明:

  • backend(str): 後端選擇,包括上面那幾種 tcp mpi gloo
  • init_method(str,optional): 用來初始化包的URL, 我理解是一個用來做並發控制的共享方式
  • world_size(int, optional): 參與這個工作的進程數
  • rank(int,optional): 當前進程的rank
  • group_name(str,optional): 用來標記這組進程名的

解釋一下init_method()也有這三種方式,具體可參看pytorch.org/docs/master

  • file:// 共享文件系統(要求所有進程可以訪問單個文件系統)有共享文件系統可以選擇
  • tcp:// IP組播(要求所有進程都在同一個網路中)比較好理解,不過需要手動設置rank
  • env:// 環境變數(需要您手動分配等級並知道所有進程可訪問節點的地址)默認是這個

分散式 Hello World

github.com/pytorch/exam

這裡,常規的操作就不多敘述了,主要講一下和分散式相關的代碼部分。

parser.add_argument(--world-size, default=2, type=int, help=number of distributed processes)parser.add_argument(--dist-url, default=tcp://172.16.1.186:2222, type=str, help=url used to set up distributed training)parser.add_argument(--dist-backend, default=gloo, type=str, help=distributed backend)parser.add_argument(--dist-rank, default=0, type=int, help=rank of distributed processes)

這幾個是必要的參數設置,其中最後一個是官網沒有的

if args.distributed: dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url,world_size=args.world_size,rank=args.dist_rank)

這個是分散式的初始化,同樣,最後添加一個rank

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

這裡,把我們平時使用的單機多卡,數據並行的API

model = torch.nn.DataParallel(model).cuda()

換掉即可。

if args.distributed: train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)

最後使用這個官方給的劃分方法,把數據集劃分即可。

需要注意的點

  • 通信主機地址一定要寫ib的ip,否則帶寬不夠會造成Gloo底層觸發延遲錯誤
  • 一定要加rank參數
  • train_dataset最好不要用自己寫的sampler,否則還需要再實現一遍分散式的數據劃分方式

後續的計劃

一次講完分散式太難,所以這會是一個系列,系列結束後希望可以讓你自如地訓練自己的檢測、分割或者各種各樣的模型。

系列的內容包括但不限於:

  • 使用uber/horovod加速訓練
  • 詳解Train ImageNet In one Hour
  • 如何得到更好的ResNet50
  • 訓練檢測網路 or Mask RCNN

敬請期待~


推薦閱讀:

負載均衡SLB新功能介紹
Kubernetes CRD Operator 實現指南
分散式架構的實現
zookeeper的觀察者詳解
處理海量數據:列式存儲綜述(存儲篇)

TAG:PyTorch | 分散式系統 |