Accelerate 文件

故障排除

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

問題排查

本指南為使用 Accelerate 時可能遇到的一些問題提供解決方案。由於 Accelerate 是一個不斷發展的活躍庫,並且存在許多不同的用例和分散式訓練設定,因此並非所有錯誤都包含在內。如果此處描述的解決方案對您的特定錯誤沒有幫助,請參閱尋求幫助部分,瞭解在哪裡以及如何獲得幫助。

日誌記錄

日誌記錄可以幫助您識別錯誤的來源。在具有多個程序的分散式設定中,日誌記錄可能是一個挑戰,但 Accelerate 提供了 logging() 工具來確保日誌同步。

要排查問題,請使用 logging() 而不是標準的 Python logging 模組。使用 log_level 引數設定詳細級別(INFODEBUGWARNINGERRORCRITICAL),然後您可以:

  1. log_level 匯出為 ACCELERATE_LOG_LEVEL 環境變數。
  2. log_level 直接傳遞給 get_logger

例如,設定 log_level="INFO"

from accelerate.logging import get_logger

logger = get_logger(__name__, log_level="DEBUG")

預設情況下,日誌僅在主程序上呼叫。要在所有程序上呼叫它,請傳遞 main_process_only=False。如果日誌應在所有程序上按順序呼叫,還請傳遞 in_order=True

from accelerate.logging import get_logger

logger = get_logger(__name__, log_level="DEBUG")
# log all processes
logger.debug("thing_to_log", main_process_only=False)
# log all processes in order
logger.debug("thing_to_log", main_process_only=False, in_order=True)

程式碼掛起和超時錯誤

程式碼掛起的原因可能有很多。讓我們看看如何解決一些可能導致程式碼掛起的最常見問題。

張量形狀不匹配

張量形狀不匹配是一個常見問題,可能導致您的程式碼在分散式設定上掛起很長時間。

在分散式設定中執行指令碼時,諸如 Accelerator.gather()Accelerator.reduce() 等函式是必要的,以便跨裝置獲取張量以集體執行操作。這些(以及其他)函式依賴於 torch.distributed 來執行 gather 操作,這要求所有程序中的張量具有完全相同的形狀。當張量形狀不匹配時,您的程式碼會掛起,最終會遇到超時異常。

您可以使用 Accelerate 的操作除錯模式來立即捕獲此問題。我們建議在 accelerate config 設定期間啟用此模式,但您也可以從 CLI、作為環境變數或透過手動編輯 config.yaml 檔案來啟用它。

命令列
環境變數
config.yaml
accelerate launch --debug {my_script.py} --arg1 --arg2

啟用除錯模式後,您應該會得到一個指向張量形狀不匹配問題的回溯資訊。

Traceback (most recent call last):
  File "/home/zach_mueller_huggingface_co/test.py", line 18, in <module>
    main()
  File "/home/zach_mueller_huggingface_co/test.py", line 15, in main
    broadcast_tensor = broadcast(tensor)
  File "/home/zach_mueller_huggingface_co/accelerate/src/accelerate/utils/operations.py", line 303, in wrapper
accelerate.utils.operations.DistributedOperationException:

Cannot apply desired operation due to shape mismatches. All shapes across devices must be valid.

Operation: `accelerate.utils.operations.broadcast`
Input shapes:
  - Process 0: [1, 5]
  - Process 1: [1, 2, 5]

提前停止

對於分散式訓練中的提前停止,如果每個程序都有特定的停止條件(例如驗證損失),則它可能無法在所有程序之間同步。因此,可能會在程序 0 上發生中斷,但在程序 1 上不會,這將導致您的程式碼無限期掛起,直到發生超時。

如果您有提前停止條件,請使用 set_triggercheck_trigger 方法確保所有程序都正確結束。

# Assume `should_do_breakpoint` is a custom defined function that returns a conditional, 
# and that conditional might be true only on process 1
if should_do_breakpoint(loss):
    accelerator.set_trigger()

# Later in the training script when we need to check for the breakpoint
if accelerator.check_trigger():
    break

Linux 上的低核心版本

據報道,在核心版本 < 5.5 的 Linux 上,程序會掛起。為避免此問題,請將您的系統升級到較新的核心版本。

MPI

