Hugging Face Accelerate:協調 DeepSpeed 與 FSDP 精度
精度差異與收斂
DeepSpeed 與 FSDP 在參數精度的處理方式不同,可能導致訓練結果出現分歧。在使用 bfloat16 載入 Mistral-7B 基礎模型的測試中,DeepSpeed 能夠穩定收斂,而 FSDP 除非手動將學習率按 GPU 數量放大或降低至 1e-5,否則無法降低損失。
此行為歸因於內部的升級(upcasting)。DeepSpeed 的 DeepSpeedZeroOptimizer_Stage3 會透過 _create_fp32_partitions 自動將可訓練參數組升級至 float32,並以完整精度保存主權重,這使得優化器能在較低精度下不穩定的學習率下仍能收斂。
精度工作流程比較
DeepSpeed 與 FSDP 在管理「展平」參數與優化器初始化方面根本不同:
| 流程 | FSDP | DeepSpeed |
|---|---|---|
| 準備 | 使用 torch_dtype |
忽略 torch_dtype;以 float32 建立 |
| 優化器初始化 | 在 torch_dtype 中建立參數 |
在 float32 中建立參數 |
| 優化器(預步驟) | 如有升級則升至 torch_dtype |
將所有內容升級至 float32 |
| 優化器(實際步驟) | 在 torch_dtype 中執行 |
在 float32 中執行 |
雖然 DeepSpeed 的原生升級確保了收斂,但會使記憶體消耗增加 2 倍,這在使用少量 GPU 訓練時相當顯著。相對地,torch 原生的 FSDP 實作不強制升級,提供了在記憶體受限情境下的更大彈性,允許優化器在低精度下運作。
Accelerate 0.30.0 中的新 FSDP 模式
為了協調這兩個框架,Hugging Face Accelerate 現在支援兩種不同的 FSDP 模式,以符合使用者在收斂穩定性與記憶體效率之間的優先考量:
- 混合精度模式:在準備與優化器步驟期間將參數升級至
fp32,與 DeepSpeed 保持一致,同時在訓練時使用bf16。 - 記憶體受限模式:在準備、訓練與優化器步驟全程使用低精度 (
bf16)。
框架比較表
| 框架 | 模型載入 | 混合精度 | 準備 | 訓練 | 優化器 |
|---|---|---|---|---|---|
| FSDP(記憶體受限) | bf16 |
無 | bf16 |
bf16 |
bf16 |
| FSDP(混合精度) | bf16 |
bf16 |
fp32 |
bf16 |
fp32 |
| DeepSpeed | bf16 |
bf16 |
fp32 |
bf16 |
fp32 |
吞吐量表現
在四張 A100 GPU 上使用 IBM Granite 7B 模型進行基準測試,顯示 FSDP(對齊模式)與 DeepSpeed(Zero3)提供了幾乎相同的吞吐量表現:
| 框架 | 每設備每秒標記數 | 步驟時間(秒) | 模型 FLOPs 利用率(MFU) |
|---|---|---|---|
| FSDP(對齊) | 3158.7 | 10.4 | 0.41 |
| DeepSpeed | 3094.5 | 10.6 | 0.40 |
遷移與設定
Hugging Face 已發布一份概念指南以協助使用者在 FSDP 與 DeepSpeed 之間遷移。切換主要透過 Accelerate 設定檔或 DeepSpeed 與 FSDP 插件類別來處理。遷移時的主要考量包括:
- 分片策略:在各框架間達成等效的分片。
- 模型載入:實作高效的載入模式。
- 權重預取:管理權重在 GPU 之間的搬移方式。
- 檢查點:處理各框架在保存與載入模型狀態上的差異。