從裸機(jī)到700億參數(shù)大模型,這里有份教程,還有現(xiàn)成可用的腳本
我們知道 LLM 是在大規(guī)模計(jì)算機(jī)集群上使用海量數(shù)據(jù)訓(xùn)練得到的,機(jī)器之心曾介紹過(guò)不少用于輔助和改進(jìn) LLM 訓(xùn)練流程的方法和技術(shù)。而今天,我們要分享的是一篇深入技術(shù)底層的文章,介紹如何將一堆連操作系統(tǒng)也沒(méi)有的「裸機(jī)」變成用于訓(xùn)練 LLM 的計(jì)算機(jī)集群。
這篇文章來(lái)自于 AI 初創(chuàng)公司 Imbue,該公司致力于通過(guò)理解機(jī)器的思維方式來(lái)實(shí)現(xiàn)通用智能。
當(dāng)然,將一堆連操作系統(tǒng)也沒(méi)有的「裸機(jī)」變成用于訓(xùn)練 LLM 的計(jì)算機(jī)集群并不是一個(gè)輕松的過(guò)程,充滿(mǎn)了探索和試錯(cuò),但 Imbue 最終成功訓(xùn)練了一個(gè) 700 億參數(shù)的 LLM,并在此過(guò)程中積累了許多有用的經(jīng)驗(yàn)。
本文將深入介紹該團(tuán)隊(duì)構(gòu)建自己的 LLM 訓(xùn)練基礎(chǔ)設(shè)施的全過(guò)程,并會(huì)分享他們?yōu)榉奖惚O(jiān)控、檢查和糾錯(cuò)而編寫(xiě)的諸多工具和腳本。
如果你有心構(gòu)建自己的 LLM 訓(xùn)練基礎(chǔ)設(shè)施或好奇 LLM 是如何煉成的,那么這篇文章值得你閱讀和收藏。
以下是 Imbue 團(tuán)隊(duì)文章原文。
引言
我們這個(gè)由研究者和工程師組成的小團(tuán)隊(duì)用了幾個(gè)月時(shí)間在自己的基礎(chǔ)設(shè)施上從頭開(kāi)始訓(xùn)練了一個(gè) 700 億參數(shù)量的模型,并且該模型在推理相關(guān)的任務(wù)上勝過(guò)了零樣本的 GPT-4o。
今天,我們要分享的是設(shè)置所需基礎(chǔ)設(shè)施的過(guò)程:從組合初始集群和安裝操作系統(tǒng)到設(shè)置在訓(xùn)練期間遭遇錯(cuò)誤時(shí)自動(dòng)恢復(fù)。我們會(huì)詳細(xì)說(shuō)明在每一步遭遇到的難題和解決方法。除了這些心得之外,我們還將發(fā)布我們一路上開(kāi)發(fā)的許多腳本,以便其他團(tuán)隊(duì)能更輕松地為自己的模型訓(xùn)練創(chuàng)建穩(wěn)定的基礎(chǔ)設(shè)施。
在整個(gè)過(guò)程中,我們的工程師團(tuán)隊(duì)與 Voltage Park 一起準(zhǔn)備好了計(jì)算機(jī)集群,構(gòu)建了生產(chǎn)應(yīng)用的基礎(chǔ)。這整個(gè)過(guò)程包括:
1. 配置各臺(tái)機(jī)器
2. 配置 InfiniBand
3. 確保機(jī)器完全健康
4. 診斷常見(jiàn)的訓(xùn)練問(wèn)題
5. 改進(jìn)基礎(chǔ)設(shè)施工具
下面將詳細(xì)描述每個(gè)步驟。
背景:這是如何煉成的
我們執(zhí)行計(jì)算的目標(biāo)是確保能快速實(shí)驗(yàn)大型語(yǔ)言模型。為此,我們需要大量高速 GPU,并且這些 GPU 之間也能高速通信。
本文將重點(diǎn)關(guān)注一個(gè)集群,其中包含分散在 511 臺(tái)計(jì)算機(jī)中的 4088 臺(tái) H100 GPU,也就是每臺(tái)計(jì)算機(jī) 8 臺(tái) GPU。之所以有 511 臺(tái)帶 GPU 的計(jì)算機(jī),是因?yàn)樾枰A粢恍┻B接給統(tǒng)一結(jié)構(gòu)管理器(Unified Fabric Manager)節(jié)點(diǎn),其作用是管理 InfiniBand 網(wǎng)絡(luò)。在 511 臺(tái)帶 GPU 的主機(jī)上,每臺(tái) GPU 都直接與一塊 ConnectX-7 網(wǎng)卡相連,其能以 400 Gbps 的速度與該 InfiniBand 網(wǎng)絡(luò)中的任意 GPU 傳輸數(shù)據(jù)。
我們的 InfiniBand 網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)的形式是「fully non-blocking」,即完全無(wú)阻塞;理論上講,這能讓 GPU 以最大速度互相通信。為此,我們使用了一種三層式 InfiniBand 網(wǎng)絡(luò)架構(gòu):三層 InfiniBand 交換機(jī)。只要連接正確,便能讓整個(gè)網(wǎng)絡(luò)都獲得這樣高水平的吞吐量。下圖展示了這個(gè) InfiniBand 網(wǎng)絡(luò)的概況:
請(qǐng)注意,訓(xùn)練網(wǎng)絡(luò)時(shí)的通信發(fā)生在 InfiniBand 上,而不是以太網(wǎng)上。盡管這些機(jī)器也連接了以太網(wǎng),但該網(wǎng)絡(luò)的作用是傳輸數(shù)據(jù)集和檢查點(diǎn)等數(shù)據(jù)。如果使用以太網(wǎng)來(lái)發(fā)送數(shù)據(jù),速度會(huì)慢得多,因?yàn)閿?shù)據(jù)會(huì)先從 GPU 傳輸?shù)?CPU,然后再通過(guò) 100 Gbps 速度的以太網(wǎng)卡發(fā)出去。盡管也可以使用名為 RDMA over Converged Ethernet(RoCE)的技術(shù)基于以太網(wǎng)進(jìn)行訓(xùn)練,但那需要在硬件和軟件方面都做大量額外工作,并且可靠程度通常也不及 InfiniBand。詳情可參閱這篇論文:https://arxiv.org/pdf/2402.15627
另外還有一個(gè)僅用于配置和管理的輔助以太網(wǎng),從而可訪(fǎng)問(wèn) BIOS(基本輸入輸出系統(tǒng))、電源和其他低層機(jī)器接口的控制界面。如果沒(méi)有這個(gè)管理網(wǎng)絡(luò),我們就必須通過(guò) USB 驅(qū)動(dòng)、鍵盤(pán)和顯示器來(lái)手動(dòng)設(shè)置每個(gè)節(jié)點(diǎn)。對(duì)于有幾百臺(tái)機(jī)器的情況,這并非一種可持續(xù)的方法。
要在這個(gè)集群上實(shí)現(xiàn)高性能訓(xùn)練,就需要每個(gè)組件(InfiniBand、以太網(wǎng)、GPU 和節(jié)點(diǎn)本身)都近乎完美地工作。如果這 12,000 多個(gè)連接中有任何一個(gè)有點(diǎn)不穩(wěn)定,就會(huì)拖慢整體的訓(xùn)練運(yùn)行速度。
本文接下來(lái)的內(nèi)容就是介紹如何讓這一切都完美且穩(wěn)定地運(yùn)行。
過(guò)程:如何將裸機(jī)變成完全可運(yùn)行的集群
配置各臺(tái)機(jī)器
在通過(guò)管理網(wǎng)絡(luò)建立了與集群的初始以太網(wǎng)連接之后,就獲得了基板管理控制器(BMC/baseboard management controller)的訪(fǎng)問(wèn)憑證。BMC 是一種遠(yuǎn)程監(jiān)控主機(jī)系統(tǒng)的專(zhuān)用服務(wù)處理器,并且通常連接到一個(gè)分立的網(wǎng)絡(luò)。它能讓我們就像是親身在現(xiàn)場(chǎng)一樣操作機(jī)器,并還額外提供了硬件健康狀況、BIOS 設(shè)置和電源管理的 API。
配備好這些組件后,我們就可以擼起袖子,開(kāi)始設(shè)置集群了。
- 步驟 0:先配置好一臺(tái)機(jī)器
我們首先使用 iDRAC(戴爾的基板管理控制器)在一臺(tái)服務(wù)器上安裝 Ubuntu 22.04,然后再基于這個(gè)操作系統(tǒng)設(shè)置其他一切。iDRAC 的一項(xiàng)能力是允許從本地計(jì)算機(jī)安裝和啟動(dòng) ISO 鏡像,并通過(guò)瀏覽器提供一個(gè)虛擬控制臺(tái)。理想情況下,這是該過(guò)程中唯一的手動(dòng)安裝步驟。
- 步驟 1:在每臺(tái)機(jī)器上安裝操作系統(tǒng)
在配置完第一臺(tái)機(jī)器之后,繼續(xù)安裝 Ubuntu 的 Metal-as-a-Service (MAAS) 軟件以幫助配置剩余的服務(wù)器。使用預(yù)啟動(dòng)執(zhí)行環(huán)境協(xié)議(PXE)啟動(dòng)和自動(dòng)化 iDRAC 工具,可指示每臺(tái)機(jī)器從網(wǎng)絡(luò)啟動(dòng)并配置 MAAS 以響應(yīng) PXE 啟動(dòng)請(qǐng)求。在執(zhí)行初始的網(wǎng)絡(luò)啟動(dòng)時(shí),服務(wù)器會(huì)通過(guò)動(dòng)態(tài) IP 分配協(xié)議 DHCP 從 MAAS 獲得一個(gè) IP 和一個(gè)初始內(nèi)核,而無(wú)需在本地驅(qū)動(dòng)器上安裝任何東西。這是用于自動(dòng)重復(fù)執(zhí)行操作系統(tǒng)安裝的基本環(huán)境。從理論上講,我們只需等待第一次啟動(dòng),然后一切都會(huì)被處理好。但實(shí)際上,MAAS 與 BMC 的整合并不可靠,因此我們使用 iDRAC API 來(lái)事先收集每臺(tái)機(jī)器的 MAC 地址(一種唯一的物理硬件標(biāo)識(shí)符)。
在這整個(gè)訓(xùn)練過(guò)程中,MAAS 通常是椎棧中比較可靠的組件。但是,我們?cè)陂_(kāi)始時(shí)遇到了一些我們的設(shè)置特有的問(wèn)題。舉個(gè)例子,在配置前幾臺(tái)機(jī)器時(shí),由于時(shí)鐘相差太大,HTTPS 證書(shū)驗(yàn)證問(wèn)題導(dǎo)致無(wú)法通過(guò) apt 安裝任何東西。與此相關(guān)的是,由于 MAAS 服務(wù)器必須負(fù)責(zé)很多事情(DHCP 服務(wù)器、用于將主機(jī)名解析成 IP 的 DNS 服務(wù)器、主機(jī)和官方 Ubuntu 軟件包服務(wù)器之間的 HTTP 代理、NTP 服務(wù)器、cloud-init 配置管理、用于將 MAC 地址連接到 IP 到主機(jī)名再到自定義元數(shù)據(jù)的 ground truth 數(shù)據(jù)庫(kù)),因此我們很難從根源上解決這些問(wèn)題。此外,還有 MAAS 配置生命周期的學(xué)習(xí)曲線(xiàn)問(wèn)題,因?yàn)槭窃O(shè)計(jì)目標(biāo)是處理管理綠地部署(greenfield deployment)的復(fù)雜性以及節(jié)點(diǎn)的逐步遷移和各種調(diào)試 / 不健康的中間狀態(tài)。
- 步驟 2:診斷損壞的機(jī)器
我們發(fā)現(xiàn)大約 10% 的機(jī)器都無(wú)法啟動(dòng),主要原因是服務(wù)器的物理問(wèn)題。這是設(shè)置大型 GPU 集群的常見(jiàn)情況。我們遇到的情況包括:沒(méi)接網(wǎng)線(xiàn)或接錯(cuò)了網(wǎng)線(xiàn)、iDRAC 中的硬件問(wèn)題、電源單元損壞、NVME(快速非易失性?xún)?nèi)存)驅(qū)動(dòng)損壞、內(nèi)部線(xiàn)路缺失、網(wǎng)卡或 GPU 無(wú)法顯示。我們自動(dòng)檢查了這些問(wèn)題,將一些機(jī)器退回給了戴爾以重新測(cè)試,并為數(shù)據(jù)中心工作人員提交相應(yīng)的工單。我們自己上手配置集群的一個(gè)優(yōu)勢(shì)是:在等待維護(hù)某些機(jī)器的同時(shí)就能立即使用健康的機(jī)器。
- 步驟 3:最小可行可觀(guān)察機(jī)器
我們繼續(xù)在每臺(tái)服務(wù)器上進(jìn)行如下設(shè)置:
1.Docker(以便更輕松地運(yùn)行服務(wù)和訓(xùn)練作業(yè))
2. 數(shù)據(jù)中心 GPU 驅(qū)動(dòng)
3.Prometheus 節(jié)點(diǎn)導(dǎo)出工具(用于導(dǎo)出穩(wěn)定的硬件 / 操作系統(tǒng)指標(biāo)數(shù)據(jù)流)
4.DCGM 導(dǎo)出工具(用于從英偉達(dá) GPU 導(dǎo)出額外的指標(biāo)數(shù)據(jù),如 GPU 狀態(tài)、時(shí)鐘、利用率)
5. 所有非操作系統(tǒng)驅(qū)動(dòng)的 RAIDZ ZFS 池,這讓機(jī)器在某個(gè)驅(qū)動(dòng)失效時(shí)也能繼續(xù)工作,同時(shí)還能免費(fèi)提供透明的壓縮(這對(duì)純文本數(shù)據(jù)集和重復(fù)性日志尤其有用 —— 相比于不使用該工具,使用該工具通常能將可使用的空間增大 10 倍)
然后我們運(yùn)行基本的 GPU 診斷以確定 GPU 是否大體功能正常 —— 不正常的通常會(huì)在幾個(gè)小時(shí)內(nèi)出現(xiàn)硬件問(wèn)題。
在此期間,當(dāng)我們?cè)噲D同時(shí)在全部 400 個(gè)節(jié)點(diǎn)上安裝軟件包時(shí),我們?cè)庥隽藥捚款i。這是我們第一次在數(shù)據(jù)中心部署的多個(gè)組件上收到高溫過(guò)熱警報(bào)。這首批發(fā)熱問(wèn)題基本上都通過(guò)固件更新得到了解決。
- 步驟 4:?jiǎn)喂?jié)點(diǎn)的 GPU 訓(xùn)練
下一步是確保每臺(tái)機(jī)器都能夠單獨(dú)處理真實(shí)的 GPU 工作負(fù)載。很多機(jī)器都無(wú)法做到這一點(diǎn),問(wèn)題包括:
- GPU 相關(guān)的錯(cuò)誤,這類(lèi)問(wèn)題基本都可通過(guò)將 GPU 卡重新插入卡槽來(lái)解決:將 200 磅重的服務(wù)器從機(jī)架上滑出來(lái),移除機(jī)蓋和 GPU 之間的所有線(xiàn)纜,然后取出 GPU,再重新裝上 GPU,之后再重新接上線(xiàn)纜并把服務(wù)器推回機(jī)架。
- 根據(jù) Ubuntu 服務(wù)器日志,GPU 和 PCIe 總線(xiàn)或網(wǎng)卡之間的許多線(xiàn)纜都發(fā)出了這樣的報(bào)錯(cuò):「limited width: x4 < x16」。在更新 PCIe 交換機(jī)總線(xiàn)固件后,我們發(fā)現(xiàn)大約四分之一的主機(jī)需要重新安裝內(nèi)部 PCIe 線(xiàn)纜 —— 大概是因?yàn)橥鈿ず?GPU 之間的線(xiàn)纜相當(dāng)脆弱,這意味著每當(dāng)對(duì) GPU 進(jìn)行維護(hù)時(shí),這些線(xiàn)纜都會(huì)被推擠或拔掉。
- 還有一些雜項(xiàng)故障也影響了幾臺(tái)主機(jī)。戴爾通過(guò)固件升級(jí)幫助我們解決了一些問(wèn)題:
- NVMe 驅(qū)動(dòng)器沒(méi)有顯示故障,但觸摸時(shí)會(huì)鎖定整臺(tái)機(jī)器。
- 硬盤(pán)驅(qū)動(dòng)器在 Linux 下以隨機(jī)順序顯示,這給 MAAS 造成了混亂,并會(huì)導(dǎo)致操作系統(tǒng)被安裝在錯(cuò)誤的驅(qū)動(dòng)器上。
- 溫度讀數(shù)錯(cuò)誤,這會(huì)導(dǎo)致風(fēng)扇一直全速運(yùn)轉(zhuǎn)。其原因可能是英偉達(dá)驅(qū)動(dòng)有問(wèn)題,這通過(guò)降級(jí)驅(qū)動(dòng)版本而得到了解決。
- CPU 的動(dòng)態(tài)調(diào)頻失控,將工作內(nèi)核限制為 2 GHz。
- 直接的 GPU-GPU 通信(GDR 或 GPUDirect RDMA Peer Memory Client)無(wú)法成功應(yīng)用。
配置 InfiniBand
- 步驟 0:安裝 UFM
InfiniBand 的一個(gè)優(yōu)勢(shì)是其中心化的設(shè)計(jì),這樣一來(lái)整個(gè)網(wǎng)絡(luò)就有了一個(gè)大腦。因此,對(duì)于整個(gè)網(wǎng)絡(luò)結(jié)構(gòu)中的 320 個(gè)網(wǎng)絡(luò)交換機(jī),我們只需處理其中一個(gè)實(shí)例。我們的首個(gè)任務(wù)是搞清楚哪臺(tái)交換機(jī)連接了哪些機(jī)器,然后將其與接線(xiàn)圖關(guān)聯(lián)起來(lái),并根據(jù)交換機(jī)的物理位置重新命名它們。
- 步驟 1:重新布線(xiàn)
一開(kāi)始,UFM 無(wú)法檢測(cè)到那 320 臺(tái)交換機(jī),更別說(shuō)本應(yīng)出現(xiàn)在網(wǎng)絡(luò)結(jié)構(gòu)中的主機(jī)了。在與我們的數(shù)據(jù)中心合作伙伴商討之后,我們確認(rèn)這些交換機(jī)已通電并接好了線(xiàn),但依然無(wú)法檢測(cè)到。在檢查網(wǎng)絡(luò)布線(xiàn)列表后,我們注意到該網(wǎng)絡(luò)結(jié)構(gòu)的頂層設(shè)計(jì)有誤:這個(gè)結(jié)構(gòu)不是統(tǒng)一的,而是分成了八個(gè)沒(méi)有公共路由路徑的互相脫離的網(wǎng)絡(luò)。在重新接線(xiàn)之后,我們添加了檢查步驟,以驗(yàn)證所有物理連接是否與新設(shè)計(jì)一致。
- 步驟 2:一萬(wàn)次溫度告警(alert)
在解決了物理接線(xiàn)問(wèn)題之后,InfiniBand 成功建立了與網(wǎng)絡(luò)結(jié)構(gòu)中所有 InfiniBand 交換機(jī)的聯(lián)系。但是,幾乎每個(gè)交換機(jī)端口都開(kāi)始報(bào)告溫度過(guò)高,有時(shí)候超過(guò) 70 ℃,即便它們還沒(méi)有傳輸數(shù)據(jù)。我們發(fā)現(xiàn)這個(gè)問(wèn)題源自同一機(jī)架中交換機(jī)之間的開(kāi)放空間,這導(dǎo)致熱空氣回流到了前面。我們的數(shù)據(jù)中心合作伙伴幫助我們快速診斷出了該問(wèn)題并制定了合適的解決方法。
- 步驟 3:1800 次告警
許多端口還有很高的錯(cuò)誤率,或在正常和損壞狀態(tài)之間來(lái)回變動(dòng),這被稱(chēng)為「抖動(dòng)(flapping)」。這些問(wèn)題只有在實(shí)際使用這些端口時(shí)才會(huì)出現(xiàn),所以很難預(yù)先檢測(cè),因?yàn)槲覀兊恼麄€(gè)結(jié)構(gòu)由 10,000 條高度冗余的鏈路組成。我們的數(shù)據(jù)中心合作伙伴幫助清潔和重新安裝告警的端口,我們?cè)诘却鎿Q時(shí)禁用了剩余的警報(bào)收發(fā)器。
盡管 InfiniBand 能彈性地應(yīng)對(duì)硬件故障,但一旦大約 10% 的結(jié)構(gòu)開(kāi)始出現(xiàn)問(wèn)題,自適應(yīng)路由等功能就無(wú)法可靠地運(yùn)行,無(wú)法解決偶爾丟失鏈路的問(wèn)題。
在此期間,我們成功使用 100 到 200 臺(tái)機(jī)器運(yùn)行了多節(jié)點(diǎn)訓(xùn)練。我們的流程比較即興:我們有時(shí)會(huì)隨機(jī)啟動(dòng)一組節(jié)點(diǎn),觀(guān)察它們的性能,然后盡力讓其中盡可能多的節(jié)點(diǎn)保持運(yùn)行。該方法可讓我們找到該 InfiniBand 網(wǎng)絡(luò)結(jié)構(gòu)中一組可靠的子集,但難度卻很大,因?yàn)槊看味夹枰淖冇糜谟?xùn)練的節(jié)點(diǎn)集合,由此改變默認(rèn)的 InfiniBand 鏈路。
- 步驟 4:InfiniBand 瘋狂燃燒
為了更高效地診斷 InfiniBand 問(wèn)題,我們專(zhuān)門(mén)為整個(gè)集群設(shè)計(jì)了一個(gè)工作負(fù)載,其作用是同時(shí)將盡可能多的數(shù)據(jù)推送經(jīng)過(guò)整個(gè)結(jié)構(gòu)中的每個(gè)端口。這不同于在整個(gè)集群上運(yùn)行一個(gè)大型的 all-reduce 工作負(fù)載,這需要使用 NCCL 來(lái)優(yōu)化各個(gè)節(jié)點(diǎn)之中的通信,方法是使用 NVLink 經(jīng)由 Server PCIe Module (SXM) 插槽來(lái)實(shí)現(xiàn) GPU 通信。
相反,我們選擇了一種蠻力方法,并輕松取得了成功。UFM 會(huì)在大多數(shù)端口的數(shù)據(jù)傳輸量超過(guò)理論容量的 97% 時(shí)開(kāi)始發(fā)出警報(bào),同時(shí)一些交換機(jī)會(huì)暫時(shí)宕機(jī)。我們認(rèn)為能堅(jiān)持到當(dāng)天結(jié)束時(shí)的每個(gè)端口都是足夠穩(wěn)健的,其余的都被禁用或移除以待維修。
- 步驟 5:GPUDirect RDMA
要讓 GPU 通信時(shí)不產(chǎn)生 CPU 計(jì)算開(kāi)銷(xiāo),我們啟用了一個(gè)名為 GPUDirect RDMA 的功能,其允許 InfiniBand 網(wǎng)卡之間直接通信。這涉及兩個(gè)關(guān)鍵步驟:
1. 啟動(dòng)一個(gè)額外的核模塊
2. 確保 PCIe Access Control Service (ACS) 被禁用,以防止 immediate hangs(立即掛起)
- 步驟 6:擴(kuò)增「黃金」服務(wù)器
要使用最新硬件構(gòu)建 GPU 集群,一個(gè)經(jīng)驗(yàn)法則是:每周都有大約 3% 的機(jī)器出問(wèn)題,要做好準(zhǔn)備。
但是,需要說(shuō)明一點(diǎn):并不是每臺(tái)機(jī)器都統(tǒng)一有 3% 的幾率發(fā)生故障,而是少量不對(duì)付的機(jī)器反復(fù)出現(xiàn)各種不同問(wèn)題,直到將它們妥善修復(fù)。這就凸顯了在同一網(wǎng)絡(luò)結(jié)構(gòu)中配備大量機(jī)器的優(yōu)勢(shì)。因此,我們的做法不是隨便找些機(jī)器來(lái)運(yùn)行大規(guī)模訓(xùn)練,就像打地鼠一樣看哪些出問(wèn)題,而是專(zhuān)注于擴(kuò)增已知可靠的服務(wù)器,也就是「黃金」服務(wù)器。
- 步驟 7:維護(hù)
InfiniBand 的維護(hù)主要涉及到響應(yīng) UFM 警報(bào)、更換故障線(xiàn)纜和收發(fā)器,以及偶爾診斷更困難的錯(cuò)誤(比如交換機(jī)故障)。導(dǎo)致大規(guī)模維護(hù)的因素通常有兩個(gè):
1. 固件更新,尤其是集群中僅有一半完成更新時(shí),這可能導(dǎo)致 UFM 狀態(tài)損壞并必需重啟所有 InfiniBand 交換機(jī)上的 UFM。
2.GPU 盒同時(shí)大規(guī)模重啟,這可能會(huì)向 UFM 狀態(tài)灌入大量更新,并同樣需要重啟 UFM 服務(wù)。
確保機(jī)器完全健康
在此過(guò)程中,我們發(fā)現(xiàn)了單臺(tái)機(jī)器的多種故障或減慢訓(xùn)練速度的方式。其中許多故障模式并不會(huì)立即顯現(xiàn),因此我們編寫(xiě)了許多健康檢查腳本,以檢查主機(jī)是否足夠健康。我們?cè)谶@里發(fā)布了這些代碼:https://github.com/imbue-ai/cluster-health
請(qǐng)注意,這些健康檢查中的很多都特定于我們的運(yùn)行時(shí)環(huán)境,并不一定與基礎(chǔ)硬件相關(guān),也不一定容易修復(fù)或自動(dòng)化。這是設(shè)計(jì)決定的:為了實(shí)現(xiàn)讓我們的機(jī)器準(zhǔn)備好訓(xùn)練的總體目標(biāo),我們想要一個(gè)可以直接了當(dāng)?shù)鼗卮稹甘恰够颉阜瘛沟膯我蝗肟邳c(diǎn),并且可以概括總結(jié)任意數(shù)量的細(xì)微細(xì)節(jié)。
- GPU 健康檢查
我們檢查了 GPU 數(shù)量是否正確、ECC(錯(cuò)誤更正代碼)檢查是否已啟用以及是否存在 ECC 錯(cuò)誤。我們還檢查了 NVLink 拓?fù)洌▽?GPU 彼此連接起來(lái))是否已啟動(dòng)且無(wú)錯(cuò)誤。
- 磁盤(pán)空間健康檢查
我們檢查了主機(jī)的磁盤(pán)空間利用率是否超過(guò) 95%。
- Docker 健康檢查
我們檢查了 Docker 能否在連接了 GPU 的情況下運(yùn)行容器(即 NVIDIA Container Runtime 是否正常工作),還檢查了與監(jiān)控 / 分析相關(guān)的 Docker 容器是否已激活并獲得了正確的主機(jī)權(quán)限。
- Dmesg 健康檢查
我們檢查了 dmesg 中是否存在硬件 Xids 或 SXid 錯(cuò)誤(由 NVIDIA GPU 或 GPU 間 NVIDIA 交換機(jī)引發(fā)的故障)。我們還讀取了所有 dmesg 日志行,以驗(yàn)證它們是否都可以歸類(lèi)到「常見(jiàn) / 預(yù)期日志行」列表中。
- iDRAC 健康檢查
我們檢查了機(jī)器上的 iDRAC 錯(cuò)誤,其中忽略了非致命錯(cuò)誤消息。這是戴爾計(jì)算機(jī)特有的檢查,所以沒(méi)有被包括在我們開(kāi)源的代碼中。
- 磁盤(pán)健康檢查
我們檢查了 zpool 是否已安裝,Docker 是否已正確連接到它,以及它是否真的可以在不鎖定 CPU 的情況下觸及它。
- InfiniBand 健康檢查
我們檢查了 InfiniBand 的錯(cuò)誤率是否會(huì)增加和 / 或驅(qū)動(dòng)固件是否過(guò)時(shí)。
- Nvlink 健康檢查
我們檢查了機(jī)器上的 NVLink 錯(cuò)誤。實(shí)踐中看,這似乎不會(huì)導(dǎo)致訓(xùn)練失敗,但可能會(huì)降低訓(xùn)練速度。
- GDR 健康檢查
我們檢查了機(jī)器上的 GDR 是否已啟用。
- VBIOS 健康檢查
我們檢查了 GPU 的 VBIOS 版本以及 H100 基板固件是否是最新的。
- Flint 健康檢查
我們使用 flint 和 hca_self_test 檢查了 Mellanox OFED 驅(qū)動(dòng)、網(wǎng)卡固件和收發(fā)器固件的版本是否正確,以及它們是否針對(duì)英偉達(dá)驅(qū)動(dòng)進(jìn)行了正確編譯。
- PSB 健康檢查
我們查詢(xún)了 PCIe 設(shè)備,以檢查 GPU、PSB(PCIe 交換機(jī)總線(xiàn))和網(wǎng)卡之間的連接速度和寬度是否符合我們的預(yù)期。我們還檢查了交換機(jī)固件是否為最新版本。該腳本由戴爾而非 Imbue 開(kāi)發(fā),所以我們目前無(wú)法共享它。
除了這些快速健康檢查,我們還進(jìn)行了一些更復(fù)雜的健康檢查,包括:
- 通過(guò) PyTorch 初始化矩陣計(jì)算,以及測(cè)量 NVLink 帶寬和 GPU 計(jì)算速度和內(nèi)存。我們?cè)O(shè)置了適當(dāng)?shù)?GDR 標(biāo)志來(lái)測(cè)試 InfiniBand 和 NVLink。
- 使用 ib_write_bw 和 –use_cuda 通過(guò) IB 卡發(fā)送數(shù)據(jù)并測(cè)量 PCIe 和 InfiniBand 卡帶寬。這個(gè)過(guò)程持續(xù)了較長(zhǎng)時(shí)間(約 15 分鐘),以確保能找出抖動(dòng)的 InfiniBand 鏈路。
- 運(yùn)行多節(jié)點(diǎn)診斷運(yùn)行以檢查 NCCL 初始化能力以及它是否會(huì)隨機(jī)停頓。如有停頓,則我們的分叉版 NCCL 代碼會(huì)添加額外的日志記錄。這需要 12 到 24 小時(shí)才能檢測(cè)到問(wèn)題,因此我們通常只對(duì)新節(jié)點(diǎn)或我們懷疑存在問(wèn)題時(shí)運(yùn)行此操作。
- 檢查 DCGM 導(dǎo)出是否存在任何 GPU 時(shí)鐘節(jié)流事件(不包括預(yù)期的 gpu_idle 和 power_cap)。為了檢查這些電源事件,最好的方法是運(yùn)行多節(jié)點(diǎn)訓(xùn)練,以同時(shí)檢查所有 GPU、InfiniBand 卡以及 CPU 和磁盤(pán)。
診斷常見(jiàn)的訓(xùn)練問(wèn)題
一旦硬件能正常工作,就可以開(kāi)始訓(xùn)練了。
這一節(jié)將基于我們?cè)谖覀兊募荷线\(yùn)行大型語(yǔ)言模型訓(xùn)練的經(jīng)驗(yàn),分享一些具體的調(diào)試步驟和見(jiàn)解。
- 啟動(dòng)時(shí)崩潰
從某種程度上講,這是所能遇到的最好的錯(cuò)誤,因?yàn)槠洌ɡ碚撋希┖苋菀字噩F(xiàn)和迭代。
我們首先檢查了我們的代碼是否在正確的版本、配置和環(huán)境變量上運(yùn)行。雖然很基礎(chǔ),但我們發(fā)現(xiàn)這一點(diǎn)至關(guān)重要:確保啟動(dòng)訓(xùn)練過(guò)程是可復(fù)現(xiàn)且容易檢查的。一大原因是 Docker 鏡像緩存或不透明秘密配置等中間抽象可能會(huì)造成混淆。
我們執(zhí)行的另一個(gè)基礎(chǔ)檢查是確保所有機(jī)器都在線(xiàn),并且可以輕松地聚合和檢查所發(fā)出的棧跟蹤記錄或日志。我們使用了 Loki、Prometheus 和 Grafana 軟件棧,但任何合適的日志聚合或跟蹤 SaaS 的工具都可以。由于這些訓(xùn)練運(yùn)行過(guò)程本質(zhì)上是同步的和分布式的,因此第一個(gè)錯(cuò)誤往往就會(huì)導(dǎo)致一連串的不相關(guān)錯(cuò)誤。在這里,健康檢查還可以幫助立馬檢測(cè)出硬盤(pán)驅(qū)動(dòng)器損壞或 GPU 缺失或無(wú)效等錯(cuò)誤。
我們構(gòu)建了一個(gè)在發(fā)生故障時(shí)自動(dòng)重啟的系統(tǒng),這使得日志和錯(cuò)誤聚合變得更加重要,以避免混淆來(lái)自不同重啟的錯(cuò)誤。我們遇到的一些常見(jiàn)錯(cuò)誤包括:
1.「Forward order differs across ranks: rank 0 is all-gathering 43 parameters while rank 1228 is all-gathering 1 parameters」這樣的錯(cuò)誤。我們發(fā)現(xiàn)這是 PyTorch 完全分片數(shù)據(jù)并行(FSDP)實(shí)現(xiàn)的一個(gè)奇怪特性,可通過(guò)重啟解決。
2.GPU 內(nèi)存不足(OOM)錯(cuò)誤,看起來(lái)像這樣:「CUDA out of memory. Tried to allocate …」通過(guò)多次檢查我們的配置和代碼并撤銷(xiāo)近期的代碼修改(由于啟動(dòng)期間 PyTorch 設(shè)備規(guī)格不正確而導(dǎo)致過(guò)多使用 GPU#0),我們解決了這些問(wèn)題。
3.CPU/RAM 內(nèi)存不足(OOM)錯(cuò)誤,這些錯(cuò)誤在錯(cuò)誤日志中不太容易發(fā)現(xiàn),并且通常能通過(guò) Docker 容器外的主機(jī)的 dmesg 日志檢測(cè)出來(lái)。當(dāng) OOM Killer 調(diào)用停止一個(gè)分叉進(jìn)程或同級(jí)網(wǎng)絡(luò)(network peer)時(shí),我們可以看到它們主要表現(xiàn)為 CalledProcessError 或 ConnectionError。當(dāng)從 dmesg 檢測(cè)到了 OOM Killer 調(diào)用時(shí),我們更傾向于直接放棄健康檢查,并重啟該機(jī)箱。我們還檢查了我們的代碼路徑是否有足夠的手動(dòng)垃圾收集(下面有一部分介紹了如何禁用它),并還檢查了是否有意外嘗試進(jìn)行計(jì)算或?qū)埩恳苿?dòng)到 CPU 上。
- 在訓(xùn)練過(guò)程中崩潰
首要任務(wù)是讓系統(tǒng)能自動(dòng)運(yùn)行,讓其能自動(dòng)重新運(yùn)行所有健康檢查,然后在沒(méi)發(fā)現(xiàn)不健康主機(jī)時(shí)重啟運(yùn)行。我們遇到了一些隨機(jī)的硬件錯(cuò)誤,包括 Xid 和 SXid 錯(cuò)誤;這些錯(cuò)誤可能會(huì)導(dǎo)致運(yùn)行崩潰,卻不會(huì)發(fā)出有意義的 Python 棧跟蹤記錄。行重映射等一些問(wèn)題可通過(guò)重啟恢復(fù)。不可糾正的 ECC 錯(cuò)誤等另一些問(wèn)題則往往需要硬件維護(hù)或更換零件。
此外,我們還觀(guān)察到格式錯(cuò)誤的訓(xùn)練數(shù)據(jù)也會(huì)導(dǎo)致崩潰。舉個(gè)例子,如果語(yǔ)料庫(kù)中有一個(gè)非常大的單個(gè)文檔,就可能導(dǎo)致 GPU 或 CPU 出現(xiàn)內(nèi)存不足錯(cuò)誤。為了防止出現(xiàn)這個(gè)問(wèn)題,我們采用了完全確定式的數(shù)據(jù)加載器 —— 通過(guò)與 epoch 或步數(shù)相關(guān)聯(lián),讓每一次崩潰都可輕松復(fù)現(xiàn)。我們發(fā)現(xiàn)禁用數(shù)據(jù)加載或替換假數(shù)據(jù)(例如全零數(shù)據(jù))有助于確認(rèn)錯(cuò)誤的根本原因是否是數(shù)據(jù)。
最后,通過(guò)指標(biāo)聚合方法記錄網(wǎng)絡(luò)和一般節(jié)點(diǎn)的健康統(tǒng)計(jì)數(shù)據(jù)也很有幫助。以太網(wǎng)短暫斷開(kāi)或磁盤(pán)空間不足等問(wèn)題可能不會(huì)顯示為有用的錯(cuò)誤消息,但卻可以很輕松地與已收集的數(shù)據(jù)相關(guān)聯(lián)。
- 沒(méi)有棧跟蹤信息的掛起(之后可能會(huì)有超時(shí)問(wèn)題)
由于這些問(wèn)題缺乏有幫助的信息,加上很難可靠地復(fù)現(xiàn),因此這類(lèi)錯(cuò)誤的調(diào)試工作著實(shí)讓人沮喪。
其中最令人難忘的錯(cuò)誤類(lèi)型伴隨著這樣的報(bào)錯(cuò)信息:
Watchdog caught collective operation timeout:WorkNCCL (SeqNum=408951, OpType=_ALLGATHER_BASE, … , Timeout (ms)=600000) ran for 600351 milliseconds before timing out
并且訓(xùn)練運(yùn)行中的所有 GPU 工作器都發(fā)出了這樣的報(bào)錯(cuò)信息。
這意味著一臺(tái)或多臺(tái)主機(jī)未能完成 NCCL 操作或者 NCCL 和 InfiniBand 連接崩潰,導(dǎo)致其他所有主機(jī)同時(shí)卡在了某個(gè)張量運(yùn)算上,直到達(dá)到 NCCL_TIMEOUT 超時(shí)時(shí)間。不幸的是,受 NCCL 軟件庫(kù)本質(zhì)所限,我們很難找到究竟是哪臺(tái)主機(jī)出了問(wèn)題。
我們對(duì) NCCL 軟件庫(kù)的日志記錄做了一些修改,參見(jiàn)我們的分叉版:https://github.com/boweiliu/nccl 。從而在崩潰發(fā)生時(shí)可能更好地揭示正在執(zhí)行的消息或操作,從而確定阻止運(yùn)行的可能是哪臺(tái)主機(jī)或 GPU。
請(qǐng)注意,為了識(shí)別行為不當(dāng)?shù)闹鳈C(jī),我們通常需要搞清楚哪些主機(jī)沒(méi)有生成某些日志消息。缺少此類(lèi)消息表明該主機(jī)上的工作器已落后或已崩潰。
其他沒(méi)有可用錯(cuò)誤消息的無(wú)響應(yīng)情況通常與硬件相關(guān)問(wèn)題有關(guān),比如之前提到的 Xid/SXid/ECC 錯(cuò)誤會(huì)導(dǎo)致英偉達(dá)驅(qū)動(dòng)或英偉達(dá) Docker 通信驅(qū)動(dòng)鎖定。為了區(qū)分 NCCL 掛起與驅(qū)動(dòng)掛起以及 Python 代碼中的競(jìng)爭(zhēng)條件或死鎖,我們使用 Py-Spy 和 GNU Project Debugger(GDB)等工具來(lái)實(shí)時(shí)調(diào)試遇到的停滯進(jìn)程。使用此方法可發(fā)現(xiàn)一個(gè)特定問(wèn)題:由于 Python 線(xiàn)程設(shè)置中的配置錯(cuò)誤,我們無(wú)法在某些主機(jī)上正確啟動(dòng)八個(gè)多線(xiàn)程 NCCL GPU 進(jìn)程,這些進(jìn)程在 PyTorch 之前的初始化代碼階段遇到了競(jìng)爭(zhēng)條件。
- 訓(xùn)練減速(由 MFU 測(cè)量)
缺乏工具讓這類(lèi)問(wèn)題比前一類(lèi)更讓人沮喪。除了使用 Py-Spy、棧跟蹤檢查和 GDB 之外,我們還采用了 NVIDIA Nsight 和 profiling 工具,其中一些工具在高度分布式的設(shè)置中很難使用。
遺憾的是,導(dǎo)致一般減速或讓速度低于之前演示的模型浮點(diǎn)數(shù)利用率(MFU)的原因有很多。
首先,事實(shí)證明多次檢查配置、代碼和環(huán)境變量是有用的。我們經(jīng)歷過(guò)的錯(cuò)誤包括:運(yùn)行了錯(cuò)誤的模型、批量大小錯(cuò)誤、UFM 或 NCCL 設(shè)置出錯(cuò)、CUDA_DEVICE_MAX_CONNECTIONS 出錯(cuò)。這都會(huì)導(dǎo)致性能無(wú)法達(dá)到最優(yōu)。
我們還發(fā)現(xiàn)測(cè)量瞬時(shí)(即每批次)MFU(而不是平滑或窗口平均值)很有用,因?yàn)槲雌交幚淼?MFU 曲線(xiàn)通常有助于診斷問(wèn)題類(lèi)別。導(dǎo)致訓(xùn)練速度下降的問(wèn)題包括:
- 從非常低的 MFU(低于預(yù)期的十分之一)立即開(kāi)始訓(xùn)練并保持穩(wěn)定
這多半是 InfiniBand 網(wǎng)絡(luò)連接的硬件問(wèn)題,例如 T2 或 T3 層的交換機(jī)死機(jī)。GPU 和 NIC 之間的硬件問(wèn)題也可能導(dǎo)致該情況,對(duì)此 dmesg 會(huì)這樣報(bào)錯(cuò):PCIe x16 lanes limited by …
- 從預(yù)期 MFU 的 30% 立即開(kāi)始訓(xùn)練并保持穩(wěn)定
其原因可能是一臺(tái)主機(jī)的 GDR 設(shè)置不正確(NVIDIA 對(duì)等內(nèi)存)或 GDR 環(huán)境變量不正確。
- 從預(yù)期 MFU 的約 60-80% 立即開(kāi)始訓(xùn)練并保持穩(wěn)定
最常見(jiàn)的原因是 InfiniBand 鏈路質(zhì)量不行或故障,尤其是單臺(tái) GPU 出現(xiàn)了與 InfiniBand NIC 相關(guān)的故障,導(dǎo)致 NCCL 嘗試經(jīng)由本地 NVLink 路由流量并在同一主機(jī)上的另一臺(tái) GPU 上使用 NIC。CPU 節(jié)流也可能導(dǎo)致該問(wèn)題,這需要調(diào)整某些主機(jī)的 BIOS 設(shè)置。
- 在處理某些數(shù)據(jù)批次時(shí)突然大幅減速(下降 10 倍),并且經(jīng)常發(fā)生這種情況
這基本上都與檢查點(diǎn)或評(píng)估有關(guān) —— 可通過(guò)檢查 epoch 數(shù)或步數(shù)來(lái)驗(yàn)證。惱火的是,如果設(shè)置了在 MFU 異常時(shí)自動(dòng)告警,就會(huì)出現(xiàn)許多誤報(bào)。
- 在處理某些數(shù)據(jù)批次時(shí)突然大幅減速(下降 10 倍)
這種情況是隨機(jī)發(fā)生的并且相當(dāng)罕見(jiàn)(大概每 15 分鐘一次),并且之后馬上就會(huì)完全恢復(fù)到良好的 MFU。
最常見(jiàn)的原因似乎是其他需要大量 CPU 計(jì)算的工作負(fù)載被調(diào)度到了一臺(tái)運(yùn)行中的主機(jī)上。我們發(fā)現(xiàn),與其構(gòu)建分析工具來(lái)識(shí)別特定的主機(jī),通過(guò) PID 來(lái)粗略地監(jiān)控 CPU 會(huì)更容易。其原因可能是偶爾出現(xiàn)的網(wǎng)絡(luò)連接問(wèn)題,比如數(shù)據(jù)加載器遭遇瓶頸。我們監(jiān)控了數(shù)據(jù)加載、檢查點(diǎn)和任何非 NCCL 代碼的指標(biāo)數(shù)據(jù)并添加了 Python 代碼計(jì)時(shí)日志,事實(shí)證明這非??煽俊?/span>
- MFU 在運(yùn)行過(guò)程中逐漸減慢,但每次重啟后又會(huì)回到 100%
理論上講,其原因可能是交換機(jī)上的熱量積累,但我們從未見(jiàn)過(guò)這種情況。不過(guò),我們使用 Python 和 NVIDIA 分析器確定:性能下降的原因似乎是自動(dòng)垃圾收集。
在調(diào)試解決這些減速問(wèn)題時(shí),我們發(fā)現(xiàn)吞吐量幾乎必然會(huì)周期性地下降。隨著訓(xùn)練地推進(jìn),這種下降會(huì)對(duì)分布式運(yùn)算帶來(lái)越來(lái)越多的影響。這讓我們猜想下降的原因可能與自動(dòng)垃圾收集有關(guān) —— 我們通過(guò)分析和測(cè)試驗(yàn)證了這個(gè)猜想。當(dāng)我們禁用了自動(dòng)垃圾收集,并在所有主機(jī)上設(shè)定只在特定的間隔內(nèi)收集垃圾,這種吞吐量「下降」就消失了。
我們使用了一種基于 ZeRO-3 的同步分布式訓(xùn)練算法 FSDP。在阻塞操作期間,運(yùn)行垃圾收集的單個(gè)工作器進(jìn)程可能會(huì)減慢其他所有工作器的速度。如果有數(shù)百個(gè)工作器進(jìn)程,就可能導(dǎo)致速度大幅下降。
一開(kāi)始性能良好,然后突然下降(達(dá)到預(yù)期的 70%),并且以高頻持續(xù)(每 15 秒)
我們觀(guān)察到這與英偉達(dá) GPU 的「時(shí)鐘節(jié)流原因」相關(guān),這可通過(guò)對(duì)英偉達(dá) DCGM 進(jìn)行適當(dāng)?shù)脑O(shè)置來(lái)解決。發(fā)熱問(wèn)題(GPU 高溫或主機(jī)冷卻風(fēng)扇故障 / 效果下降)或電源故障會(huì)導(dǎo)致該問(wèn)題。另外,當(dāng)我們同時(shí)最大化所有 8 臺(tái) GPU 利用率和 8x NIC InfiniBand 利用率以及 CPU/RAM/ 磁盤(pán)時(shí),我們的一些具有特定電源硬件的主機(jī)會(huì)出現(xiàn)電壓?jiǎn)栴},但只有全部使用它們(通常只在實(shí)際訓(xùn)練運(yùn)行期間)時(shí)才會(huì)出現(xiàn)這種情況。
- 性能優(yōu)良但噪聲比平常情況多(高頻白噪聲方差在預(yù)期 MFU 的 90% 和 100% 之間)
這也與 InfiniBand 硬件有關(guān),但通常是由于網(wǎng)絡(luò)中較高層的鏈路出現(xiàn)一定程度的性能下降或抖動(dòng),而不是冗余度較低的主機(jī)到 T2 層。
不幸的是,很多這類(lèi)問(wèn)題都難以定位到某臺(tái)具體主機(jī),而與 InfiniBand 相關(guān)的問(wèn)題尤其難以定位,這是由于 InfiniBand 交換機(jī)技術(shù)的拓?fù)涓兄匦?。InfiniBand 似乎更偏好 InfiniBand fat-tree 設(shè)計(jì)中的相鄰主機(jī),而 UFM 能以不對(duì)稱(chēng)的鏈路速度路由數(shù)據(jù)包。
以下是用于調(diào)試吞吐量問(wèn)題的簡(jiǎn)單摘要 / 流程圖 / 完備性檢查表:
- 這套系統(tǒng)之前能正常工作嗎?
- 你最近做了什么修改(比如合并代碼、更新驅(qū)動(dòng))?
- 你運(yùn)行的主機(jī)是否健康?你的所有依賴(lài)服務(wù)是否都運(yùn)行正常,包括第三方的 SaaS,比如 Docker Hub、GitHub 等等?
- 你能確定現(xiàn)在運(yùn)行的代碼、環(huán)境、配置、版本、主機(jī)列表、排名順序、隨機(jī)種子與上次完全相同嗎?(如果能實(shí)現(xiàn)這樣的檢查的話(huà)。)
- 問(wèn)題可復(fù)現(xiàn)嗎?
- 與其他事物有何關(guān)聯(lián)?其他進(jìn)程?每日 crontab 定時(shí)任務(wù)?主機(jī)或 DCGM 或 UFM 指標(biāo)?
- 你的工具是否能正確度量這些指標(biāo)?
- 在運(yùn)行約簡(jiǎn)版的代碼(使用更小的模型、假數(shù)據(jù)、不保存或加載檢查點(diǎn))時(shí),問(wèn)題是否依然存在?
改進(jìn)基礎(chǔ)設(shè)施工具
完成了以上步驟之后,就能在訓(xùn)練模型時(shí)實(shí)現(xiàn)優(yōu)良性能了…… 至少在某個(gè)地方出故障之前是這樣。
本節(jié)將介紹一些用于確保訓(xùn)練持續(xù)穩(wěn)定的工具和系統(tǒng),同時(shí)最好盡可能地少地需要人類(lèi)干預(yù)。由于我們這個(gè)團(tuán)隊(duì)很小,因此我們沒(méi)有足夠的人手來(lái)進(jìn)行人工維修,所以我們也希望能盡可能地自動(dòng)化這個(gè)過(guò)程。
我們?cè)谟?xùn)練過(guò)程中遇到的所有問(wèn)題幾乎都可歸因于機(jī)器或網(wǎng)絡(luò)組件故障。這類(lèi)故障在大型集群中很常見(jiàn),因此我們的做法是自動(dòng)禁用出故障的機(jī)器和網(wǎng)絡(luò)組件并發(fā)送維修請(qǐng)求。
- 機(jī)器故障
我們開(kāi)發(fā)了一個(gè)系統(tǒng),可在運(yùn)行崩潰時(shí)自動(dòng)從最近的檢查點(diǎn)重啟。在這個(gè)重啟過(guò)程中,首先是對(duì)每臺(tái)可用機(jī)器進(jìn)行健康檢查,然后基于其傳遞的健康檢查結(jié)果對(duì)每臺(tái)機(jī)器進(jìn)行分類(lèi);然后嘗試在最健康的機(jī)器上重啟訓(xùn)練。
- 網(wǎng)絡(luò)組件故障
我們觀(guān)察到的所有網(wǎng)絡(luò)故障都可通過(guò) UFM 檢測(cè)到,并會(huì)被記錄到 UFM 事件日志中,因此響應(yīng)方式也很簡(jiǎn)單:解析 UFM 日志并采取相應(yīng)措施。
UFM 事件系統(tǒng)非常復(fù)雜,包含數(shù)十種事件類(lèi)型。但在實(shí)踐中,我們發(fā)現(xiàn)只有少數(shù)事件有問(wèn)題,主要與鏈路故障或符號(hào)錯(cuò)誤技術(shù)較高有關(guān)。在識(shí)別出這些事件后,我們可以編寫(xiě)腳本來(lái)解析 UFM 事件日志、禁用與最近事件相關(guān)的鏈路和端口、為這些網(wǎng)絡(luò)組件申請(qǐng)維護(hù)工單、維護(hù)完成后重新啟用這些組件。
- 本地鏡像文件系統(tǒng)
對(duì)于這些大型分布式訓(xùn)練,人們很早就發(fā)現(xiàn)集群與以太網(wǎng)的數(shù)據(jù)交換速度是一大瓶頸。一條共享以太網(wǎng)連接的帶寬大約為 10Gbit/s;如果有數(shù)百個(gè)工作器同時(shí)下載數(shù)據(jù)集和模型檢查點(diǎn),那么這點(diǎn)帶寬會(huì)很快飽和。
為此,我們決定在我們集群內(nèi)部構(gòu)建一個(gè)本地文件系統(tǒng),以作為云存儲(chǔ)的鏡像,其本質(zhì)上就是一個(gè)緩存空間,可以減少?gòu)?S3 讀取的文件量。為了解決集群流失問(wèn)題(即因?yàn)榫S修原因而禁用或更換機(jī)器的情況),我們?yōu)槊糠菸募紲?zhǔn)備了三個(gè)副本,并使用了一致性哈希以均勻分配負(fù)載,從而在集群流失期間最大限度地減少文件移動(dòng)。由于集群的磁盤(pán)空間有限,所以我們必須開(kāi)發(fā)多種工具來(lái)跟蹤文件的生命周期和清除不再有用的文件。
- 本地分布式 Docker 注冊(cè)表
我們使用了 Kraken,這是一個(gè)可點(diǎn)對(duì)點(diǎn)傳輸 Docker 鏡像的出色開(kāi)源軟件。這個(gè)軟件幾乎沒(méi)出現(xiàn)過(guò)任何問(wèn)題,我們還是挺驚訝的,畢竟我們的任務(wù)和實(shí)現(xiàn)都很復(fù)雜。工具地址:https://github.com/uber/kraken
- 各種性能監(jiān)控工具
我們?cè)O(shè)置了默認(rèn)的 Torch 分析器以及英偉達(dá)的 Nsight Systems。后者可幫助我們了解前向 / 反向通過(guò)以及 NCCL 通信所需的確切時(shí)間,并進(jìn)一步幫助我們確定給定的模型大小和工作器數(shù)量是否會(huì)成為瓶頸。然而,Nsight Systems 有點(diǎn)難用,因?yàn)槠湫枰谔貦?quán)模式下運(yùn)行 Docker,這需要禁用與性能監(jiān)控事件相關(guān)的安全檢查,并且保存其配置時(shí)往往需要停止整個(gè)訓(xùn)練進(jìn)程。
此外,我們也編寫(xiě)了工具來(lái)檢測(cè)訓(xùn)練速度慢的數(shù)據(jù)批次并理解其可能原因。我們發(fā)現(xiàn)這很有用。其中最有用的工具的作用是監(jiān)控每一批次所需的時(shí)間并在某批次過(guò)于慢時(shí)丟棄該工作器的棧跟蹤 —— 這讓我們可以更輕松地找到硬件或軟件有些小問(wèn)題的主機(jī)。
- 將機(jī)器分成不同的組別以定位故障主機(jī)
在使用該集群的前幾個(gè)月(那時(shí)候健康檢查還不如現(xiàn)在這般透徹),我們經(jīng)常遇到這種情況:在一組機(jī)器上訓(xùn)練時(shí)出現(xiàn)故障,但并不清楚究竟是哪臺(tái)機(jī)器有問(wèn)題。為了找到故障主機(jī),我們開(kāi)發(fā)了一些工具,可輕松地把一組機(jī)器分成不同的小組,然后在每個(gè)機(jī)器小組上運(yùn)行更小的訓(xùn)練。
舉個(gè)例子,如果一個(gè)在 48 臺(tái)機(jī)器上運(yùn)行的訓(xùn)練失敗了,那么就在 6 組各 8 臺(tái)機(jī)器上進(jìn)行更小規(guī)模的訓(xùn)練,然后在 8 組各 6 臺(tái)機(jī)器上運(yùn)行更小規(guī)模的訓(xùn)練。通常情況下,這兩個(gè)階段中只有一次運(yùn)行會(huì)失敗,這讓我們有信心得出結(jié)論:在兩個(gè)階段中都出問(wèn)題的機(jī)器是有問(wèn)題的。
反思和學(xué)習(xí)到的經(jīng)驗(yàn)教訓(xùn)
在設(shè)置和維護(hù)基礎(chǔ)設(shè)施的過(guò)程中,我們獲得了一些有用的經(jīng)驗(yàn)教訓(xùn):
- 一種有用的做法是交換機(jī)器的位置。在運(yùn)行時(shí),使用多于所需機(jī)器數(shù)量 10-20% 的機(jī)器會(huì)很有幫助,這樣就能在機(jī)器故障時(shí)輕松重啟訓(xùn)練了。設(shè)置集群網(wǎng)絡(luò)連接時(shí)讓每臺(tái)機(jī)器都與其他每臺(tái)機(jī)器緊密相連,這樣一來(lái)我們就能使用這些機(jī)器中任意可工作的子集。
- 對(duì)遇到的每一個(gè)硬件或軟件故障,編寫(xiě)測(cè)試和自動(dòng)化解決方案是值得的,因?yàn)橛?xùn)練中遇到的每一個(gè)問(wèn)題都會(huì)再次出現(xiàn)。類(lèi)似地,對(duì)于每一個(gè)含混不清的報(bào)錯(cuò)消息,都值得編寫(xiě)更能解釋該錯(cuò)誤的工具。
- 可重復(fù)性是優(yōu)秀科研的關(guān)鍵。我們立馬就采用的一大原則是:「一次只修改一個(gè)地方」,即便最簡(jiǎn)單的地方也是如此。
- 信任,但也要驗(yàn)證。每當(dāng)我們引入外部工具或加入新人員(無(wú)論是來(lái)自公司內(nèi)還是公司外)時(shí),我們都會(huì)仔細(xì)檢查他們聲稱(chēng)的東西,尤其是當(dāng)后續(xù)步驟依賴(lài)于這些聲稱(chēng)的東西時(shí)。
總結(jié)
訓(xùn)練大型語(yǔ)言模型一開(kāi)始就需要復(fù)雜的基礎(chǔ)設(shè)施。我們之所以選擇深入?yún)⑴c基礎(chǔ)設(shè)施的設(shè)置細(xì)節(jié),是因?yàn)槲覀兿嘈磐耆斫馕覀儾僮鞯南到y(tǒng)是非常重要的,也因?yàn)槲覀冋J(rèn)為這樣做的效率更高。
現(xiàn)在,經(jīng)歷過(guò)整個(gè)流程之后,我們很高興我們采用了這樣的方法 —— 事實(shí)證明,能完全控制我們的基礎(chǔ)設(shè)施以及有能力輕松地在每個(gè)抽象層級(jí)上進(jìn)行調(diào)試具有至關(guān)重要的價(jià)值。雖然這個(gè)過(guò)程需要大量的監(jiān)督和迭代,但它讓我們可以深入地理解其底層工作流程、構(gòu)建一系列用于確保主機(jī)健康的工具、學(xué)習(xí)如何讓系統(tǒng)自動(dòng)運(yùn)行以確保訓(xùn)練持續(xù)平滑,最終構(gòu)建起一套讓我們可以快速迭代訓(xùn)練前沿語(yǔ)言模型的基礎(chǔ)設(shè)施。
這個(gè)基礎(chǔ)設(shè)施構(gòu)建流程體現(xiàn)了我們研究和構(gòu)建 AI 智能體的基礎(chǔ)方法論:探究細(xì)枝末節(jié),不斷改進(jìn)現(xiàn)有流程,并構(gòu)建有用的工具和系統(tǒng)使我們這個(gè)積極奮進(jìn)的團(tuán)隊(duì)能夠應(yīng)對(duì)更大的挑戰(zhàn)。