隨著我們從單個(gè) GPU 轉(zhuǎn)移到多個(gè) GPU,再轉(zhuǎn)移到包含多個(gè) GPU 的多臺(tái)服務(wù)器,可能都分布在多個(gè)機(jī)架和網(wǎng)絡(luò)交換機(jī)上,我們的分布式和并行訓(xùn)練算法需要變得更加復(fù)雜。細(xì)節(jié)很重要,因?yàn)椴煌幕ミB具有非常不同的帶寬(例如,NVLink 可以在適當(dāng)?shù)脑O(shè)置下跨 6 個(gè)鏈路提供高達(dá) 100 GB/s 的速度,PCIe 4.0(16 通道)提供 32 GB/s,而即使是高速 100GbE 以太網(wǎng)也只能達(dá)到到 10 GB/秒)。同時(shí),期望統(tǒng)計(jì)建模師成為網(wǎng)絡(luò)和系統(tǒng)方面的專家是不合理的。
Smola 和 Narayanamurthy ( 2010 )在分布式潛變量模型的背景下引入了參數(shù)服務(wù)器的核心思想 。隨后在Ahmed等人中描述了推拉語(yǔ)義。( 2012 )以及Li等人對(duì)系統(tǒng)和開(kāi)源庫(kù)的描述 。(2014 年)。在下文中,我們將激勵(lì)效率所需的組件。
13.7.1。數(shù)據(jù)并行訓(xùn)練
讓我們回顧一下分布式訓(xùn)練的數(shù)據(jù)并行訓(xùn)練方法。我們將使用它來(lái)排除本節(jié)中的所有其他內(nèi)容,因?yàn)樗趯?shí)踐中實(shí)施起來(lái)要簡(jiǎn)單得多。由于現(xiàn)在 GPU 有足夠的內(nèi)存,因此幾乎沒(méi)有任何用例(除了圖上的深度學(xué)習(xí))首選任何其他并行策略。圖 13.7.1描述了我們?cè)?/font>13.5 節(jié)中實(shí)現(xiàn)的數(shù)據(jù)并行的變體 。其中的關(guān)鍵方面是在將更新的參數(shù)重新廣播到所有 GPU 之前,梯度的聚合發(fā)生在一個(gè) GPU (GPU 0) 上。
回想起來(lái),在 GPU 0 上聚合的決定似乎是臨時(shí)的。畢竟,我們還不如聚合在 CPU 上。事實(shí)上,我們甚至可以決定在一個(gè) GPU 上聚合一些參數(shù),在另一個(gè) GPU 上聚合一些其他參數(shù)。只要優(yōu)化算法支持這一點(diǎn),就沒(méi)有我們不能這樣做的真正原因。例如,如果我們有四個(gè)具有相關(guān)梯度的參數(shù)向量 g1,…,g4我們可以在一個(gè) GPU 上聚合梯度gi (i=1,…,4).
這種推理似乎是武斷和輕率的。畢竟,數(shù)學(xué)自始至終都是一樣的。然而,我們正在處理真實(shí)的物理硬件,其中不同的總線具有不同的帶寬,如第 13.4 節(jié)所述 。考慮一個(gè)真實(shí)的 4 路 GPU 服務(wù)器,如圖13.7.2所示。如果連接特別好,它可能有 100 GbE 網(wǎng)卡。更典型的數(shù)字在 1–10 GbE 范圍內(nèi),有效帶寬為 100 MB/s 至 1 GB/s。由于 CPU 的 PCIe 通道太少而無(wú)法直接連接到所有 GPU(例如,消費(fèi)級(jí) Intel CPU 有 24 條通道),我們需要一個(gè) 多路復(fù)用器。CPU 在 16x Gen3 鏈路上的帶寬為 16 GB/s。這也是每個(gè)人的速度GPU 連接到交換機(jī)。這意味著設(shè)備之間的通信更加有效。
為了論證,我們假設(shè)梯度為 160 MB。在這種情況下,將梯度從所有剩余的 3 個(gè) GPU 發(fā)送到第四個(gè) GPU 需要 30 毫秒(每次傳輸需要 10 毫秒 = 160 MB / 16 GB/s)。再加上 30 毫秒來(lái)傳回權(quán)重向量,我們總共需要 60 毫秒。如果我們將所有數(shù)據(jù)發(fā)送到 CPU,我們會(huì)受到 40 毫秒的懲罰,因?yàn)樗膫€(gè) GPU 中的每一個(gè)都需要將數(shù)據(jù)發(fā)送到 CPU,總共需要 80 毫秒。最后假設(shè)我們能夠?qū)⑻荻确殖?4 個(gè)部分,每個(gè)部分 40 MB。現(xiàn)在我們可以同時(shí)在不同的 GPU 上聚合每個(gè)部分因?yàn)?PCIe 交換機(jī)在所有鏈路之間提供全帶寬操作。這需要 7.5 毫秒而不是 30 毫秒,同步操作總共需要 15 毫秒。簡(jiǎn)而言之,根據(jù)我們同步參數(shù)的方式,同一操作可能需要 15 毫秒到 80 毫秒不等。 圖 13.7.3描述了交換參數(shù)的不同策略。
請(qǐng)注意,在提高性能方面,我們還有另一種工具可供使用:在深度網(wǎng)絡(luò)中,需要一些時(shí)間來(lái)計(jì)算從頂部到底部的所有梯度。即使我們?nèi)栽诿τ跒槠渌麉?shù)組計(jì)算梯度,我們也可以開(kāi)始同步某些參數(shù)組的梯度。 有關(guān)如何在 Horovod中執(zhí)行此操作的詳細(xì)信息,請(qǐng)參見(jiàn)例如Sergeev 和 Del Balso ( 2018 )。
13.7.2。環(huán)同步
當(dāng)談到現(xiàn)代深度學(xué)習(xí)硬件上的同步時(shí),我們經(jīng)常會(huì)遇到大量定制的網(wǎng)絡(luò)連接。例如,AWS p3.16xlarge 和 NVIDIA DGX-2 實(shí)例共享圖 13.7.4的連接結(jié)構(gòu)。每個(gè) GPU 通過(guò) PCIe 鏈路連接到主機(jī) CPU,該鏈路最高運(yùn)行速度為 16 GB/s。此外,每個(gè) GPU 還有 6 個(gè) NVLink 連接,每個(gè)連接都能夠雙向傳輸 300 Gbit/s。這相當(dāng)于每個(gè)鏈接每個(gè)方向大約 18 GB/s。簡(jiǎn)而言之,總 NVLink 帶寬明顯高于 PCIe 帶寬。問(wèn)題是如何最有效地使用它。
事實(shí)證明,最佳同步策略是將網(wǎng)絡(luò)分解為兩個(gè)環(huán),并使用它們直接同步數(shù)據(jù) (Wang et al. , 2018)。圖 13.7.5 說(shuō)明網(wǎng)絡(luò)可以分解為具有雙 NVLink 帶寬的一個(gè)環(huán) (1-2-3-4-5-6-7-8-1) 和一個(gè) (1-4-6-3- 5-8-2-7-1) 具有常規(guī)帶寬。在這種情況下設(shè)計(jì)高效的同步協(xié)議并非易事。
考慮以下思想實(shí)驗(yàn):給定一環(huán)n 計(jì)算節(jié)點(diǎn)(或 GPU),我們可以將梯度從第一個(gè)節(jié)點(diǎn)發(fā)送到第二個(gè)節(jié)點(diǎn)。在那里它被添加到局部梯度并發(fā)送到第三個(gè)節(jié)點(diǎn),依此類推。后n?1步驟聚合梯度可以在最后訪問(wèn)的節(jié)點(diǎn)中找到。也就是說(shuō),聚合梯度的時(shí)間隨著節(jié)點(diǎn)的數(shù)量線性增長(zhǎng)。但如果我們這樣做,算法效率會(huì)很低。畢竟,任何時(shí)候都只有一個(gè)節(jié)點(diǎn)在通信。如果我們把梯度分解成 n塊并開(kāi)始同步塊i從節(jié)點(diǎn)開(kāi)始i?由于每個(gè)塊的大小1/n現(xiàn)在的總時(shí)間(n?1)/n≈1. 換句話說(shuō),隨著我們?cè)黾迎h(huán)的大小,聚合梯度所花費(fèi)的時(shí)間不會(huì)增加。這是一個(gè)相當(dāng)驚人的結(jié)果。圖 13.7.6 說(shuō)明了步驟的順序n=4節(jié)點(diǎn)。
如果我們使用跨 8 個(gè) V100 GPU 同步 160 MB 的相同示例,我們將得到大約 2?160MB/(3?18GB/s)≈6ms. 這比使用 PCIe 總線要好,即使我們現(xiàn)在使用 8 個(gè) GPU。請(qǐng)注意,在實(shí)踐中,這些數(shù)字會(huì)更糟一些,因?yàn)樯疃葘W(xué)習(xí)框架通常無(wú)法將通信組合成大量突發(fā)傳輸。
請(qǐng)注意,有一個(gè)常見(jiàn)的誤解,認(rèn)為環(huán)同步與其他同步算法根本不同。唯一的區(qū)別是與簡(jiǎn)單的樹(shù)相比,同步路徑稍微復(fù)雜一些。
13.7.3。多機(jī)訓(xùn)練
在多臺(tái)機(jī)器上進(jìn)行分布式訓(xùn)練增加了一個(gè)進(jìn)一步的挑戰(zhàn):我們需要與僅通過(guò)相對(duì)較低帶寬的結(jié)構(gòu)連接的服務(wù)器進(jìn)行通信,在某些情況下,這種結(jié)構(gòu)的速度可能會(huì)慢一個(gè)數(shù)量級(jí)以上。跨設(shè)備同步很棘手。畢竟,不同機(jī)器運(yùn)行訓(xùn)練代碼的速度會(huì)有細(xì)微差別。因此,如果我們想使用同步分布式優(yōu)化, 我們需要同步它們。圖 13.7.7說(shuō)明了分布式并行訓(xùn)練是如何發(fā)生的。
-
在每臺(tái)機(jī)器上讀?。ú煌模┮慌鷶?shù)據(jù),將其拆分到多個(gè) GPU 并傳輸?shù)?GPU 內(nèi)存。預(yù)測(cè)和梯度分別在每個(gè) GPU 批次上計(jì)算。
-
來(lái)自所有本地 GPU 的梯度聚合在一個(gè) GPU 上(或其中的一部分聚合在不同的 GPU 上)。
-
梯度被發(fā)送到 CPU。
-
CPU 將梯度發(fā)送到聚合所有梯度的中央?yún)?shù)服務(wù)器。
-
然后使用聚合梯度來(lái)更新參數(shù),并將更新后的參數(shù)廣播回各個(gè) CPU。
-
信息被發(fā)送到一個(gè)(或多個(gè))GPU。
-
更新后的參數(shù)分布在所有 GPU 上。
這些操作中的每一個(gè)看起來(lái)都相當(dāng)簡(jiǎn)單。而且,事實(shí)上,它們可以在一臺(tái)機(jī)器上高效地執(zhí)行。但是,一旦我們查看多臺(tái)機(jī)器,我們就會(huì)發(fā)現(xiàn)中央?yún)?shù)服務(wù)器成為瓶頸。畢竟每臺(tái)服務(wù)器的帶寬是有限的,因此對(duì)于m工作人員將所有梯度發(fā)送到服務(wù)器所需的時(shí)間是O(m). 我們可以通過(guò)增加服務(wù)器數(shù)量來(lái)突破這個(gè)障礙n. 此時(shí)每臺(tái)服務(wù)器只需要存儲(chǔ)O(1/n)的參數(shù),因此更新和優(yōu)化的總時(shí)間變?yōu)?O(m/n). 無(wú)論我們正在處理多少工人,匹配這兩個(gè)數(shù)字都會(huì)產(chǎn)生恒定的縮放比例。在實(shí)踐中,我們使用同一臺(tái)機(jī)器作為工作人員和服務(wù)器。 圖 13.7.8說(shuō)明了該設(shè)計(jì)(詳見(jiàn) ( Li et al. , 2014 ))。特別是,確保多臺(tái)機(jī)器在沒(méi)有不合理延遲的情況下工作是非常重要的。
評(píng)論
查看更多