

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# SageMaker 分散式模型平行化程式庫組態提示和缺陷
<a name="model-parallel-customize-tips-pitfalls"></a>

使用 Amazon SageMaker AI 模型平行化程式庫之前，請先檢閱下列提示和缺陷。此清單包含適用於跨架構的提示。如需 TensorFlow 和 PyTorch 的特定提示，請分別參閱 [修改 TensorFlow 訓練指令碼](model-parallel-customize-training-script-tf.md) 和 [修改 PyTorch 訓練指令碼](model-parallel-customize-training-script-pt.md)。

## 批次大小和微批次數量
<a name="model-parallel-customize-tips-pitfalls-batch-size"></a>
+ 當批次大小增加時，程式庫效率最高。對於模型符合單一裝置但只能以小批次進行訓練的使用案例，在整合程式庫之後，批次大小可以且應該增加。模型平行化可節省大型模型的記憶體，讓您能夠使用先前不符合記憶體的批次大小進行訓練。
+ 選擇太小或太大的微批次數量可能會降低性能。該程式庫在每個裝置中循序執行每個微批次，因此微批大小 (批次大小除以微批次數量) 必須足夠以充分利用每個 GPU。同時，管道效率隨著微批次數量增加，因此保持正確的平衡非常重要。通常，好的起點是嘗試 2 或 4 微批次，將批次大小增加到記憶體限制，然後實驗使用更大的批次大小和微批次數量。隨著微批次數量增加，如果已使用交錯管道，則更大的批次大小可能會變得可行。
+ 您的批次大小必須始終可以被微批次數量整除。請注意，根據資料集的大小，有時每個週期的最後一批次可能比其餘更小，並且這個較小的批次也需要被微批次的數量整除。如果沒有，您可以在 `tf.Dataset.batch()` 呼叫中設定 `drop_remainder=True` (在 TensorFlow 中)，或在 `DataLoader` 中設定 `drop_last=True` (在 PyTorch 中)，以便不使用最後一個小批次。如果您為 Data Pipeline 使用不同的 API，則每當最後一個批次無法被微批次數量整除時，您可能需要手動略過最後一個批次。

## 手動分割
<a name="model-parallel-customize-tips-pitfalls-manual-partitioning"></a>
+ 如果您使用手動分割，請注意模型中多個作業和模組所使用的參數，例如轉換器架構中的內嵌資料表。共用相同參數的模組必須放置在同一裝置中，以確保正確性。使用自動分割時，程式庫會自動強制執行此限制。

## 資料準備
<a name="model-parallel-customize-tips-pitfalls-data-preparation"></a>
+ 如果模型需要多個輸入，請確保使用 `smp.dp_rank()` 在 Data Pipeline 中植入隨機操作 (例如，隨機顯示)。如果資料集在資料平行裝置之間進行確定性分割，請確保碎片已由 `smp.dp_rank()` 編製索引。這是為了確保在形成模型分區的所有排名上，看到的資料順序是一致的。

## 從 `smp.DistributedModel` 中傳回張量
<a name="model-parallel-customize-tips-pitfalls-return-tensors"></a>
+ 從 `smp.DistributedModel.call` (適用於 TensorFlow) 或 `smp.DistributedModel.forward` (適用於 PyTorch) 函式傳回的任何張量都會廣播至所有其他排名，包括運算特定張量的排名。因此，在呼叫和轉送方法 (例如中繼啟動) 之外不需要的任何張量都不應傳回，因為這會造成不必要的通訊和記憶體負荷，並且損害效能。

## `@smp.step` 裝飾項目
<a name="model-parallel-customize-tips-pitfalls-smp-step-decorator"></a>
+ 如果 `smp.step` 裝飾函式具有沒有批次維度的張量引數，則在呼叫 `smp.step` 時必須在 `non_split_inputs` 清單中提供引數名稱。這樣可以防止程式庫嘗試將張量分成微批次。如需詳細資訊，請參閱 API 文件中的 [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_common_api.html](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_common_api.html)。

## 延遲參數初始化
<a name="model-parallel-customize-tips-pitfalls-delaying-param-initialization"></a>

對於超過 100 億個參數的極大型模型，透過 CPU 記憶體進行加權初始化可能導致記憶體不足錯誤。若要因應此問題，程式庫提供 `smp.delay_param_initialization` 關聯內容管理員。這會延遲參數的實體配置，直到它們在 `smp.step` 裝飾函式第一次執行期間移動到 GPU。這樣可以避免訓練初始化期間 CPU 的不必要記憶體使用量。當您建立模型物件時，請使用關聯內容管理員，如下列程式碼所示。

```
with smp.delay_param_initialization(enabled=True):    
    model = MyModel()
```

## PyTorch 的張量平行處理
<a name="model-parallel-customize-tips-pitfalls-tensor-parallelism-pytorch"></a>
+ 如果您使用種子取得確定性結果，請根據 `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` 採取不同步驟數而造成的懸置。
+ 如果您使用 PyTorch `DistributedDataParallel` 類別的 `join` API，處理不同資料平行排名具有不同批次數量的情況，您仍然需要確保相同 `TP_GROUP` 的排名具有相同批次數量；否則用於分散式模組執行的通訊集合可能會懸置。只要使用 `join` API，位於不同 `TP_GROUP` 的排名就可以有不同的批次數量。
+ 如果您想要對模型執行檢查點，並使用張量平行處理，請考慮下列事項：
  + 當您使用張量平行處理時，若要避免在儲存和載入模型時出現延遲和競爭狀態，請確認您從已降低的資料平行處理排名內的下列模型和最佳化工具狀態呼叫適當的函式。
  + 如果您正在傳輸現有管道平行指令碼，並為指令碼啟用張量平行，請務必修改用於使用 `if smp.rdp_rank() == 0` 儲存和載入的任何 `if smp.dp_rank() == 0` 區塊。否則，可能導致您的訓練任務停止。

  如需對具有張量平行處理之模型執行檢查點的更多相關資訊，請參閱[對分散式模型進行檢查點](distributed-model-parallel-checkpointing-and-finetuning.md#distributed-model-parallel-checkpoint)。