The Communication Problem
當(dāng)將神經(jīng)網(wǎng)絡(luò)的訓(xùn)練并行化到許多GPU上時(shí)锭碳,你必須選擇如何將不同的操作分配到你可用的不同GPU上。在這里分唾,我們關(guān)注一種稱為數(shù)據(jù)并行隨機(jī)梯度下降( SGD )的技術(shù)抗碰。與標(biāo)準(zhǔn)SGD一樣,梯度下降是通過(guò)數(shù)據(jù)子集(小批次)完成的绽乔,需要多次迭代才能在整個(gè)數(shù)據(jù)集上進(jìn)行改含。然而,在數(shù)據(jù)并行訓(xùn)練中,每個(gè)GPU都有整個(gè)神經(jīng)網(wǎng)絡(luò)模型的完整副本捍壤,對(duì)于每次迭代,只分配了小批次中樣本的子集鞍爱。對(duì)于每次迭代鹃觉,每個(gè)GPU在其數(shù)據(jù)上運(yùn)行網(wǎng)絡(luò)的前向傳播,隨后進(jìn)行誤差反向傳播睹逃,以計(jì)算損耗相對(duì)于網(wǎng)絡(luò)參數(shù)的梯度盗扇。最后,GPU相互通信以平均由不同GPU計(jì)算的梯度沉填,將平均梯度應(yīng)用于權(quán)重以獲得新權(quán)重疗隶。GPU都在鎖定步驟的迭代中前進(jìn),一旦GPU完成了迭代翼闹,它必須等待所有其他GPU完成它們的迭代斑鼻,這樣權(quán)重才能被正確更新。這相當(dāng)于在單個(gè)GPU上執(zhí)行SGD猎荠,但是我們通過(guò)在多個(gè)GPU之間分發(fā)數(shù)據(jù)并并行執(zhí)行計(jì)算來(lái)獲得加速坚弱。
當(dāng)你只有兩個(gè)GPU和以兆字節(jié)數(shù)據(jù)衡量的參數(shù)時(shí),這些GPU的通信方式可能并不重要关摇。然而荒叶,當(dāng)你的模型有數(shù)十億個(gè)參數(shù)時(shí),梯度可能需要幾十億字節(jié)的空間(因?yàn)槊總€(gè)參數(shù)都有一個(gè)梯度值)输虱,并且你正在協(xié)調(diào)幾十個(gè)GPU些楣,通信機(jī)制變得至關(guān)重要。
例如宪睹,考慮最直接的通信機(jī)制愁茁。每一個(gè)GPU都計(jì)算其子集的小批次上的梯度。然后横堡,每個(gè)GPU將其梯度發(fā)送到單個(gè)GPU埋市,該GPU取所有梯度的平均值,并將平均值發(fā)送回所有其他GPU命贴。
在直接從單個(gè)GPU發(fā)送和接收數(shù)據(jù)的機(jī)制中道宅,單個(gè)GPU必須從所有GPU接收所有參數(shù),并將所有參數(shù)發(fā)送到所有GPU胸蛛。系統(tǒng)中的gpu越多污茵,通信成本就越大。
讓我們?cè)u(píng)估一下這種通信策略如何在真實(shí)模型上運(yùn)行葬项,例如以百度深度語(yǔ)音2 為模型的語(yǔ)音識(shí)別網(wǎng)絡(luò)泞当,具有三億個(gè)可訓(xùn)練參數(shù)。 每個(gè)參數(shù)四個(gè)字節(jié)的三億個(gè)參數(shù)大約是1.2千兆字節(jié)的數(shù)據(jù)民珍。 假設(shè)您系統(tǒng)上的網(wǎng)絡(luò)硬件可以支持每秒1千兆字節(jié)的帶寬; 在這種情況下襟士,如上所述將系統(tǒng)并行化到兩個(gè)GPU上將使每次迭代減慢1.2秒盗飒。 將您的訓(xùn)練并行化到10個(gè)GPU將使每次迭代減慢10.8秒; 隨著GPU數(shù)量的增長(zhǎng),每次迭代所需的時(shí)間呈線性增長(zhǎng)陋桂。 即使每次迭代花費(fèi)幾秒鐘逆趣,通信成本的這種線性增長(zhǎng)也會(huì)使得進(jìn)一步的并行化變得不切實(shí)際并且會(huì)降低訓(xùn)練效率。
需要發(fā)送的數(shù)據(jù)越多嗜历,發(fā)送時(shí)間就越長(zhǎng);每個(gè)通信通道都有一個(gè)最大的吞吐量(帶寬)宣渗。例如,一個(gè)好的internet連接可以提供每秒15兆字節(jié)的帶寬梨州,而千兆以太網(wǎng)連接可以提供每秒125兆字節(jié)的帶寬痕囱。HPC集群上的專(zhuān)用網(wǎng)絡(luò)硬件(如Infiniband)可以在節(jié)點(diǎn)之間提供每秒數(shù)gb的帶寬。
另一種選擇是放棄訓(xùn)練算法的同步性暴匠,并通過(guò)梯度下降的迭代消除所有GPU在鎖定步驟中前進(jìn)的限制鞍恢。然而,雖然這可以使模型更容易并行化巷查,但是消除這種約束的算法(異步SGD的變體)可能很難調(diào)試有序,對(duì)于某些模型來(lái)說(shuō),可能會(huì)收斂到子結(jié)果岛请,所以我們不考慮這些問(wèn)題旭寿。
相反,我們可以通過(guò)使用高性能計(jì)算領(lǐng)域的分布式縮減算法并利用帶寬優(yōu)化環(huán)來(lái)解決通信問(wèn)題崇败。
The Ring Allreduce
上述簡(jiǎn)單通信策略的主要問(wèn)題是盅称,通信成本隨系統(tǒng)中g(shù)pu的數(shù)量線性增長(zhǎng)。相比之下后室,環(huán)allreduce算法的通信成本是恒定的缩膝,與系統(tǒng)中g(shù)pu的數(shù)量無(wú)關(guān),完全由系統(tǒng)中g(shù)pu之間最慢的連接決定;事實(shí)上岸霹,如果您只考慮帶寬作為通信成本的一個(gè)因素(并忽略延遲)疾层,那么環(huán)allreduce是一種最優(yōu)通信算法(當(dāng)您的模型很大,并且您需要發(fā)送大量數(shù)據(jù)的次數(shù)很少時(shí)贡避,這是一個(gè)很好的通信成本估算痛黎。)。
環(huán)中的gpu都被安排在一個(gè)邏輯環(huán)中刮吧。每個(gè)GPU應(yīng)該有一個(gè)左鄰和一個(gè)右鄰;它只會(huì)向它的右鄰居發(fā)送數(shù)據(jù)湖饱,并從它的左鄰居接收數(shù)據(jù)。
該算法分兩個(gè)步驟進(jìn)行:首先是scatter-reduce杀捻,然后是allgather井厌。在scatter-reduce步驟中,GPU將交換數(shù)據(jù),使每個(gè)GPU可得到最終結(jié)果的一個(gè)塊仅仆。在allgather步驟中器赞,gpu將交換這些塊,以便所有g(shù)pu得到完整的最終結(jié)果蝇恶。
The Scatter-Reduce
為簡(jiǎn)單起見(jiàn)拳魁,讓我們假設(shè)目標(biāo)是對(duì)一個(gè)浮點(diǎn)數(shù)的大數(shù)組求和; 系統(tǒng)中有N個(gè)GPU,每個(gè)GPU都有一個(gè)相同大小的數(shù)組撮弧,并且在allreduce的末尾,每個(gè)GPU都應(yīng)該有一個(gè)相同大小的數(shù)組姚糊,其中包含原始數(shù)組中數(shù)字的總和贿衍。
首先,gpu將數(shù)組劃分為N個(gè)更小的塊(其中N是環(huán)中的gpu數(shù))救恨。
接下來(lái)贸辈,GPU將進(jìn)行N-1次 Scatter-Reduce 迭代;在每次迭代中肠槽,GPU將向其右鄰居發(fā)送一個(gè)塊擎淤,并從其左鄰居接收一個(gè)塊并累積到該塊中。每個(gè)GPU發(fā)送和接收的塊在每次迭代中都是不同的秸仙;第n個(gè)GPU從發(fā)送塊N和接收塊N - 1開(kāi)始嘴拢,然后從那里向后進(jìn)行,每次迭代都發(fā)送它在前一次迭代中接收到的塊寂纪。
例如席吴,在第一次迭代中,上圖中的五個(gè)GPU將發(fā)送和接收以下區(qū)塊:
在第一次發(fā)送和接收完成之后捞蛋,每個(gè)GPU將擁有一個(gè)塊孝冒,該塊由兩個(gè)不同GPU上相同塊的和組成。例如拟杉,第二個(gè)GPU上的第一個(gè)塊將是該塊中來(lái)自第二個(gè)GPU和第一個(gè)GPU的值的和庄涡。
在下一次迭代中,該過(guò)程繼續(xù)進(jìn)行搬设,到最后穴店,每個(gè)GPU將有一個(gè)塊,該塊包含所有GPU中該塊中所有值的總和焕梅。下圖展示了所有數(shù)據(jù)傳輸和中間結(jié)果迹鹅,從第一次迭代開(kāi)始,一直持續(xù)到Scatter-Reduce完成贞言。
The Allgather
在scatter-reduce步驟完成之后斜棚,每個(gè)GPU都有一個(gè)值數(shù)組,其中一些值(每個(gè)GPU一個(gè)塊)是最終的值,其中包括來(lái)自所有GPU的貢獻(xiàn)弟蚀。為了完成allreduce, gpu必須交換這些塊蚤霞,以便所有g(shù)pu都具有所有必需的值。
環(huán)的收集過(guò)程與scatter-reduce是相同的(發(fā)送和接收的N-1次迭代)义钉,只是gpu接收的值沒(méi)有累加昧绣,而是簡(jiǎn)單地覆蓋塊。第n個(gè)GPU首先發(fā)送第n+1個(gè)塊并接收第n個(gè)塊捶闸,然后在以后的迭代中總是發(fā)送它剛剛接收到的塊夜畴。
例如,在我們的5 - gpu設(shè)置的第一次迭代中删壮,gpu將發(fā)送和接收以下塊
第一次迭代完成后贪绘,每個(gè)GPU將擁有最終數(shù)組的兩個(gè)塊。
在下一個(gè)迭代中央碟,該過(guò)程將繼續(xù)税灌,到最后,每個(gè)GPU將擁有整個(gè)數(shù)組的完整累積值亿虽。下面的圖像演示了所有數(shù)據(jù)傳輸和中間結(jié)果菱涤,從第一次迭代開(kāi)始,一直到allgather完成洛勉。
Allreduce Communication Cost
回想一下粘秆,對(duì)于介紹中描述的簡(jiǎn)單通信算法,通信成本隨著GPU的數(shù)量線性增長(zhǎng)坯认。 allreduce運(yùn)行良好的主要原因是不再是這種情況翻擒。
在我們描述的系統(tǒng)中,N個(gè)GPU中的每一個(gè)都將發(fā)送和接收N-1次scatter-reduce牛哺,N-1次allgather陋气。每次,GPU都會(huì)發(fā)送K / N值引润,其中K是數(shù)組中不同GPU上相加的值總數(shù)巩趁。因此,傳輸?shù)矫總€(gè)GPU和從每個(gè)GPU傳輸?shù)臄?shù)據(jù)總量為
重要的是淳附,這與GPU的數(shù)量無(wú)關(guān)议慰。
由于所有傳輸都是在離散迭代中同步進(jìn)行的,因此所有傳輸?shù)乃俣仁艿江h(huán)中相鄰GPU之間最慢(最低帶寬)連接的限制奴曙。給定每個(gè)GPU的鄰居的正確選擇别凹,該算法是帶寬最優(yōu)的,并且是執(zhí)行全面操作的最快算法(假設(shè)延遲成本與帶寬相比可以忽略不計(jì))洽糟。一般來(lái)說(shuō)炉菲,如果一個(gè)節(jié)點(diǎn)上的所有GPU在環(huán)中彼此相鄰堕战,則該算法的功能最佳;這最小化了網(wǎng)絡(luò)爭(zhēng)用的量拍霜,否則這可能會(huì)顯著降低GPU-GPU連接的有效帶寬嘱丢。
Applying the Allreduce to Deep Learning
Ring allreduce是高性能計(jì)算領(lǐng)域中著名的算法,但在深度學(xué)習(xí)中很少使用祠饺。在我們的實(shí)驗(yàn)室中越驻,我們已經(jīng)成功地將這個(gè)工具作為所有數(shù)據(jù)并行訓(xùn)練的基礎(chǔ),使我們能夠有效地將訓(xùn)練擴(kuò)展到幾十個(gè)gpu道偷。
為了最小化通信開(kāi)銷(xiāo)缀旁,我們可以利用神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)。在每次迭代中勺鸦,每個(gè)GPU運(yùn)行正向傳播來(lái)計(jì)算誤差诵棵,然后運(yùn)行反向傳播來(lái)計(jì)算神經(jīng)網(wǎng)絡(luò)的每個(gè)參數(shù)的梯度。反向傳播計(jì)算梯度祝旷,從輸出層開(kāi)始,向輸入層移動(dòng)嘶窄,這意味著輸出層參數(shù)的梯度在早期層的梯度之前很明顯是可用的怀跛。因?yàn)槿窟\(yùn)算可以一次對(duì)網(wǎng)絡(luò)的一部分參數(shù)進(jìn)行運(yùn)算,所以我們可以在其他梯度仍在計(jì)算的時(shí)候開(kāi)始對(duì)輸出層參數(shù)進(jìn)行全部運(yùn)算柄冲。這樣做將通信與反向傳播步驟中的其余計(jì)算重疊吻谋,從而減少了每個(gè)GPU等待通信完成的總時(shí)間。
例如现横,考慮一個(gè)類(lèi)似于2的語(yǔ)言模型漓拾,但有大約3億個(gè)可學(xué)習(xí)的參數(shù)(因此總梯度大小為1.2千兆字節(jié))。 使用allreduce戒祠,每個(gè)GPU必須發(fā)送和接收大約2.4千兆字節(jié)的數(shù)據(jù)骇两。 使用支持CUDA的MPI實(shí)現(xiàn)(例如OpenMPI),我們可以使用GPUDirect RDMA在GPU之間傳輸數(shù)據(jù)姜盈,帶寬大約為每秒10千兆字節(jié); 但是低千,我們集群中節(jié)點(diǎn)之間的連接速度較慢,Infiniband提供的帶寬大約為每秒6千兆字節(jié)馏颂。 由于限制因素是Infiniband連接示血,因此單次迭代需要大約
由于更深層次的網(wǎng)絡(luò)首先有可用的梯度,我們可以在完成整個(gè)反向傳播傳遞之前開(kāi)始進(jìn)行數(shù)據(jù)傳輸救拉,因此真正的開(kāi)銷(xiāo)可能小于400毫秒;根據(jù)所優(yōu)化的神經(jīng)網(wǎng)絡(luò)的性質(zhì)难审,通信和計(jì)算之間的重疊可能有所不同。
我們實(shí)現(xiàn)了上述語(yǔ)言模型亿絮,并測(cè)試了每次迭代所花費(fèi)的時(shí)間告喊,因?yàn)槲覀儚膯蝹€(gè)GPU(沒(méi)有通信開(kāi)銷(xiāo))擴(kuò)展到40個(gè)GPU麸拄。 這40個(gè)GPU排列成5個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)有8個(gè)GPU葱绒,由Infiniband連接感帅。 我們運(yùn)行語(yǔ)言模型300次迭代,批量大小為32地淀,并計(jì)算每秒處理的樣本數(shù)失球。
正如您所看到的,整個(gè)系統(tǒng)的吞吐量隨著GPU的數(shù)量線性擴(kuò)展帮毁;超過(guò)一定的意見(jiàn)后实苞,添加更多的GPU不會(huì)導(dǎo)致每次迭代的顯著減速。在40個(gè)GPU上運(yùn)行模型每次迭代大約需要650 - 700毫秒烈疚,而在單個(gè)GPU上大約需要370毫秒黔牵。根據(jù)我們的估計(jì),通信將花費(fèi)400毫秒爷肝,通過(guò)將反向傳播與數(shù)據(jù)傳輸重疊猾浦,我們?cè)诿看蔚泄?jié)省了額外的70 - 120毫秒。