首頁  >  文章  >  科技週邊  >  從裸機到700億參數大模型,這裡有一個教程,還有現成可用的腳本

從裸機到700億參數大模型,這裡有一個教程,還有現成可用的腳本

王林
王林原創
2024-07-24 20:13:31456瀏覽

我們知道 LLM 是在大規模電腦叢集上使用海量資料訓練得到的,本站曾介紹過不少用於輔助和改進 LLM 訓練流程的方法和技術。而今天,我們要分享的是一篇深入技術底層的文章,介紹如何將一堆連作業系統也沒有的「裸機」變成用來訓練 LLM 的電腦叢集。這篇文章來自於 AI 新創公司 Imbue,該公司致力於透過理解機器的思維方式來實現通用智慧。當然,將一堆連作業系統也沒有的「裸機」變成用於訓練LLM 的電腦叢集並不是一個輕鬆的過程,充滿了探索和試錯,但Imbue 最終成功訓練了一個700 億參數的LLM,並在過程中累積了許多有用的經驗。本文將深入介紹團隊建立自己的 LLM 訓練基礎架構的完整流程,並將分享他們為方便監控、檢查和糾錯而編寫的諸多工具和腳本。如果你有心建立自己的 LLM 訓練基礎設施或好奇 LLM 是如何煉成的,那麼這篇文章值得你閱讀和收藏。以下是 Imbue 團隊文章原文。引言我們這個由研究者和工程師組成的小團隊花了幾個月時間在自己的基礎設施上從頭開始訓練了一個700 億參數量的模型,並且該模型在推理相關的任務上勝過了零樣本的GPT-4o。今天,我們要分享的是設定所需基礎設施的過程:從組合初始叢集和安裝作業系統到設定在訓練期間遭遇錯誤時自動恢復。我們會詳細說明在每一步遭遇到的難題和解決方法。除了這些心得之外,我們還將發布我們一路上開發的許多腳本,以便其他團隊能更輕鬆地為自己的模型訓練創建穩定的基礎設施。在整個過程中,我們的工程師團隊與 Voltage Park 一起準備好了電腦集群,建立了生產應用的基礎。這整個過程包括:1. 配置各台機器2. 配置 InfiniBand3. 確保機器完全健康4. 診斷常見的訓練問題5. 改進基礎設施工具下面將詳細描述每個步驟。背景:這是如何煉成的我們執行計算的目標是確保能快速實驗大型語言模型。為此,我們需要大量高速 GPU,而這些 GPU 之間也能高速通訊。本文將重點放在一個集群,其中包含分散在 511 台電腦中的 4088 台 H100 GPU,也就是每台電腦 8 台 GPU。之所以有 511 台帶有 GPU 的計算機,是因為需要保留一些連接給統一結構管理器(Unified Fabric Manager)節點,其作用是管理 InfiniBand 網路。在 511 台有 GPU 的主機上,每台 GPU 都直接與一塊 ConnectX-7 網路卡相連,其能以 400 Gbps 的速度與該 InfiniBand 網路中的任意 GPU 傳輸資料。我們的 InfiniBand 網路拓撲結構的形式是「fully non-blocking」,即完全無阻塞;理論上講,這能讓 GPU 以最大速度互相通訊。為此,我們使用了三層式 InfiniBand 網路架構:三層 InfiniBand 交換器。只要連接正確,便能讓整個網路都獲得這樣高水準的吞吐量。下圖展示了這個 InfiniBand 網路的概況:

從裸機到700億參數大模型,這裡有一個教程,還有現成可用的腳本


