[分布式訓練] 單機多卡的正确打開方式:理論基礎
轉自:https://fyubang.com/2019/07/08/distributed-training/
瓦礫由于最近bert-large用的比較多,踩了很多分布式訓練的坑,加上在TensorFlow和PyTorch之間更換,算是熟悉了一下各類架構的分布式訓練接口,由于集中在一起講可能比較亂,筆者準備分三到四篇來講一下深度學習的分布式訓練。這一篇先講一下“分布式訓練的類型與算法”。
分布式訓練的需求和重要性不需要多說,随着GPT、BERT、xlnet這些預訓練模型的出現,普通的16G的顯存已經不足以支撐深度學習模型訓練的要求了,這時候就需要用到分布式訓練來提高效率。
注意:這個系列主要介紹單機多卡的分布式訓練情況(這種情況比較常見,土豪和大佬們請忽略)。
總的來說,分布式訓練分為這幾類:
- 按照并行方式來分:模型并行 vs 資料并行
- 按照更新方式來分:同步更新 vs 異步更新
- 按照算法來分:Parameter Server算法 vs AllReduce算法
模型并行 vs. 資料并行
假設我們有n張GPU:
- 模型并行:不同的GPU輸入相同的資料,運作模型的不同部分,比如多層網絡的不同層。
- 資料并行:不同的GPU輸入不同的資料,運作相同的完整模型。

當模型非常大,一張GPU已經存不下的時候,可以使用模型并行,把模型的不同部分交給不同的機器負責,但是這樣會帶來很大的通信開銷,而且模型并行各個部分存在一定的依賴,規模伸縮性差。是以,通常一張可以放下一個模型的時候,會采用資料并行的方式,各部分獨立,伸縮性好。
同步更新 vs. 異步更新
對于資料并行來說,由于每個GPU負責一部分資料,那就涉及到如果更新參數的問題,分為同步更新和異步更新兩種方式。
- 同步更新:每個batch所有GPU計算完成後,再統一計算新權值,然後所有GPU同步新值後,再進行下一輪計算。
- 異步更新:每個GPU計算完梯度後,無需等待其他更新,立即更新整體權值并同步。
同步更新有等待,速度取決于最慢的那個GPU;異步更新沒有等待,但是涉及到更複雜的梯度過時,loss下降抖動大的問題。是以實踐中,一般使用同步更新的方式。
Parameter Server算法 vs. Ring AllReduce算法
這裡講一下常用的兩種參數同步的算法:PS 和 Ring AllReduce。
假設有5張GPU:
- Parameter Server:GPU 0将資料分成五份分到各個卡上,每張卡負責自己的那一份mini-batch的訓練,得到grad後,傳回給GPU 0上做累積,得到更新的權重參數後,再分發給各個卡。
- Ring AllReduce:5張以環形相連,每張卡都有左手卡和右手卡,一個負責接收,一個負責發送,循環4次完成梯度累積,再循環4次做參數同步。分為Scatter Reduce和All Gather兩個環節。
Parameter Server算法
Parameter Server的思想其實有點類似于MapReduce,以上講同步異步的時候,都是用的這種算法,但是它存在兩個缺點:
- 每一輪的訓練疊代都需要所有卡都将資料同步完做一次Reduce才算結束,并行的卡很多的時候,木桶效應就會很嚴重,計算效率低。
- 所有的GPU卡需要和Reducer進行資料、梯度和參數的通信,當模型較大或者資料較大的時候,通信開銷很大。
假設有 N N N個GPU,通信一次完整的參數所需時間為 K K K,那麼使用PS架構,花費的通信成本為:
T = 2 ( N − 1 ) K T=2(N-1)K T=2(N−1)K
是以我們亟需一種新的算法來提高深度學習模型訓練的并行效率。
Ring AllReduce算法
2017 年 Facebook 釋出了《Accurate, large minibatch SGD: Training ImageNet in 1 hour 》驗證了大資料并行的高效性,同年百度發表了《Bringing HPC techniques to deep learning 》,驗證了全新的梯度同步和權值更新算法的可行性,并提出了一種利用帶寬優化環解決通信問題的方法——Ring AllReduce。
Parameter Service最大的問題就是通信成本和GPU的數量線性相關。而Ring AllReduce的通信成本與GPU數量無關。Ring AllReduce分為兩個步驟:Scatter Reduce和All Gather。
Scatter Reduce過程:首先,我們将參數分為N份,相鄰的GPU傳遞不同的參數,在傳遞N-1次之後,可以得到每一份參數的累積(在不同的GPU上)。
All Gather:得到每一份參數的累積之後,再做一次傳遞,同步到所有的GPU上。
根據這兩個過程,我們可以計算到All Reduce的通信成本為:
T = 2 ( N − 1 ) K N T=2(N-1)\frac{K}{N} T=2(N−1)NK
可以看到通信成本T與GPU數量無關。
由于All Reduce算法在通信成本上的優勢,現在幾個架構基本上都實作了其對于的官方API,後面幾篇,瓦礫會跟大家一起過一遍TF,Torch的分布式訓練API具體是怎麼用的,有哪些坑。
Reference
- 是時候放棄Tensorflow,擁抱Horovod了
- Tensorflow單機多卡實作
- Binging HPC Techniques to Deep Learning
- Training Neural Nets on Larger Batches: Practical Tips for 1-GPU, Multi-GPU & Distributed setups