Accelerate 文件
故障排除
並獲得增強的文件體驗
開始使用
問題排查
本指南為使用 Accelerate 時可能遇到的一些問題提供解決方案。由於 Accelerate 是一個不斷發展的活躍庫,並且存在許多不同的用例和分散式訓練設定,因此並非所有錯誤都包含在內。如果此處描述的解決方案對您的特定錯誤沒有幫助,請參閱尋求幫助部分,瞭解在哪裡以及如何獲得幫助。
日誌記錄
日誌記錄可以幫助您識別錯誤的來源。在具有多個程序的分散式設定中,日誌記錄可能是一個挑戰,但 Accelerate 提供了 logging()
工具來確保日誌同步。
要排查問題,請使用 logging()
而不是標準的 Python logging
模組。使用 log_level
引數設定詳細級別(INFO
、DEBUG
、WARNING
、ERROR
、CRITICAL
),然後您可以:
- 將
log_level
匯出為ACCELERATE_LOG_LEVEL
環境變數。 - 將
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
檔案來啟用它。
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_trigger
和 check_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。請包含有關錯誤的上下文和分散式設定的詳細資訊,以幫助我們更好地找出問題所在以及如何修復它。