請注意,訓練網路時的通訊發生在 InfiniBand 上,而不是乙太網路上。儘管這些機器也連接了以太網,但該網路的作用是傳輸資料集和檢查點等資料。如果使用乙太網路來傳送數據,速度會慢得多,因為資料會先從 GPU 傳輸到 CPU,然後再透過 100 Gbps 速度的乙太網路卡發出去。儘管也可以使用名為 RDMA over Converged Ethernet(RoCE)的技術基於乙太網路進行訓練,但那需要在硬體和軟體方面都做大量額外工作,可靠程度通常也不及 InfiniBand。詳情可參考這篇論文:https://arxiv.org/pdf/2402.15627
另外還有一個僅用於配置和管理的輔助以太網,從而可訪問BIOS(基本輸入輸出系統)、電源和其他低層機器接口的控制介面。如果沒有這個管理網絡,我們就必須透過 USB 驅動、鍵盤和顯示器來手動設定每個節點。對於有幾百台機器的情況,這並非一種可持續的方法。
要在這個叢集上實現高效能訓練,就需要每個元件(InfiniBand、乙太網路、GPU 和節點本身)都近乎完美地工作。如果這 12,000 多個連線中有任何一個有點不穩定,就會拖慢整體的訓練運行速度。
本文接下來的內容就是介紹如何讓這一切都完美且穩定地運作。
流程:如何將裸機變成完全可運行的集群
配置各台機器
在通過管理網絡建立了與集群的初始以太網連接之後,就獲得了基板管理控制器(BMC/baseboard management controller)的訪問憑證。 BMC 是一種遠端監控主機系統的專用服務處理器,並且通常連接到一個分立的網路。它能讓我們就像是親身在現場一樣操作機器,並還額外提供了硬體健康狀況、BIOS 設定和電源管理的 API。
配備好這些組件後,我們就可以擼起袖子,開始設置集群了。
步驟 0:先配置一台機器
我們先使用 iDRAC(戴爾的基板管理控制器)在一台伺服器上安裝 Ubuntu 22.04,然後再基於這個作業系統設定其他一切。 iDRAC 的一項能力是允許從本機安裝和啟動 ISO 映像,並透過瀏覽器提供一個虛擬控制台。理想情況下,這是該過程中唯一的手動安裝步驟。
步驟 1:在每台機器上安裝作業系統
在配置完第一台機器之後,繼續安裝 Ubuntu 的 Metal-as-a-Service (MAAS) 軟體以協助配置剩餘的伺服器。使用預啟動執行環境協定(PXE)啟動和自動化 iDRAC 工具,可指示每台機器從網路啟動並設定 MAAS 以回應 PXE 啟動請求。在執行初始的網路啟動時,伺服器會透過動態 IP 分配協定 DHCP 從 MAAS 獲得一個 IP 和一個初始內核,而無需在本機磁碟機上安裝任何東西。這是用於自動重複執行作業系統安裝的基本環境。從理論上講,我們只需等待第一次啟動,然後一切都會被處理好。但實際上,MAAS 與 BMC 的整合並不可靠,因此我們使用 iDRAC API 來事先收集每台機器的 MAC 位址(一種唯一的實體硬體識別碼)。
在這整個訓練過程中,MAAS 通常是椎棧中比較可靠的組件。但是,我們在開始時遇到了一些我們的設定特有的問題。舉個例子,在配置前幾台機器時,由於時脈相差太大,HTTPS 憑證驗證問題導致無法透過 apt 安裝任何東西。與此相關的是,由於MAAS 伺服器必須負責很多事情(DHCP 伺服器、用於將主機名稱解析成IP 的DNS 伺服器、主機和官方Ubuntu 軟體包伺服器之間的HTTP 代理、NTP 伺服器、cloud-init 設定管理、用於將MAC 位址連接到IP 到主機名稱再到自訂元資料的ground truth 資料庫),因此我們很難從根源解決這些問題。此外,還有 MAAS 配置生命週期的學習曲線問題,因為是設計目標是處理管理綠地部署(greenfield deployment)的複雜性以及節點的逐步遷移和各種調試 / 不健康的中間狀態。
步驟 2:診斷損壞的機器
我們發現大約 10% 的機器都無法啟動,主要原因是伺服器的物理問題。這是設定大型 GPU 叢集的常見情況。我們遇到的情況包括:未接線或接錯了網路線、iDRAC 中的硬體問題、電源單元損壞、NVME(快速非揮發性記憶體)驅動損壞、內部線路缺失、網路卡或 GPU 無法顯示。我們自動檢查了這些問題,將一些機器退回給了戴爾以重新測試,並為資料中心工作人員提交相應的工單。我們自己上手配置叢集的一個優點是:在等待維護某些機器的同時就能立即使用健康的機器。
步驟 3:最小可行可觀察機器
我們繼續在每台伺服器上進行以下設定:
1.Docker(以便更輕鬆地運行服務和訓練作業)
  1. 資料中心GPU 驅動
    3.Prometheus 節點導出工具(用於導出穩定的硬體/ 作業系統指標資料流)
    4.DCGM 導出工具(用於從英偉達GPU 導出額外的指標數據,如GPU 狀態、時鐘、利用率)
  2. 所有非作業系統驅動的RAIDZ ZFS 池,這讓機器在某個驅動失效時也能繼續工作,同時還能免費提供透明的壓縮(這對純文字資料集和重複性日誌尤其有用—— 相比於不使用該工具,使用該工具通常能將可使用的空間增大10 倍)
    然後我們運行基本的GPU 診斷以確定GPU 是否大體功能正常—— 不正常的通常會在幾小時內出現硬體問題。
    在此期間,當我們試圖同時在全部 400 個節點上安裝軟體包時,我們遭遇了頻寬瓶頸。這是我們第一次在資料中心部署的多個元件上收到高溫過熱警報。這首批發熱問題基本上都透過韌體更新得到了解決。
    步驟 4:單節點的 GPU 訓練
    下一步是確保每台機器都能夠單獨處理真實的 GPU 工作負載。許多機器都無法做到這一點,問題包括:
    GPU 相關的錯誤,這類問題基本上都可透過將GPU 卡重新插入卡槽來解決:將200 磅重的伺服器從機架上滑出來,移除機蓋和GPU 之間的所有線纜,然後取出GPU,再重新裝上GPU,之後再重新接上線纜並將伺服器推回機架。
    根據 Ubuntu 伺服器日誌,GPU 和 PCIe 匯流排或網路卡之間的許多線纜都發出了這樣的報錯:「limited width: x4 還有一些雜項故障也影響了幾台主機。戴爾透過韌體升級幫助我們解決了一些問題:
    NVMe 驅動器沒有顯示故障,但觸摸時會鎖定整台機器。
    硬碟在 Linux 下以隨機順序顯示,這給 MAAS 造成了混亂,並會導致作業系統被安裝在錯誤的磁碟機上。
    溫度讀數錯誤,這會導致風扇一直全速運轉。原因可能是英偉達驅動有問題,這透過降級驅動版本而得到了解決。
    CPU 的動態調頻失控,將工作核心限制為 2 GHz。
    直接的 GPU-GPU 通訊(GDR 或 GPUDirect RDMA Peer Memory Client)無法成功應用。
    設定 InfiniBand
    步驟 0:安裝 UFM
    InfiniBand 的一個優點是其中心化的設計,這樣一來整個網路就有了一個大腦。因此,對於整個網路結構中的 320 個網路交換機,我們只需處理其中一個實例。我們的首個任務是搞清楚哪台交換器連接了哪些機器,然後將其與接線圖關聯起來,並根據交換器的實體位置重新命名它們。
    步驟 1:重新佈線
    一開始,UFM 無法偵測到那 320 台交換機,更別說本來應該出現在網路結構中的主機了。在與我們的資料中心合作夥伴商討之後,我們確認這些交換器已通電並接好了線,但仍無法偵測到。在檢查網路佈線清單後,我們注意到這個網路結構的頂層設計有誤:這個結構不是統一的,而是分成了八個沒有公共路由路徑的互相脫離的網路。在重新接線之後,我們新增了檢查步驟,以驗證所有實體連接是否與新設計一致。
    步驟 2:一萬次溫度警報(alert)
    在解決了實體接線問題之後,InfiniBand 成功建立了與網路結構中所有 InfiniBand 交換器的連結。但是,幾乎每個交換器連接埠都開始報告溫度過高,有時超過 70 ℃,即便它們還沒有傳輸資料。我們發現這個問題源自於同一機架中交換器之間的開放空間,這導致熱空氣回流到了前面。我們的資料中心合作夥伴幫助我們快速診斷出了問題並制定了合適的解決方法。
    步驟 3:1800 次告警
    許多連接埠還有很高的錯誤率,或在正常和損壞狀態之間來回變動,這被稱為「抖動(flapping)」。這些問題只有在實際使用這些連接埠時才會出現,所以很難預先檢測,因為我們的整個結構由 10,000 條高度冗餘的連結組成。我們的資料中心合作夥伴協助清潔和重新安裝警告的端口,我們在等待替換時禁用了剩餘的警報收發器。
    儘管 InfiniBand 能彈性地應對硬體故障,但一旦大約 10% 的結構開始出現問題,自適應路由等功能就無法可靠地運行,無法解決偶爾丟失鏈路的問題。
    在此期間,我們成功使用 100 到 200 台機器運行了多節點訓練。我們的流程比較即興:我們有時會隨機啟動一組節點,觀察它們的效能,然後盡力讓其中盡可能多的節點保持運作。此方法可讓我們找到該 InfiniBand 網路結構中一組可靠的子集,但難度卻很大,因為每次都需要改變用於訓練的節點集合,由此改變預設的 InfiniBand 連結。
    步驟 4:InfiniBand 瘋狂燃燒
    為了更有效率地診斷 InfiniBand 問題,我們專門為整個叢集設計了一個工作負載,其作用是同時將盡可能多的資料推送經過整個結構中的每個連接埠。這不同於在整個叢集上運行一個大型的 all-reduce 工作負載,這需要使用 NCCL 來優化各個節點之中的通信,方法是使用 NVLink 經由 Server PCIe Module (SXM) 插槽來實現 GPU 通訊。
    相反,我們選擇了一種蠻力方法,並且輕鬆取得了成功。 UFM 會在大多數連接埠的資料傳輸量超過理論容量的 97% 時開始發出警報,同時一些交換機會暫時宕機。我們認為能堅持到當天結束時的每個連接埠都是足夠穩健的,其餘的都被禁用或移除以待維修。
    步驟 5:GPUDirect RDMA
    要讓 GPU 通訊時不產生 CPU 運算開銷,我們啟用了一個名為 GPUDirect RDMA 的功能,其允許 InfiniBand 網路卡之間直接通訊。這涉及兩個關鍵步驟:
  3. 啟動一個額外的核模組
  4. 確保PCIe Access Control Service (ACS) 被禁用,以防止immediate hangs(立即掛起)
    步驟6:擴增「黃金」伺服器
    要使用最新硬體建構GPU 集群,一個經驗法則是:每週都有大約3% 的機器出問題,要做好準備。
    但是,需要說明一點:並不是每台機器都統一有 3% 的幾率發生故障,而是少量不對付的機器反覆出現各種不同問題,直到將它們妥善修復。這凸顯了在同一網路結構中配備大量機器的優勢。因此,我們的做法不是隨便找些機器來運行大規模訓練,就像打地鼠一樣看哪些出問題,而是專注於擴增已知可靠的伺服器,也就是「黃金」伺服器。
    步驟 7:維護
    InfiniBand 的維護主要涉及到回應 UFM 警報、更換故障線和收發器,以及偶爾診斷更困難的錯誤(例如交換器故障)。導致大規模維護的因素通常有兩個:
  5. 韌體更新,尤其是叢集中僅有一半完成更新時,這可能導致 UFM 狀態損壞並必需重新啟動所有 InfiniBand 交換器上的 UFM。
    2.GPU 盒同時大規模重啟,這可能會向 UFM 狀態灌入大量更新,並同樣需要重新啟動 UFM 服務。
    確保機器完全健康
    在此過程中,我們發現了單台機器的多種故障或減慢訓練速度的方式。其中許多故障模式並不會立即顯現,因此我們編寫了許多健康檢查腳本,以檢查主機是否足夠健康。我們在這裡發布了這些程式碼:https://github.com/imbue-ai/cluster-health
    請注意,這些健康檢查中的許多都特定於我們的運行時環境,並不一定與基礎硬體相關,也不一定容易修復或自動化。這是設計決定的:為了實現讓我們的機器準備好訓練的總體目標,我們想要一個可以直接了當地回答“是”或“否”的單一入口點,並且可以概括總結任意數量的細微細節。
    GPU 健康檢查
    我們檢查了 GPU 數量是否正確、ECC(錯誤更正代碼)檢查是否已啟用以及是否有 ECC 錯誤。我們還檢查了 NVLink 拓撲(將 GPU 彼此連接起來)是否已啟動且無錯誤。
    磁碟空間健康檢查
    我們檢查了主機的磁碟空間利用率是否超過 95%。
    Docker 健康檢查
    我們檢查了Docker 能否在連接了GPU 的情況下運行容器(即NVIDIA Container Runtime 是否正常工作),還檢查了與監控/ 分析相關的Docker 容器是否已啟動並獲得了正確的主機權限。
    Dmesg 健康檢查
    我們檢查了 dmesg 中是否有硬體 Xids 或 SXid 錯誤(由 NVIDIA GPU 或 GPU 間 NVIDIA 交換器引發的故障)。我們也讀取了所有 dmesg 日誌行,以驗證它們是否都可以歸類到「常見 / 預期日誌行」清單中。
    iDRAC 健康檢查
    我們檢查了機器上的 iDRAC 錯誤,其中忽略了非致命錯誤訊息。這是戴爾電腦特有的檢查,所以沒有被納入我們開源的程式碼中。
    磁碟健康檢查
    我們檢查了 zpool 是否已安裝,Docker 是否已正確連接到它,以及它是否真的可以在不鎖定 CPU 的情況下觸及它。
    InfiniBand 健康檢查
    我們檢查了 InfiniBand 的錯誤率是否會增加和 / 或驅動韌體是否過時。
    Nvlink 健康檢查
    我們檢查了機器上的 NVLink 錯誤。實踐中看,這似乎不會導致訓練失敗,但可能會降低訓練速度。
    GDR 健康檢查
    我們檢查了機器上的 GDR 是否已啟用。
    VBIOS 健康檢查
    我們檢查了 GPU 的 VBIOS 版本以及 H100 基板韌體是否是最新的。
    Flint 健康檢查
    我們使用 flint 和 hca_self_test 檢查了 Mellanox OFED 驅動、網卡韌體和收發器韌體的版本是否正確,以及它們是否針對英偉達驅動進行了正確編譯。
    PSB 健康檢查
    我們查詢了 PCIe 設備,以檢查 GPU、PSB(PCIe 交換器匯流排)和網路卡之間的連接速度和寬度是否符合我們的預期。我們也檢查了交換器韌體是否為最新版本。該腳本由戴爾而非 Imbue 開發,所以我們目前無法共享它。
    除了這些快速健康檢查,我們還進行了一些更複雜的健康檢查,包括:
    透過 PyTorch 初始化矩陣計算,以及測量 NVLink 頻寬和 GPU 計算速度和記憶體。我們設置了適當的 GDR 標誌來測試 InfiniBand 和 NVLink。
    使用 ib_write_bw 和 –use_cuda 透過 IB 卡發送資料並測量 PCIe 和 InfiniBand 卡頻寬。這個過程持續了較長時間(約 15 分鐘),以確保能找出抖動的 InfiniBand 連結。
    運行多節點診斷運行以檢查 NCCL 初始化能力以及它是否會隨機停頓。如有停頓,則我們的分叉版 NCCL 程式碼會新增額外的日誌記錄。這需要 12 到 24 小時才能檢測到問題,因此我們通常只對新節點或我們懷疑有問題時執行此操作。
    檢查 DCGM 導出是否有任何 GPU 時脈節流事件(不包括預期的 gpu_idle 和 power_cap)。為了檢查這些電源事件,最好的方法是執行多節點訓練,以同時檢查所有 GPU、InfiniBand 卡以及 CPU 和磁碟。
    診斷常見的訓練問題
    一旦硬體能正常運作,就可以開始訓練了。
    這一節將基於我們在我們的叢集上運行大型語言模型訓練的經驗,分享一些具體的調試步驟和見解。
    啟動時崩潰
    從某種程度上講,這是所能遇到的最好的錯誤,因為其(理論上)很容易重現和迭代。
    我們首先檢查了我們的程式碼是否在正確的版本、配置和環境變數上運行。雖然很基礎,但我們發現這一點至關重要:確保啟動訓練過程是可重現且容易檢查的。一大原因是 Docker 映像快取或不透明秘密配置等中間抽象可能會造成混淆。
    我們執行的另一個基礎檢查是確保所有機器都在線,並且可以輕鬆地聚合和檢查所發出的堆疊追蹤記錄或日誌。我們使用了 Loki、Prometheus 和 Grafana 軟體棧,但任何合適的日誌聚合或追蹤 SaaS 的工具都可以。由於這些訓練運行過程本質上是同步的和分散的,因此第一個錯誤往往會導致一連串的不相關錯誤。在這裡,健康檢查還可以幫助立刻偵測出硬碟損壞或 GPU 缺失或無效等錯誤。
    我們建立了一個在發生故障時自動重新啟動的系統,這使得日誌和錯誤聚合變得更加重要,以避免混淆來自不同重啟的錯誤。我們遇到的一些常見錯誤包括:
    1.「Forward order differs across ranks: rank 0 is all-gathering 43 parameters while rank 1228 is all-gathering 1 parameters」這樣的錯誤。我們發現這是 PyTorch 完全分片資料並行(FSDP)實現的一個奇怪特性,可透過重啟解決。
    2.GPU 記憶體不足(OOM)錯誤,看起來像這樣:「CUDA out of memory. Tried to allocate …」透過多次檢查我們的配置和程式碼並撤銷近期的程式碼修改(由於啟動期間PyTorch 裝置規格不正確而導致過度使用GPU#0),我們解決了這些問題。
    3.CPU/RAM 記憶體不足(OOM)錯誤,這些錯誤在錯誤日誌中不太容易發現,並且通常能透過 Docker 容器外的主機的 dmesg 日誌檢測出來。當 OOM Killer 呼叫停止一個分叉進程或同級網路(network peer)時,我們可以看到它們主要表現為 CalledProcessError 或 ConnectionError。當從 dmesg 檢測到了 OOM Killer 呼叫時,我們更傾向於直接放棄健康檢查,並重新啟動該機箱。我們還檢查了我們的程式碼路徑是否有足夠的手動垃圾收集(下面有一部分介紹如何停用它),並還檢查了是否有意外嘗試進行計算或將張量移至 CPU 上。
    在訓練過程中崩潰
    首要任務是讓系統能自動運行,讓其能自動重新運行所有健康檢查,然後在沒發現不健康主機時重啟運行。我們遇到了一些隨機的硬體錯誤,包括 Xid 和 SXid 錯誤;這些錯誤可能會導致運行崩潰,但不會發出有意義的 Python 堆疊追蹤記錄。行重映射等一些問題可透過重啟恢復。不可糾正的 ECC 錯誤等其他問題則往往需要硬體維護或更換零件。
    此外,我們還觀察到格式錯誤的訓練資料也會導致崩潰。舉個例子,如果語料庫中有一個非常大的單一文檔,就可能導致 GPU 或 CPU 出現記憶體不足錯誤。為了防止這個問題,我們採用了完全確定式的資料載入器 —— 透過與 epoch 或步數相關聯,讓每一次崩潰都可輕鬆復現。我們發現停用資料載入或替換假資料(例如全零資料)有助於確認錯誤的根本原因是否是資料。
    最後,透過指標聚合方法記錄網路和一般節點的健康統計數據也很有幫助。乙太網路短暫斷開或磁碟空間不足等問題可能不會顯示為有用的錯誤訊息,但卻可以輕鬆地與已收集的資料相關聯。
    沒有堆疊追蹤資訊的掛起(之後可能會有超時問題)
    由於這些問題缺乏有幫助的信息,加上很難可靠地復現,因此這類錯誤的調試工作著實讓人沮喪。
    其中最令人難忘的錯誤類型伴隨著這樣的報錯訊息:

    Watchdog caught collective operation timeout:WorkNCCL (SeqNum=408951, OpType=_ALLGATHER_BASE, … , Timeout (ms)=600000) ran for 600351 milliseconds before timing out


    並且訓練運作中的所有 GPU 工作器都發出了這樣的報錯訊息。

這表示一台或多台主機未能完成 NCCL 操作或 NCCL 和 InfiniBand 連線崩潰,導致其他所有主機同時卡在了某個張量運算上,直到達到 NCCL_TIMEOUT 逾時時間。不幸的是,受 NCCL 軟體庫本質所限,我們很難找到究竟是哪台主機出了問題。

我們對 NCCL 軟體庫的日誌記錄做了一些修改,請參閱我們的分叉版:https://github.com/boweiliu/nccl 。從而在崩潰發生時可能更好地揭示正在執行的訊息或操作,從而確定阻止運行的可能是哪台主機或 GPU。

請注意,為了辨識行為不當的主機,我們通常需要搞清楚哪些主機沒有產生某些日誌訊息。缺少此類訊息表明該主機上的工作器已落後或已崩潰。

其他沒有可用錯誤訊息的無回應情況通常與硬體相關問題有關,例如先前提到的 Xid/SXid/ECC 錯誤會導致英偉達驅動或英偉達 Docker 通訊驅動鎖定。為了區分 NCCL 掛起與驅動掛起以及 Python 程式碼中的競爭條件或死鎖,我們使用 Py-Spy 和 GNU Project Debugger(GDB)等工具來即時偵錯遇到的停滯進程。使用此方法可發現一個特定問題:由於 Python 執行緒設定中的設定錯誤,我們無法在某些主機上正確啟動八個多執行緒 NCCL GPU 進程,這些進程在 PyTorch 之前的初始化程式碼階段遇到了競爭條件。

  • 訓練減速(由 MFU 測量)

缺乏工具讓這類問題比前一類更讓人沮喪。除了使用 Py-Spy、堆疊追蹤檢查和 GDB 之外,我們還採用了 NVIDIA Nsight 和 profiling 工具,其中一些工具在高度分散的設定中很難使用。

遺憾的是,導致一般減速或讓速度低於先前示範的模型浮點數利用率(MFU)的原因有很多。

首先,事實證明多次檢查配置、程式碼和環境變數是有用的。我們經歷過的錯誤包括:運行了錯誤的模型、批次大小錯誤、UFM 或 NCCL 設定出錯、CUDA_DEVICE_MAX_CONNECTIONS 出錯。這都會導致效能無法達到最優。

我們也發現測量瞬時(即每批次)MFU(而不是平滑或視窗平均值)很有用,因為未平滑處理的 MFU 曲線通常有助於診斷問題類別。導致訓練速度下降的問題包括:

  • 從非常低的MFU(低於預期的十分之一)立即開始訓練並保持穩定

這多半是InfiniBand 網路連接的硬體問題,例如T2 或T3 層的交換器死機。 GPU 和NIC 之間的硬體問題也可能導致該情況,對此dmesg 會這樣報錯:PCIe x16 lanes limited by …

  • 從預期MFU 的30% 立即開始訓練並保持穩定

其原因可能是一一原因台主機的GDR 設定不正確(NVIDIA 對等記憶體)或GDR 環境變數不正確。

  • 從預期MFU 的約60-80% 立即開始訓練並保持穩定

最常見的原因是InfiniBand 鏈路品質不行或故障,尤其是單台GPU 出現了與InfiniBand NIC 相關的故障,導致NCCL嘗試經由本機NVLink 路由流量並在同一主機上的另一台GPU 上使用NIC。 CPU 節流也可能導致該問題,這需要調整某些主機的 BIOS 設定。

  • 在處理某些數據批次時突然大幅減速(下降10 倍),並且經常發生這種情況

這基本上都與檢查點或評估有關—— 可透過檢查epoch 數或步數來驗證。惱火的是,如果設定了在 MFU 異常時自動告警,就會出現許多誤報。

  • 在處理某些數據批次時突然大幅減速(下降10 倍)

這種情況是隨機發生的並且相當罕見(大概每15 分鐘一次),並且之後馬上就會完全恢復到良好的MFU。

最常見的原因似乎是其他需要大量 CPU 計算的工作負載被調度到了一台運行中的主機。我們發現,與其建立分析工具來識別特定的主機,透過 PID 來粗略地監控 CPU 會更容易。原因可能是偶爾出現的網路連線問題,例如資料載入器遭遇瓶頸。我們監控了資料載入、檢查點和任何非 NCCL 程式碼的指標資料並添加了 Python 程式碼計時日誌,事實證明這非常可靠。

  • MFU 在運行過程中逐漸減慢,但每次重啟後又會回到 100%

理論上講,原因可能是交換器上的熱量積累,但我們從未見過這種情況。不過,我們使用 Python 和 NVIDIA 分析器來確定:效能下降的原因似乎是自動垃圾收集。

從裸機到700億參數大模型,這裡有一個教程,還有現成可用的腳本

調試吞吐量下降問題

在調試解決這些減速問題時,我們發現吞吐量幾乎必然會週期性地下降。隨著訓練地推進,這種下降會對分散式運算帶來越來越多的影響。這讓我們猜想下降的原因可能與自動垃圾收集有關 —— 我們透過分析和測試驗證了這個猜想。當我們停用了自動垃圾收集,並在所有主機上設定只在特定的間隔內收集垃圾,這種吞吐量「下降」就消失了。

我們使用了一個基於 ZeRO-3 的同步分散式訓練演算法 FSDP。在阻塞操作期間,執行垃圾收集的單一工作器程序可能會減慢其他所有工作器的速度。如果有數百個工作器進程,就可能導致速度大幅下降。

一開始性能良好,然後突然下降(達到預期的70%),並且以高頻持續(每15 秒)

我們觀察到這與英偉達GPU 的“時鐘節流原因”相關,這可通過對英偉達DCGM 進行適當的設定來解決。發熱問題(GPU 高溫或主機冷卻風扇故障 / 效果下降)或電源故障會導致此問題。另外,當我們同時最大化所有8 台GPU 利用率和8x NIC InfiniBand 利用率以及CPU/RAM/ 磁碟時,我們的一些具有特定電源硬體的主機會出現電壓問題,但只有全部使用它們(通常只在實際訓練運行期間)時才會出現這種情況。

性能問題相關性

  • 性能優良但噪聲比平常情況多(高頻白噪聲方差在預期MFU 的90% 和100% 之間)

這也與InfiniBand 有關,但通常是硬件由於網路中較高層的連結出現一定程度的效能下降或抖動,而不是冗餘度較低的主機到T2 層。

不幸的是,許多這類問題都難以定位到某台具體主機,而與 InfiniBand 相關的問題尤其難以定位,這是由於 InfiniBand 交換器技術的拓撲感知特性。 InfiniBand 似乎更偏好 InfiniBand fat-tree 設計中的鄰近主機,而 UFM 則能以不對稱的連結速度路由封包。

調試吞吐量問題的完整性檢查表

以下是用於調試吞吐量問題的簡單摘要 / 流程圖 / 完備性檢查表:

  • 這套系統之前能正常工作嗎?
  • 你最近做了什麼修改(例如合併程式碼、更新驅動程式)?
  • 你運行的主機是否健康?你所有的依賴服務是否都運作正常,包括第三方的 SaaS,例如 Docker Hub、GitHub 等等?
  • 你能確定現在運行的程式碼、環境、設定、版本、主機列表、排名順序、隨機種子與上次完全相同嗎? (如果能實現這樣的檢查的話。)
  • 問題可復現嗎?
  • 與其他事物有何關聯?其他進程?每日 crontab 定時任務?主機或 DCGM 或 UFM 指標?
  • 你的工具是否能正確度量這些指標?
  • 在執行約簡版的程式碼(使用較小的模型、假資料、不儲存或載入檢查點)時,問題是否依然存在?

改進基礎設施工具

完成了以上步驟之後,就能在訓練模型時實現優良性能了… 至少在某個地方出故障之前是這樣。

本節將介紹一些用於確保訓練持續穩定的工具和系統,同時最好盡可能地少需要人類幹預。由於我們這個團隊很小,因此我們沒有足夠的人手來進行人工維修,所以我們也希望能盡可能地自動化這個流程。

我們在這個過程中遇到的所有問題幾乎都可歸因於機器或網路組件故障。這類故障在大型叢集中很常見,因此我們的做法是自動停用故障的機器和網路組件並發送維修請求。

機器故障

我們開發了一個系統,可在運行崩潰時自動從最近的檢查點重新啟動。在這個重啟過程中,首先是對每台可用機器進行健康檢查,然後基於其傳遞的健康檢查結果對每台機器進行分類;然後嘗試在最健康的機器上重新啟動訓練。

網路元件故障

我們觀察到的所有網路故障都可透過 UFM 偵測到,並會被記錄到 UFM 事件日誌中,因此回應方式也很簡單:解析 UFM 日誌並採取相應措施。

UFM 事件系統非常複雜,包含數十種事件類型。但在實務中,我們發現只有少數事件有問題,主要與鏈路故障或符號錯誤技術較高有關。在識別出這些事件後,我們可以編寫腳本來解析 UFM 事件日誌、停用與最近事件相關的連結和連接埠、為這些網路元件申請維護工單、維護完成後重新啟用這些元件。

本地鏡像檔案系統

對於這些大型分散式訓練,人們很早就發現叢集與乙太網路的資料交換速度是一大瓶頸。一條共享乙太網路連線的頻寬大約是 10Gbit/s;如果有數百個工作器同時下載資料集和模型檢查點,那麼這點頻寬會很快飽和。

為此,我們決定在我們叢集內部建立一個本地檔案系統,以作為雲端儲存的鏡像,其本質上就是一個快取空間,可以減少從 S3 讀取的檔案量。為了解決叢集流失問題(即因為維修原因而停用或更換機器的情況),我們為每份文件都準備了三個副本,並使用了一致性雜湊以均勻分配負載,從而在叢集流失期間最大限度地減少文件移動。由於叢集的磁碟空間有限,所以我們必須開發多種工具來追蹤檔案的生命週期並清除不再有用的檔案。

本地分散式 Docker 註冊表

我們使用了 Kraken,這是一個可點對點傳輸 Docker 映像的出色開源軟體。這個軟體幾乎沒出現過任何問題,我們還挺驚訝的,畢竟我們的任務和實作都很複雜。工具位址:https://github.com/uber/kraken

各種效能監控工具

我們設定了預設的 Torch 分析器以及英偉達的 Nsight Systems。後者可協助我們了解前向 / 反向通過以及 NCCL 通訊所需的確切時間,並進一步幫助我們確定給定的模型大小和工作器數量是否會成為瓶頸。然而,Nsight Systems 有點難用,因為需要在特權模式下執行 Docker,這需要停用與效能監控事件相關的安全檢查,並且在儲存其配置時往往需要停止整個訓練進程。

此外,我們還編寫了工具來檢測訓練速度慢的資料批次並理解其可能原因。我們發現這很有用。其中最有用的工具的作用是監控每一批次所需的時間並在某批次過於慢時丟棄該工作器的堆疊追蹤—— 這讓我們可以更輕鬆地找到硬體或軟體有些小問題的主機。

將機器分成不同的組別以定位故障主機

在使用該集群的前幾個月(那時候健康檢查還不如現在這般透徹),我們經常遇到這種情況:在一組機器上訓練時故障,但不清楚究竟是哪台機器有問題。為了找到故障主機,我們開發了一些工具,可以輕鬆地把一組機器分成不同的小組,然後在每個機器小組上執行較小的訓練。

舉個例子,如果一個在48 台機器上運行的訓練失敗了,那麼就在6 組各8 台機器上進行更小規模的訓練,然後在8 組各6 台機器上運行更小規模的訓練。通常情況下,這兩個階段中只有一次運行會失敗,這讓我們有信心得出結論:在兩個階段中都出問題的機器是有問題的。

反思和學習到的經驗教訓

在設置和維護基礎設施的過程中,我們獲得了一些有用的經驗教訓:

  • 一個有用的做法是交換機器的位置。在運作時,使用多於所需機器數量 10-20% 的機器會很有幫助,這樣就能在機器故障時輕鬆重啟訓練了。設定叢集網路連線時讓每台機器都與其他每台機器緊密相連,這樣一來我們就能使用這些機器中任意可工作的子集。
  • 對遇到的每一個硬體或軟體故障,編寫測試和自動化解決方案是值得的,因為訓練中遇到的每一個問題都會再次出現。類似地,對於每一個含混不清的報錯訊息,都值得寫出更能解釋該錯誤的工具。
  • 可重複性是優良科學研究的關鍵。我們立刻就採用的一大原則是:「一次只修改一個地方」,即便最簡單的地方也是如此。
  • 信任,但也要驗證。每當我們引入外部工具或加入新人員(無論是來自公司內部還是公司外)時,我們都會仔細檢查他們聲稱的東西,尤其是當後續步驟依賴這些聲稱的東西時。

總結

訓練大型語言模型一開始就需要複雜的基礎設施。我們之所以選擇深入參與基礎設施的設置細節,是因為我們相信完全理解我們操作的系統是非常重要的,也因為我們認為這樣做的效率更高。

現在,經歷過整個流程之後,我們很高興我們採用了這樣的方法—— 事實證明,能完全控制我們的基礎設施以及有能力輕鬆地在每個抽象層級上進行調試具有至關重要的價值。雖然這個過程需要大量的監督和迭代,但它讓我們可以深入地理解其底層工作流程、建立一系列用於確保主機健康的工具、學習如何讓系統自動運行以確保訓練持續平滑,最終構建起一套讓我們可以快速迭代訓練前沿語言模型的基礎設施。

這個基礎設施建構流程體現了我們研究和建構 AI 智能體的基礎方法論:探究細枝末節,

以上是從裸機到700億參數大模型,這裡有一個教程,還有現成可用的腳本的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn