分布式訓(xùn)練需求
Deep Learning 在過(guò)去幾年中取得了長(zhǎng)足的發(fā)展,尤其在語(yǔ)音、圖像、機(jī)器翻譯、自然語(yǔ)言處理等領(lǐng)域更是取得了飛躍式的提升,但與之相伴的是模型越來(lái)越復(fù)雜,參數(shù)量越來(lái)越大,例如:Inception v3參數(shù)量約25million,ResNet 152 擁有 60million 參數(shù)、VGG16 約 140million 參數(shù),Deep Speech 2 參數(shù)量更是超過(guò)300million,一些語(yǔ)言模型參數(shù)量甚至超過(guò) 1billion (Exploringthe Limits of Language Modeling)。數(shù)據(jù)并行訓(xùn)練方式要求每個(gè) GPU 節(jié)點(diǎn)擁有一份完整的模型參數(shù)副本,并在融合梯度時(shí)發(fā)送和接收完整的梯度數(shù)據(jù),巨大的通信數(shù)據(jù)量給多機(jī)多卡并行訓(xùn)練帶來(lái)了極大的網(wǎng)絡(luò)通信壓力。
另一方面,越來(lái)越多的機(jī)器學(xué)習(xí)領(lǐng)域開始轉(zhuǎn)向DeepLearning比如 TTS、NLP。這意味著 GPU 集群的用戶(研發(fā)人員)數(shù)量將大幅膨脹。如何在多用戶環(huán)境下更高效的分配、利用 GPU 資源?一個(gè)辦法是計(jì)算資源以 GPU 為單位分配給用戶,而不管這些 GPU 是否在同一臺(tái)物理機(jī)上。這種分配方式的資源利用率雖高但同時(shí)也要求分布式訓(xùn)練效率要足夠高,高到可以忽略跨機(jī)通信時(shí)延。
以上兩方面原因促使我們必須尋找更高效的通信算法,最大限度釋放 GPU 集群的并行計(jì)算能力。
分布式訓(xùn)練的通信方法和問(wèn)題
模型參數(shù)量的大小與計(jì)算量不是成簡(jiǎn)單的正比關(guān)系,比如相同參數(shù)量的全連接模型和 CNN 的計(jì)算量相差了幾個(gè)數(shù)量級(jí),但模型的參數(shù)量與分布式訓(xùn)練的網(wǎng)絡(luò)通信代價(jià)一定是正相關(guān)的,尤其是超大模型,跨節(jié)點(diǎn)同步參數(shù)通常會(huì)造成嚴(yán)重的網(wǎng)絡(luò)擁塞。
主流的 Deep Learning 框架解決參數(shù)同步的方式有兩種:同步更新和異步更新。同步更新模式下,所有 GPU 在同一時(shí)間點(diǎn)與參數(shù)服務(wù)器交換、融合梯度;異步更新模式下,GPU 更新參數(shù)的時(shí)間點(diǎn)彼此解耦,各自獨(dú)立與參數(shù)服務(wù)器通信,交換、融合梯度。兩種更新模式各有優(yōu)缺點(diǎn),為了文章不失焦點(diǎn)并限制篇幅,這里不做展開討論了,我們只列出結(jié)論:
異步更新通信效率高速度快,但往往收斂不佳,因?yàn)橐恍┧俣嚷墓?jié)點(diǎn)總會(huì)提供過(guò)時(shí)、錯(cuò)誤的梯度方向
同步更新通信效率低,通常訓(xùn)練更慢,但訓(xùn)練收斂穩(wěn)定,因?yàn)橥礁禄镜韧趩慰ㄕ{(diào)大 batch size 訓(xùn)練
在實(shí)際生產(chǎn)環(huán)境中,我們通常很看重模型效果和訓(xùn)練速度,但當(dāng)魚與熊掌不能兼得時(shí),模型效果還是更重要一些的,為此犧牲一些訓(xùn)練速度也不是不可接受,所以同步更新基本是主流方法
那么如何解決同步更新的網(wǎng)絡(luò)瓶頸問(wèn)題呢?學(xué)者和工程師想出了多種優(yōu)化方法,比如結(jié)合同步更新和異步更新、半精度訓(xùn)練、稀疏梯度更新等等。限于篇幅,我們無(wú)法一一展開,在本文中,我們只介紹一種方法:Ring Allreduce。
如何搭建一套高效的分布式訓(xùn)練框架
通過(guò)上面的分析,以及日常工作中的經(jīng)驗(yàn),我們通常認(rèn)為一個(gè)理想的 GPU 集群應(yīng)包含這樣幾個(gè)特性:
1. GPU 跨機(jī)并行,達(dá)到近似線性加速比
2. 用戶以 GPUs 為單位申請(qǐng)資源,物理節(jié)點(diǎn)對(duì)用戶透明
3. 使用要簡(jiǎn)單,甚至單機(jī)單卡、單機(jī)多卡、多機(jī)多卡可以由一套代碼實(shí)現(xiàn)
目標(biāo)確定了,就來(lái)看看如何搭建這樣一套系統(tǒng),我們選擇如下幾個(gè)組件:Kubernetes、TensorFlow以及 Horovod。
Kubernetes 是目前最流行的開源容器集群管理系統(tǒng),在我們的系統(tǒng)中,Kubernetes 主要負(fù)責(zé)負(fù)責(zé)集群的容器化管理,包括 GPU 資源的申請(qǐng)、釋放、監(jiān)控等。
TensorFlow 是 Google 大力推廣的基于數(shù)據(jù)流圖的 Deep Learning 框架,無(wú)論是使用者數(shù)量還是社區(qū)活躍程度,都遙遙領(lǐng)先其他競(jìng)爭(zhēng)對(duì)手,在我們的系統(tǒng)中主要負(fù)責(zé)各個(gè)業(yè)務(wù)線上深度模型的搭建。
Horovod 是 Uber 新近開源的高效分布式訓(xùn)練通信框架,Horovod本身只負(fù)責(zé)節(jié)點(diǎn)間網(wǎng)絡(luò)通信、梯度融合,在運(yùn)行時(shí)需要綁定 TensorFlow 做單機(jī)運(yùn)算。
這里有兩個(gè)問(wèn)題需要說(shuō)明一下:
1. TensorFlow 框架本身已經(jīng)支持分布式訓(xùn)練,為什么不直接使用呢?
因?yàn)門ensorFlow的分布式框架是基于參數(shù)服務(wù)器的,這種結(jié)構(gòu)容易造成網(wǎng)絡(luò)堵塞;
并且開源版 TensorFlow 的跨機(jī)通信是通過(guò)gRPC + ProtocolBuffers 實(shí)現(xiàn)的,這種方案的問(wèn)題是,首先 gRPC 本身的效率就比較差,其次使用 Protocol Buffers 序列化就意味著節(jié)點(diǎn)間的所有交互必須經(jīng)過(guò)內(nèi)存,無(wú)法使用 GPUDirect RDMA,限制了速度提升;
即使拋開性能問(wèn)題,編寫 TensorFlow 的分布式代碼也是一件十分繁瑣的工作,有過(guò)相關(guān)經(jīng)驗(yàn)的同學(xué)應(yīng)該有所體會(huì)。
2. Horovod 是一個(gè)較新的分布式訓(xùn)練通信框架,它有哪些優(yōu)勢(shì)呢?
Horovod 有如下主要特點(diǎn):Horovod可以實(shí)現(xiàn)接近 0.9x 的加速比;
一套代碼實(shí)現(xiàn)單機(jī)單卡、單機(jī)多卡、多機(jī)多卡;社區(qū)活躍,代碼迭代速度快,作為對(duì)比 Baidu Allreduce 已經(jīng)停止維護(hù)了。
在接下來(lái)的兩小節(jié)中,我們將分別介紹 Horovod的核心算法和以及部署實(shí)踐。
Horovod 核心算法
Ring Allreduce ,原是 HPC 領(lǐng)域一種比較成熟的通信算法,后被 Baidu SVAIL 引入到 Deep Learning訓(xùn)練框架中,并于 2017年2月公開 。Ring Allreduce 完全拋棄了參數(shù)服務(wù)器,理論上可以做到線性加速。Ring Allreduce 算法也是 Horovod的核心,Horovod對(duì) Baidu SVAIL 的實(shí)現(xiàn)做了易用性改進(jìn)和性能優(yōu)化。
在這一節(jié)中,我們會(huì)詳細(xì)介紹Ring Allreduce 的算法流程:。
PS WORKER 框架下同步更新方式,以及網(wǎng)絡(luò)瓶頸定量分析
我們來(lái)定量分析一下,同步更新的網(wǎng)絡(luò)瓶頸問(wèn)題,以Deep Speech 2 為例:
模型包含 300M 參數(shù),相當(dāng)于 1.2 G 的大小的內(nèi)存數(shù)據(jù)(300M * sizeof(float))
假設(shè)網(wǎng)絡(luò)帶寬 1G bytes/s (萬(wàn)兆網(wǎng)卡)
2 卡同步更新,需要 1.2 s 完成參數(shù) Send(這還不算 Receive 的時(shí)間)
10 卡同步更新,需要 9.8 s 完成參數(shù) Send
通過(guò)簡(jiǎn)單的計(jì)算會(huì)發(fā)現(xiàn),在單 ps 節(jié)點(diǎn)、有限帶寬環(huán)境下,通信時(shí)間隨著 GPU 數(shù)量的增加而線性增長(zhǎng),很難想象一個(gè)10卡的集群每訓(xùn)練一個(gè) batch 都需要等待 10 ~ 20s 來(lái)同步參數(shù)!通信時(shí)延幾乎完全覆蓋掉了 GPU 并行計(jì)算節(jié)節(jié)省下的計(jì)算時(shí)間,當(dāng)然在實(shí)際訓(xùn)練環(huán)境中,網(wǎng)絡(luò)速度也是能達(dá)到幾十 Gbps 的,而且通常也會(huì)多設(shè)置幾個(gè) ps 節(jié)點(diǎn),比如每個(gè)物理節(jié)點(diǎn)設(shè)置一個(gè) ps ,這樣可以減輕帶寬瓶頸,但這些措施都沒(méi)有從根本上解決問(wèn)題。
Ring Allreduce 框架下同步更新方式
在上面的通信方式中,網(wǎng)絡(luò)傳輸量跟 GPU 成正比,而Ring Allreduce 是一種通信量恒定的通信算法,也就是說(shuō),GPU 的網(wǎng)絡(luò)通信量不隨 GPU 的數(shù)量增加而增加,下面我們會(huì)詳細(xì)說(shuō)明一下Ring Allreduce 框架下 GPU 的通信流程。
首先定義 GPU 集群的拓?fù)浣Y(jié)構(gòu):
GPU 集群被組織成一個(gè)邏輯環(huán)
每個(gè) GPU 有一個(gè)左鄰居、一個(gè)右鄰居
每個(gè) GPU 只從左鄰居接受數(shù)據(jù)、并發(fā)送數(shù)據(jù)給右鄰居。
梯度融合過(guò)程分為兩階段:
1. Scatter Reduce :在這個(gè)Scatter Reduce 階段,GPU 會(huì)逐步交換彼此的梯度并融合,最后每個(gè) GPU 都會(huì)包含完整融合梯度的一部分
2. Allgather :GPU 會(huì)逐步交換彼此不完整的融合梯度,最后所有 GPU 都會(huì)得到完整的融合梯度
Scatter Reduce
為了方便說(shuō)明,我們用梯度加和代替梯度融合。假設(shè)集群中有 N 個(gè) GPU,那么將梯度數(shù)據(jù)等分為 N 份,接下來(lái)將在 GPUs 間進(jìn)行 N-1 次Scatter Reduce 迭代,在每一次迭代中,每個(gè) GPU 都會(huì)發(fā)送所有梯度數(shù)據(jù)的 1/N 給右鄰居,并從左鄰居接收所有梯度數(shù)據(jù)的 1/N 。同一次Scatter Reduce 迭代中,發(fā)送和接收的數(shù)據(jù)塊的編號(hào)是不同的,例如,第一輪迭代,第 n 個(gè) GPU 會(huì)發(fā)送第 n 號(hào)數(shù)據(jù)塊,并接收第 n-1 號(hào)數(shù)據(jù)塊。經(jīng)過(guò) n-1 輪迭代,梯度數(shù)據(jù)會(huì)像圖2 所示,每個(gè) GPU 都包含了部分完整梯度信息。
Allgather
和Scatter Reduce 階段類似,只不過(guò)這里只拷貝不求和,最終每個(gè)GPU 都得到了所有融合后的梯度。
這么做有什么好處呢?
下面我們來(lái)定量的分析一下,每個(gè) GPU 在Scatter Reduce 階段,接收 N-1 次數(shù)據(jù),N 是 GPU 數(shù)量;每個(gè) GPU 在allgather 階段,接收 N-1 次 數(shù)據(jù);每個(gè) GPU 每次發(fā)送 K/N 大小數(shù)據(jù)塊,K 是總數(shù)據(jù)大??;所以,Data Transferred=2(N?1)*K/N =
(2(N?1)/N)*K,隨著 GPU 數(shù)量 N 增加,總傳輸量恒定!總傳輸量恒定意味著通信成本不隨 GPU 數(shù)量增長(zhǎng)而增長(zhǎng),也就是說(shuō)我們系統(tǒng)擁有理論上的線性加速能力。再回到 DS2 的例子,300million參數(shù)也就是 1.2Gb 數(shù)據(jù)量,Ring Allreduce 方式更新一次需要傳送并接收 2.4Gb 數(shù)據(jù),假設(shè)網(wǎng)絡(luò)使用 GPUDirect RDMA + InfiniBand,GPUDirect RDMA 帶寬約為10Gb/s;InfiniBand 帶寬約為6Gb/s,所以通信瓶頸在 InfiniBand 。(2.4Gb)/(6.0Gb/s) ≈ 400ms,也就是每輪迭代需要 400 ms 做參數(shù)同步,這 400ms 的數(shù)據(jù)傳輸時(shí)間是恒定的,不隨 GPU 數(shù)量增加而增加。
在 Kubernetes 環(huán)境部署Horovod
Kubernetes 是一套容器集群管理系統(tǒng),支持集群化的容器應(yīng)用,從使用角度看
Kubernetes 包含幾個(gè)重要的概念:
1. pod,pod 由一個(gè)或多個(gè)容器構(gòu)成,在問(wèn)本文描述的場(chǎng)景下,一個(gè) pod 包含一個(gè)容器,容器中包含1個(gè)或多個(gè) GPU 資源
2. Services,對(duì)外提供服務(wù)發(fā)現(xiàn),后面通常會(huì)對(duì)接容器實(shí)例
3. YAML , YAML 是一種類似 JSON 的描述語(yǔ)言 ,在Kubernetes 中用 YAML 定義 pod 、Service 、Replication Controller等組件
4.kubectl,kubectl 是一套命令行工具,負(fù)責(zé)執(zhí)行開發(fā)人員和 Kubernetes 集群間的交互操作,例如查看 Kubernetes 集群內(nèi) pod 信息匯總kubectl get pod;查看 Kubernetes 內(nèi)物理節(jié)點(diǎn)信息匯總 kubectl get node
另外,近期我們還會(huì)有一篇詳細(xì)介紹TensorFlow on Kubernetes 的文章,所以關(guān)于Kubernetes 的詳細(xì)信息本文就不贅述了。
Build image
首先我們需要?jiǎng)?chuàng)建一個(gè) Horovod鏡像,這個(gè)鏡像需要包含 TensorFlow 環(huán)境 、Horovod環(huán)境 、以及 OpenMPI的免密的登陸配置,我們可以選擇TensorFlow:1.3.0-gpu-py3 作為基礎(chǔ)鏡像,通過(guò) Dockerfile 逐步安裝 Horovod環(huán)境及 Open MPI免密登陸配置。
第一步,安裝 Horovod相關(guān)依賴:apt-getupdate ; apt-get install -y openssh-server wgetlibnccl2 libnccl-dev。
第二步,下載并安裝 Open MPI,注意:如果你的網(wǎng)絡(luò)環(huán)境支持 RDMA,那你需要帶 --with-cuda 參數(shù)從源碼配置安裝:./configure --with-cuda ; make all install。
第三步,安裝 Horovod:HOROVOD_GPU_ALLREDUCE=NCCLpip install --no-cache-dir horovod,
第四步,設(shè)置 MPI SSH 免密登陸環(huán)境,方法見下面的Dockerfile。
編寫完成 Dockerfile 后,我們就可以 build 鏡像了:docker build -t horovod:v1 . 。
MPI on Kubernetes 相關(guān)問(wèn)題
我們?cè)谡{(diào)試過(guò)程中發(fā)現(xiàn),Kubernetes 環(huán)境運(yùn)行 Open MPI必須將 pod 設(shè)置為 host 網(wǎng)絡(luò)模式,否則 MPI 節(jié)點(diǎn)間通信時(shí)會(huì) hang 住。host 網(wǎng)絡(luò)模式的問(wèn)題在于它會(huì)占用宿主機(jī)端口號(hào),多用戶環(huán)境下會(huì)有沖突,所以我們還需要想辦法為每個(gè) pod 獨(dú)立設(shè)置一個(gè)SSH端口號(hào),并通知集群里所有 Horovod節(jié)點(diǎn)。
方法詳見下面的腳本:腳本在 pod 創(chuàng)建時(shí)啟動(dòng),其中 Host** 為集群中所有節(jié)點(diǎn)的節(jié)點(diǎn)名和 SSH 端口號(hào),腳本的最后一行作用是更改本機(jī)的 SSH端口號(hào)。這種方法可行但并不優(yōu)雅,所以如果你有其他更好的方案,請(qǐng)?jiān)谖恼孪路搅粞愿嬖V我。
Pod yaml
這里我們申請(qǐng) 2 pod,每個(gè) pod 各 2 個(gè) GPU ,horovod-mpi0 的 SSH端口設(shè)置為 8900 ;horovod-mpi1 的 SSH端口設(shè)置為 8901。
測(cè)試腳本及 Benchmark
·集群環(huán)境:Kubernetes,兩機(jī)兩卡,1080ti
啟動(dòng)腳本:
如果將 Benchmark 整理成圖表,那么看起來(lái)是這樣的。
在普通以太網(wǎng)環(huán)境下, 2 機(jī) 4 卡相比單機(jī)單卡,Horovod 可加速 3.6 倍。
-
服務(wù)器
+關(guān)注
關(guān)注
13文章
9795瀏覽量
88002 -
計(jì)算量
+關(guān)注
關(guān)注
0文章
4瀏覽量
6938
發(fā)布評(píng)論請(qǐng)先 登錄
分布式軟件系統(tǒng)
LED分布式恒流原理
基于分布式調(diào)用鏈監(jiān)控技術(shù)的全息排查功能
分布式系統(tǒng)的優(yōu)勢(shì)是什么?
HarmonyOS應(yīng)用開發(fā)-分布式設(shè)計(jì)
如何高效完成HarmonyOS分布式應(yīng)用測(cè)試?
分布式系統(tǒng)硬件資源池原理和接入實(shí)踐
GL Studio的分布式虛擬訓(xùn)練系統(tǒng)關(guān)鍵技術(shù)
關(guān)于分布式系統(tǒng)的幾個(gè)問(wèn)題
探究超大Transformer語(yǔ)言模型的分布式訓(xùn)練框架
基于PyTorch的模型并行分布式訓(xùn)練Megatron解析

分布式通信的原理和實(shí)現(xiàn)高效分布式通信背后的技術(shù)NVLink的演進(jìn)

評(píng)論