本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
SageMaker 分散式模型平行程式庫組態提示和缺陷
在使用 Amazon SageMaker 的模型平行程式庫之前,請先檢閱下列提示和陷阱。此清單包含適用於跨架構的提示。如需 TensorFlow 和 PyTorch特定秘訣,請分別參閱修改 TensorFlow 訓練指令集和修改 PyTorch 訓練指令集。
批次大小和微批次數量
-
當批次大小增加時,程式庫效率最高。對於模型符合單一裝置但只能以小批次進行訓練的使用案例,在整合程式庫之後,批次大小可以且應該增加。模型平行處理可節省大型模型的記憶體,讓您能夠使用先前不符合記憶體的批次大小進行訓練。
-
選擇太小或太大的微批次數量可能會降低性能。該程式庫在每個裝置中循序執行每個微批次,因此微批大小 (批次大小除以微批次數量) 必須足夠以充分利用每個 GPU。同時,管道效率隨著微批次數量增加,因此保持正確的平衡非常重要。通常,好的起點是嘗試 2 或 4 微批次,將批次大小增加到記憶體限制,然後實驗使用更大的批次大小和微批次數量。隨著微批次數量增加,如果已使用交錯管道,則更大的批次大小可能會變得可行。
-
您的批次大小必須始終可以被微批次數量整除。請注意,根據資料集的大小,有時每個週期的最後一批次可能比其餘更小,並且這個較小的批次也需要被微批次的數量整除。如果不是,則可以在
tf.Dataset.batch()
調用(drop_remainder=True
in TensorFlow)中設置,或者drop_last=True
在DataLoader
(in PyTorch)中設置,這樣最後一個小批量就不會使用。如果您為 Data Pipeline 使用不同的 API,則每當最後一個批次無法被微批次數量整除時,您可能需要手動略過最後一個批次。
手動分割
-
如果您使用手動分割,請注意模型中多個作業和模組所使用的參數,例如轉換器架構中的內嵌資料表。共用相同參數的模組必須放置在同一裝置中,以確保正確性。使用自動分割時,程式庫會自動強制執行此限制。
資料準備
-
如果模型需要多個輸入,請確保使用
smp.dp_rank()
在 Data Pipeline 中植入隨機操作 (例如,隨機顯示)。如果資料集在資料平行裝置之間進行確定性分割,請確保碎片已由smp.dp_rank()
編製索引。這是為了確保在形成模型分區的所有排名上,看到的資料順序是一致的。
從 smp.DistributedModel
中傳回張量
-
從(for TensorFlow)或
smp.DistributedModel.call
smp.DistributedModel.forward
(for PyTorch)函數返回的任何張量都會從計算該特定張量的等級廣播到所有其他級別。因此,在呼叫和轉送方法 (例如中繼啟動) 之外不需要的任何張量都不應傳回,因為這會造成不必要的通訊和記憶體負荷,並且損害效能。
@smp.step
裝飾項目
-
如果
smp.step
裝飾函數具有沒有批次維度的張量引數,則在呼叫smp.step
時必須在non_split_inputs
清單中提供引數名稱。這樣可以防止程式庫嘗試將張量分成微批次。如需詳細資訊,請參閱 API 文件中的smp.step
。
延遲參數初始化
對於超過 100 億個參數的非常大型模型,透過 CPU 記憶體進行加權初始化可能會導致錯 out-of-memory 誤。若要因應此問題,程式庫提供 smp.delay_param_initialization
關聯內容管理員。這會延遲參數的實體配置,直到它們在 smp.step
裝飾函數第一次執行期間移動到 GPU。這樣可以避免訓練初始化期間 CPU 的不必要記憶體使用量。當您建立模型物件時,請使用關聯內容管理員,如下列程式碼所示。
with smp.delay_param_initialization(enabled=True): model = MyModel()
張量平行度 PyTorch
-
如果您使用種子取得確定性結果,請根據
smp.dp_rank()
(例如,torch.manual_seed(42 + smp.dp_rank())
) 設定種子。如果您沒有這樣做,則會以相同的方式初始化nn.Parameter
的不同分割區,從而影響收斂。 -
SageMaker的模型並行程式庫使用 NCCL 來實作分發模組所需的集合。特別是較小型號,如果同時在 GPU 上排程過多的 NCCL 呼叫,則可能因為 NCCL 使用額外的空間,導致記憶體使用量增加。為了阻止這種情況發生,
smp
會調節 NCCL 呼叫,以便在任何給定時間的進行中 NCCL 操作數量小於或等於給定限制。預設限制為 8,但可以使用環境變數SMP_NCCL_THROTTLE_LIMIT
調整。如果您在使用張量平行處理時發現記憶體使用量超出預期,可以嘗試降低此限制。但是,選擇太小的限制可能導致輸送量損失。若要完全停用調節,您可以設定SMP_NCCL_THROTTLE_LIMIT=-1
。 -
當張量平行處理程度為 1 時,以下身份成立;張量平行處理程度大於 1 時則不成立:
smp.mp_size() * smp.dp_size() == smp.size()
。這是因為張量平行群組是模型平行處理群組和資料平行處理群組的一部分。如果您的程式碼具有mp_rank
、mp_size
、MP_GROUP
等的現有參考,並且如果您只想使用管道平行群組,則可能需要將參照取代為smp.pp_size()
。以下身分一律為 true:-
smp.mp_size() * smp.rdp_size() == smp.size()
-
smp.pp_size() * smp.dp_size() == smp.size()
-
smp.pp_size() * smp.tp_size() * smp.rdp_size() == smp.size()
-
-
由於
smp.DistributedModel
包裝函式在已啟用張量平行處理時修改模型參數,因此應使用分散式參數在呼叫smp.DistributedModel
之後建立最佳化工具。例如,下列項目未運作:## WRONG model = MyModel() optimizer = SomeOptimizer(model.parameters()) model = smp.DistributedModel(model) # optimizer now has outdated parameters!
相反地,最佳化工具應該使用下列
smp.DistributedModel
參數來建立:## CORRECT model = smp.DistributedModel(MyModel()) optimizer = SomeOptimizer(model.optimizers())
-
當透過張量平行處理將模組替換為其分散式對應項目時,分散式模組不會從原始模組繼承其權重,並初始化新的權重。這表示,例如,如果權重需要在特定呼叫中初始化 (例如,透過
load_state_dict
呼叫),一旦模組發佈發生,則需要在smp.DistributedModel
呼叫之後進行。 -
當直接存取分散式模組的參數時,請注意,權重不具有與原始模組的相同形狀。例如,
with smp.tensor_parallelism(): linear = nn.Linear(60, 60) # will pass assert tuple(linear.weight.shape) == (60, 60) distributed_linear = smp.DistributedModel(linear) # will fail. the number of input channels will have been divided by smp.tp_size() assert tuple(distributed_linear.module.weight.shape) == (60, 60)
-
強烈建議為張量平行處理使用
torch.utils.data.distributed.DistributedSampler
。這可確保每個資料平行排名都會接收相同數量的資料範例,以防止因不同dp_rank
採取不同步驟數而造成的懸置。 -
如果您使用
DistributedDataParallel
類別 PyTorch的join
API 來處理不同資料 parallel 排名具有不同批次數目的案例,您仍然需要確定相同的等級TP_GROUP
具有相同數量的批次;否則在分散式執行模組中使用的通訊集合可能會當機。只要使用join
API,位於不同TP_GROUP
的排名就可以有不同的批次數量。 -
如果您想要對模型執行檢查點,並使用張量平行處理,請考慮下列事項:
-
當您使用張量平行處理時,若要避免在儲存和載入模型時出現延遲和競爭狀態,請確認您從已降低的資料平行處理排名內的下列模型和最佳化工具狀態呼叫適當的函數。
-
如果您正在傳輸現有管道平行指令碼,並為指令碼啟用張量平行,請務必修改用於使用
if smp.rdp_rank() == 0
儲存和載入的任何if smp.dp_rank() == 0
區塊。否則,可能導致您的訓練任務停止。
如需對具有張量平行處理之模型執行檢查點的更多相關資訊,請參閱 對分散式模型進行檢查點。
-