AI 的檢查點:為什麼訓練中斷還能救

artificial%20intelligence%20concept%2C%20digital%2...
發表時間:2026 年 10 月 28 日 | 更新日期:2026 年 10 月 28 日 | 編輯:雅寶社區編輯團隊
AI 的檢查點:為什麼訓練中斷還能救 - 雅寶社區 · 頂客論壇

  • 優化器狀態(Optimizer States):以 Adam 或 AdamW 為例,需要保存一階動量(m)與二階動量(v),通常以 fp32 儲存。對 7B 模型而言,這部分約 56GB,是整個檢查點中最肥的一塊。
  • 主權重(Master Weights):混合精度訓練時,fp32 的主參數副本約 28GB,用於參數更新。
  • 學習率排程器狀態:目前跑到第幾步、warmup 結束了沒、cosine decay 走到哪個位置。
  • 資料載入器狀態:包含目前的 epoch、資料集內的取樣位置、shuffle 的種子與狀態。這一項最常被遺漏,卻直接影響訓練資料的順序。
  • 隨機數生成器狀態(RNG States):Python、NumPy、PyTorch CPU 與 CUDA 各有各的隨機數狀態,若要做到完全可重現,這些都必須保存。
  • 梯度縮放器狀態(GradScaler):使用混合精度時,動態損失縮放的係數也需要接續。
  • 訓練元資料:全域步數、已消耗 token 數、當下的 loss、程式碼版本、設定檔快照等。
  • 把這些加總起來,一個 7B 模型的完整檢查點大約落在 90 至 100GB 級別;而像 Llama 3 405B 這種規模的模型,單一完整檢查點是以「數 TB」為單位在計算的。這也解釋了為什麼檢查點策略本質上是一場工程與成本的拉鋸戰——存得太少,中斷時會痛;存得太多,光是寫入硬碟就吃掉大量訓練時間。

    二、訓練為什麼會中斷?那些沒寫在新聞稿裡的災難

    外界看 AI 訓練,往往只看到「某公司用幾萬張 GPU 訓練出某個模型」這種一句話結論。但真正的訓練日誌,通常是一部災難紀錄片。

    硬體:GPU 也會過勞死

    大型訓練叢集動輒數千甚至數萬張 GPU 同時運作,這代表任何一個元件的故障機率都會被放大。GPU 本身的錯誤(ECC 錯誤、HBM 記憶體故障、Xid 錯誤)、NVLink 連線異常、InfiniBand 網路交換機瞬斷、節點電源模組老化,這些都是家常便飯。

    更麻煩的是「靜默錯誤」(Silent Data Corruption)。硬體沒有當掉、程式沒有報錯,但某張 GPU 的計算結果開始出現偏差,導致 loss 緩慢地往上飄。這類問題往往要過了好幾天,等到模型行為明顯異常時才會被發現,而這時你唯一能做的,就是回溯到出問題之前的檢查點重跑。

    Meta 在 OPT-175B 的公開訓練日誌中,就記錄了大量硬體故障與反覆重啟的過程;BLOOM 團隊在法國 Jean Zay 超級電腦上訓練 176B 模型時,也遭遇過多次節點故障與儲存系統問題。這些不是特例,而是大規模訓練的常態。

    軟體與人為:一個 typo 就能毀掉三週

    硬體之外,軟體層面的中斷同樣頻繁。資料前處理的邊界條件沒處理好,訓練到某個 batch 時突然丟出例外;記憶體逐漸洩漏,跑到第 8 萬步時 OOM;分散式通訊的 timeout 設定太短,某個節點稍微慢一點就判斷死亡並讓整個 job 崩潰。

    還有人為因素。研究員想「順手」調個超參數、改個資料集、修個 bug,改了程式碼卻忘了跟訓練中的 job 同步;或者不小心在錯的節點上下錯指令、把儲存空間塞爆。這些聽起來很蠢,但在壓力大、迭代快的 AI 團隊裡,發生的頻率高得驚人。

    分散式訓練的蝴蝶效應

    單機訓練時,中斷就是中斷,影響範圍僅限一台機器。但分散式訓練的邏輯是:所有節點必須同步(synchronous)地進行梯度交換,任何一個節點掛掉,整個訓練群組都會停擺等待,最終觸發 timeout 而全體崩潰。

    這意味著,一個由 1,024 張 GPU 組成的訓練任務,只要其中 1 張出問題,另外 1,023 張也得跟著停工。你可以想像這對「有效算力利用率」(MFU)的傷害有多大。而檢查點,就是讓這 1,023 張 GPU 不必從頭再來的那道防線。

    三、沒有檢查點的世界:從「重跑一次」到「重跑一個月」

    要理解檢查點的價值,最快的方式是想像它不存在。

    成本對照:三天與三十分鐘的差別

    假設你正在訓練一個中型模型,使用 64 張 H100,預計跑 30 天。如果在第 25 天發生硬體故障,而你完全沒有存檢查點,那你面對的選項只有一個:從第 0 步重來。這不只是浪費 25 天,而是浪費了 64 張 GPU × 25 天 × 24 小時的算力成本。以雲端現價粗估,這可能是數百萬台幣的損失。

    反過來說,如果你每兩小時存一次檢查點,最壞情況下你只損失兩小時的進度。重啟、載入、驗證、繼續訓練,整個流程可能在 30 分鐘到 1 小時內完成。同樣一場災難,損失從「災難級」降為「不便級」。

    這就是為什麼在 AI 工程的實務中,檢查點不是「有空再做的加分項」,而是專案啟動前就必須設計好的基礎設施。

    不只是錢,還有「不可重現」的詛咒

    成本之外,還有一個更隱微的損失:可重現性。如果訓練中斷後你得從頭來過,你有可能拿到一個完全不同的結果嗎?答案是「會」。即使你把隨機種子固定,不同時間點的硬體狀態、驅動版本、函式庫版本、甚至資料集本身的微小變動,都可能讓兩次訓練走上不同的路。

    對於需要嚴謹實驗對照的研究團隊來說,這幾乎是致命的。你無法回答「是因為改了這個超參數才變好,還是因為這次運氣比較好」。而檢查點的存在,讓你能在同一個狀態基礎上做分支實驗、做 A/B 對照,這對研究品質的影響,往往比省下的算力更長遠。

    四、檢查點是怎麼運作的?恢復訓練的關鍵細節

    知道要存什麼之後,下一個問題是:這些東西要怎麼存、怎麼載入,才能真的「無縫接續」?這裡有幾個技術細節,決定了你的檢查點是「救命仙丹」還是「安慰劑」。

    模型權重只是三分之一:優化器狀態才是魔鬼

    前面提到,7B 模型的檢查點中,權重只占約 14GB,而優化器狀態卻占了 56GB 以上。很多人第一次做續訓實驗時,會想「優化器狀態太大了,跳過應該沒差吧」,然後就迎來 loss 尖峰。

    原因在於 Adam 的行為:它會根據歷史梯度的平均值與平方值來調整每個參數的更新幅度。如果你把 m 和 v 歸零,等於讓優化器「失憶」,重新用非常小的有效學習率暖機。對於已經訓練到後期的模型,這種劇烈的更新動態改變往往會破壞已經學到的表徵,需要花上數千步才能恢復,甚至永遠回不去。

    所以在實務上,一個可續訓的檢查點,優化器狀態與主權重是不可省略的。若要節省空間,可以考慮只保留最近幾份完整檢查點,較舊的則只留權重作為歸檔版本。

    資料管線與隨機性:被忽略的隱形狀態

    另一個常見的坑是資料載入器。現代訓練框架(如 PyTorch 的 DataLoader)通常會用多個 worker 平行預取資料,並透過隨機種子決定 shuffle 順序。如果你只存了模型,沒有存資料載入器的狀態,續訓後資料會從頭開始讀,等於模型會看到重複的資料分佈。

    實務上的解法有兩種:一是完整保存 DataLoader 與 sampler 的狀態;二是採用「可決定性」的取樣策略,例如以「已消耗的樣本數」作為種子來產生每一輪的順序,這樣只要記錄全域步數,就能還原出理論上相同的資料流。第二種做法在大型訓練中更常見,因為它避開了多 worker 狀態難以同步的問題。

    至於 RNG 狀態,是否要完整保存取決於你對可重現性的要求。對於生產訓練,通常保存即可;對於研究實驗,則建議連 CUDA 的 RNG 狀態一併存下,並在恢復後驗證前幾步的 loss 是否與中斷前一致。

    分散式檢查點:從「每個人存一份」到「分片共享」

    在分散式訓練中,檢查點的寫入是一大挑戰。早期最直覺的做法是「每個 rank 各存一份自己負責的參數」,但這會導致儲存空間爆炸,而且載入時難以還原到不同的並行拓撲(例如從 64 卡換到 128 卡重啟)。

    現在的標準做法是分片式檢查點(Sharded Checkpoint)。以 PyTorch 的 Distributed Checkpoint(DCP)或 DeepSpeed 的 Universal Checkpoint 為例,它們會把參數按張量切片儲存,並記錄每個切片的邏輯位置。好處是:載入時可以根據新的平行策略重新組合(resharding),這對彈性訓練(elastic training)至關重要。

    此外,寫入效能也是關鍵。寫一份數 TB 的檢查點,若儲存頻寬不足,可能要花上數十分鐘甚至數小時,這段時間 GPU 是閒置的。Meta 在 Llama 3 的技術報告中提到,他們透過改良儲存架構與非同步寫入,把檢查點的寫入時間大幅壓縮,讓「存檔」不再成為訓練效率的瓶頸。

    五、檢查點策略怎麼設計?頻率、儲存與成本的三角習題

    知道怎麼存之後,接下來的問題是:多久存一次?存到哪裡?存幾份?這些問題沒有標準答案,只有最適合你團隊的取捨。

    多久存一次?用「損失期望值」來算

    檢查點頻率的本質是一道數學題。假設每儲存一次檢查點需要成本 C(包含寫入時間造成的算力閒置、儲存費用),而訓練平均每 T 小時會中斷一次,中斷後平均損失的進度是「檢查點間隔的一半」,那麼間隔越短,平均損失越小,但檢查點本身的成本越高。

    把它寫成式子大概長這樣:總成本 ≈ (訓練時長 ÷ 間隔)× C + (中斷次數 × 間隔 ÷ 2 × 單位算力成本)。對這個式子做最佳化,就能得到理論上的最佳間隔。

    當然,現實中的參數往往估不準,所以業界的實務做法通常是:初期先密集存(例如每 30 分鐘或每 500 步),跑一段時間後統計實際的中斷頻率與檢查點耗時,再動態調整。有些團隊會直接採用「每 N 步 + 每 X 分鐘」的雙條件觸發,確保無論訓練速度如何變化,都不會累積太多未存檔的進度。

    同步寫入 vs. 非同步寫入

    同步寫入的意思是:訓練停下來,等檢查點完整寫入儲存後才繼續。這保證了一致性,但代價是 GPU 閒置。非同步寫入則是先把檢查點複製到 CPU 記憶體或本機暫存,再由背景執行緒慢慢寫到遠端儲存,訓練幾乎不受影響。

    非同步寫入的代價是記憶體佔用與複雜度。一份數百 GB 的檢查點暫存在主機記憶體中,對節點規格是很大的負擔;而且要確保在背景寫入完成前,程式若崩潰也不會留下半殘的檔案。實作上通常會搭配「寫入暫存檔 → 完成後原子性改名」的機制。

    目前主流框架(如 PyTorch DCP、NeMo、DeepSpeed)都已支援非同步儲存,對於中大型訓練來說,這幾乎是必備功能。

    存到哪裡?從本地 NVMe 到物件儲存

    儲存層的選擇直接影響寫入速度與成本。常見的選項有三類:

  • 本地 NVMe SSD:速度最快、延遲最低,但容量有限、且與節點綁定。一旦節點故障,本地資料也跟著消失,所以只能當作「快速中繼站」。
  • 平行檔案系統:如 Lustre、GPFS、WekaFS,能提供高吞吐量與共享存取,是多數大型訓練叢集的標準配置,但建置與維護成本高。
  • 物件儲存:如 S3 或相容服務,成本最低、耐久性最高,適合長期歸檔,但寫入與讀取的延遲較高,通常搭配平行檔案系統做分層。
  • 實務上常見的架構是「三層式」:訓練過程中先把檢查點寫到本地 NVMe(最快),再非同步複製到平行檔案系統(供其他節點讀取),最後定期歸檔到物件儲存(長期保存)。這樣兼顧了速度、可用性與成本。

    保留策略與版本管理

    檢查點不是存越多越好。以 405B 模型為例,每個完整檢查點數 TB,若每兩小時存一次、跑 60 天,那就是 720 份、數千 TB 的規模,儲存成本會直接吃掉整個專案的預算。

    常見的保留策略是「輪替 + 里程碑」:保留最近 N 份(例如 3 至 5 份)作為快速恢復用,另外在特定節點(如每個 epoch 結束、loss 達到某個水準、發布候選版本)保留永久歸檔。同時,每個檢查點都應該附帶一份元資料檔,記錄程式碼 commit hash、設定檔、依賴套件版本、訓練步數、當下 loss 等資訊,否則幾個月後你根本分不清哪個檔案是哪一版。

    六、常見陷阱:你的檢查點可能救不了你

    檢查點最諷刺的地方在於:它平常看起來一切正常,直到你真的需要它的那一刻,才會發現它是壞的。以下整理幾個實務上最常踩到的雷。

    陷阱一:只存權重,不存優化器狀態

    這是最常見也最致命的錯誤,前面已經詳細說明。判斷方法很簡單:如果你的檢查點大小約等於「參數量 × 2 bytes」,那大概只存了權重;完整的檢查點通常會是權重的 6 至 7 倍以上。

    陷阱二:沒有驗證過「真的能載入」

    很多團隊寫好了儲存邏輯,卻從來沒有測試過恢復流程。等到真的出事,才發現版本不相容、路徑寫錯、分片數量對不上。建議的做法是定期做「恢復演練」:在訓練過程中主動載入最近的檢查點到另一個環境,確認能正確恢復並跑幾步,這能提前抓出九成的問題。

    陷阱三:寫入過程中被中斷,留下損壞檔案

    如果檢查點寫到一半系統崩潰,你可能會得到一個看似存在、實際上半殘的檔案。解法是採用原子性寫入:先寫到 `checkpoint.tmp`,確認完整性(可用雜湊校驗)後再改名為正式檔名。載入時也要檢查完整性標記,避免把壞檔案當成好檔案。

    陷阱四:平行拓撲變更後無法載入

    當你從 64 卡恢復到 128 卡,或是從某個節點故障後換了新機器,傳統的「每個 rank 存一份」格式會直接失效。這就是為什麼建議使用支援 resharding 的分片式檢查點格式。

    陷阱五:忽略程式碼與環境的版本綁定

    模型權重是資料,但載入權重的程式碼是邏輯。如果你在訓練中途改了模型結構、換了函式庫版本、甚至只是改了參數名稱,舊的檢查點可能就載不進去了。務必在檢查點中記錄程式碼版本與環境快照,並在變更模型結構時做好相容性處理(例如提供轉換腳本)。

    七、從容錯到彈性:檢查點的下一步

    檢查點機制本身也在進化。過去它被視為「出事後的补救措施」,現在則逐漸成為「訓練系統設計的核心抽象」。

    彈性訓練與搶佔式執行個體

    雲端上的搶佔式執行個體(Spot Instance)價格便宜,但隨時可能被回收。有了可靠的檢查點與 resharding 能力,訓練任務就能在節點被回收時自動儲存、遷移到新節點、調整平行度後繼續跑。這種「彈性訓練」的能力,讓原本只有大公司玩得起的大規模訓練,有了更平價的選項。

    PyTorch 的 elastic launcher、Kubernetes 上的訓練 Operator、以及各家雲端的受管訓練服務,都在朝這個方向演進。它們的共同基礎,就是「任何時刻都能存、任何拓撲都能載」的檢查點格式。

    自動化頻率與記憶體內複製

    學術界也提出了不少改良方案。例如微軟的 CheckFreq 會根據訓練的迭代時間與中斷機率,自動調整檢查點頻率;有些研究則嘗試「記憶體內複製」——把檢查點先複製到其他節點的記憶體中,形成一個快速的分散式快照,等空閒時再落地到磁碟。這些技術的目標都是一致的:把檢查點的成本壓到接近零,讓「隨時可以中斷、隨時可以續跑」成為預設狀態。

    八、結語:檢查點是 AI 工程的「安全帶」

    回到最初的問題:為什麼 AI 訓練中斷還能救?答案其實很樸素——因為在每一次中斷之前,系統都已經把「走到這裡為止的一切」好好地保存了下來。

    這背後沒有什麼神奇的演算法,只有一連串工程紀律的累積:知道要存什麼、知道怎麼存、知道存到哪裡、知道多久存一次,並且定期演練「真的能救回來」。這些事情在順利的時候毫無存在感,但在災難發生的那一刻,它們就是整個專案能否存活的分水嶺。

    下一次當你啟動一場長時間的訓練時,不妨先問自己一個問題:如果現在停電,我需要花多久才能回到這一刻?如果答案是「三天」,那或許該先把檢查點機制補起來,再去調那些超參數。畢竟,模型可以慢慢調,但蒸發掉的算力與時間,是救不回來的。

    ```

    🏠 返回首頁