如果您使用 MPI 的分散式 CPU 訓練任務掛起,請確保您已在節點之間設定了免密 SSH(使用金鑰)。這意味著對於主機檔案中的所有節點,您應該能夠從一個節點 SSH 到另一個節點,而不會被提示輸入密碼。

接下來,嘗試執行 mpirun 命令作為健全性檢查。例如,下面的命令應該會為每個節點打印出主機名。

mpirun -f hostfile -n {number of nodes} -ppn 1 hostname

記憶體不足

在執行訓練指令碼時,最令人沮喪的錯誤之一是在 CUDA、XPU 或 CPU 等裝置上遇到“記憶體不足”。整個指令碼需要重新啟動,並且任何進度都會丟失。

為了解決這個問題,Accelerate 提供了 find_executable_batch_size() 工具,該工具大量借鑑了 toma。該工具會重試因 OOM(記憶體不足)條件而失敗的程式碼,並自動降低批處理大小。對於每個 OOM 條件,演算法會將批處理大小減半並重試程式碼,直到成功為止。

要使用 find_executable_batch_size(),請重新構建您的訓練函式,以包含一個帶有 find_executable_batch_size 的內部函式,並在其中構建您的資料載入器。最少只需要 4 行新程式碼。

內部函式必須將批處理大小作為第一個引數,但我們在呼叫它時不傳遞任何引數。包裝器會為您處理這個問題。任何消耗裝置記憶體並傳遞給 Accelerator 的物件(模型、最佳化器)也必須在內部函式中宣告。

def training_function(args):
    accelerator = Accelerator()

+   @find_executable_batch_size(starting_batch_size=args.batch_size)
+   def inner_training_loop(batch_size):
+       nonlocal accelerator # Ensure they can be used in our context
+       accelerator.free_memory() # Free all lingering references
        model = get_model()
        model.to(accelerator.device)
        optimizer = get_optimizer()
        train_dataloader, eval_dataloader = get_dataloaders(accelerator, batch_size)
        lr_scheduler = get_scheduler(
            optimizer, 
            num_training_steps=len(train_dataloader)*num_epochs
        )
        model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare(
            model, optimizer, train_dataloader, eval_dataloader, lr_scheduler
        )
        train(model, optimizer, train_dataloader, lr_scheduler)
        validate(model, eval_dataloader)
+   inner_training_loop()

不同裝置設定之間的結果不可復現

如果您更改了裝置設定並觀察到不同的模型效能,很可能是您在從一個設定遷移到另一個設定時沒有更新指令碼。即使您使用相同的指令碼和相同的批處理大小,在 TPU、多 GPU 和單 GPU 上的結果仍然會不同。

例如,如果您在單個 GPU 上以批處理大小 16 進行訓練,然後遷移到雙 GPU 設定,您需要將批處理大小更改為 8 才能獲得相同的有效批處理大小。這是因為使用 Accelerate 訓練時,傳遞給資料載入器的批處理大小是每個 GPU 的批處理大小

為了確保您可以在不同設定之間復現結果,請確保使用相同的種子,相應地調整批處理大小,並考慮縮放學習率。

有關更多詳細資訊和批處理大小的快速參考,請檢視比較不同裝置設定之間的效能指南。

不同 GPU 上的效能問題

如果您的多 GPU 設定包含不同的 GPU,您可能會遇到一些效能問題

  • GPU 之間的 GPU 記憶體可能不平衡。在這種情況下,記憶體較小的 GPU 會限制批處理大小或可載入到 GPU 上的模型大小。
  • 如果您使用效能配置檔案不同的 GPU,效能將由您使用的最慢的 GPU 決定,因為其他 GPU 必須等待它完成其工作負載。

同一設定中差異巨大的 GPU 可能導致效能瓶頸。

尋求幫助

如果此處的解決方案和建議都無法解決您的問題,您可以隨時向社群和 Accelerate 團隊尋求幫助。

  • 透過在Accelerate 類別中釋出您的問題,在 Hugging Face 論壇上尋求幫助。請務必撰寫一篇描述性帖子,其中包含有關您的設定和可復現程式碼的相關上下文,以最大程度地提高問題解決的可能性!

  • Discord 上釋出問題,讓團隊和社群幫助您。

  • 如果您認為自己發現了與庫相關的錯誤,請在 Accelerate GitHub 倉庫中建立一個 Issue。請包含有關錯誤的上下文和分散式設定的詳細資訊,以幫助我們更好地找出問題所在以及如何修復它。

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.