torchrun(彈性啟動)¶
torch.distributed.launch 的超集。
torchrun 提供了 torch.distributed.launch 的功能超集,並具有以下額外功能
- 透過重新啟動所有工作者,可以妥善處理工作者失敗。 
- 工作者 - RANK和- WORLD_SIZE會自動分配。
- 允許節點數量在最小和最大大小之間變化(彈性)。 
注意
torchrun 是一個 Python 主控台腳本,指向 setup.py 中 entry_points 設定中宣告的主要模組 torch.distributed.run。它相當於呼叫 python -m torch.distributed.run。
從 torch.distributed.launch 轉換到 torchrun¶
torchrun 支援與 torch.distributed.launch 相同的參數,除了 --use-env 現在已棄用。要從 torch.distributed.launch 遷移到 torchrun,請按照以下步驟操作
- 如果您的訓練腳本已經從 - LOCAL_RANK環境變數讀取- local_rank。那麼您只需要省略- --use-env旗標,例如- torch.distributed.launch- torchrun- $ python -m torch.distributed.launch --use-env train_script.py - $ torchrun train_script.py 
- 如果您的訓練腳本從 - --local-rank命令列參數讀取本地端排名。請將您的訓練腳本更改為從- LOCAL_RANK環境變數讀取,如下段程式碼片段所示- torch.distributed.launch- torchrun- import argparse parser = argparse.ArgumentParser() parser.add_argument("--local-rank", type=int) args = parser.parse_args() local_rank = args.local_rank - import os local_rank = int(os.environ["LOCAL_RANK"]) 
在 2.0.0 版中已變更: 啟動器會將 --local-rank=<rank> 參數傳遞給您的腳本。從 PyTorch 2.0.0 開始,建議使用帶破折號的 --local-rank,而不是先前使用的帶底線的 --local_rank。
為了向後相容,使用者可能需要在其參數解析程式碼中處理這兩種情況。這表示在參數解析器中同時包含 "--local-rank" 和 "--local_rank"。如果只提供 "--local_rank",啟動器將觸發錯誤:「錯誤:無法辨識的參數:–local-rank=<rank>」。對於僅支援 PyTorch 2.0.0+ 的訓練程式碼,包含 "--local-rank" 應該就足夠了。
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("--local-rank", "--local_rank", type=int)
>>> args = parser.parse_args()
上述更改足以從 torch.distributed.launch 遷移到 torchrun。要利用 torchrun 的新功能,例如彈性、容錯和錯誤報告,請參閱
- 訓練腳本 以取得更多關於編寫符合 - torchrun規範的訓練腳本的資訊。
- 本頁面的其餘部分,以取得更多關於 - torchrun功能的資訊。
用法¶
單節點多工作者¶
torchrun
    --standalone
    --nnodes=1
    --nproc-per-node=$NUM_TRAINERS
    YOUR_TRAINING_SCRIPT.py (--arg1 ... train script args...)
堆疊式單節點多工作者¶
要在同一台主機上執行多個單節點、多工作者的執行個體(個別作業),我們需要確保每個執行個體(作業)都設定在不同的埠上,以避免埠衝突(或者更糟的情況是,兩個作業被合併為一個作業)。為此,您必須使用 --rdzv-backend=c10d 執行,並透過設定 --rdzv-endpoint=localhost:$PORT_k 指定不同的埠。對於 --nodes=1,通常讓 torchrun 自動選擇一個可用的隨機埠,而不是每次執行時手動分配不同的埠,這樣會比較方便。
torchrun
    --rdzv-backend=c10d
    --rdzv-endpoint=localhost:0
    --nnodes=1
    --nproc-per-node=$NUM_TRAINERS
    YOUR_TRAINING_SCRIPT.py (--arg1 ... train script args...)
容錯(固定數量的工作者,無彈性,容許 3 次失敗)¶
torchrun
    --nnodes=$NUM_NODES
    --nproc-per-node=$NUM_TRAINERS
    --max-restarts=3
    --rdzv-id=$JOB_ID
    --rdzv-backend=c10d
    --rdzv-endpoint=$HOST_NODE_ADDR
    YOUR_TRAINING_SCRIPT.py (--arg1 ... train script args...)
以 <主機>[:<埠>] 形式(例如 node1.example.com:29400)的 HOST_NODE_ADDR 指定要建立和託管 C10d 會合後端的節點和埠。它可以是您的訓練叢集中的任何節點,但理想情況下,您應該選擇具有高頻寬的節點。
注意
如果未指定埠號,則 HOST_NODE_ADDR 預設為 29400。
彈性 (min=1, max=4,最多可容忍 3 個成員變更或故障)¶
torchrun
    --nnodes=1:4
    --nproc-per-node=$NUM_TRAINERS
    --max-restarts=3
    --rdzv-id=$JOB_ID
    --rdzv-backend=c10d
    --rdzv-endpoint=$HOST_NODE_ADDR
    YOUR_TRAINING_SCRIPT.py (--arg1 ... train script args...)
以 <主機>[:<埠>] 形式(例如 node1.example.com:29400)的 HOST_NODE_ADDR 指定要建立和託管 C10d 會合後端的節點和埠。它可以是您的訓練叢集中的任何節點,但理想情況下,您應該選擇具有高頻寬的節點。
注意
如果未指定埠號,則 HOST_NODE_ADDR 預設為 29400。
關於會合後端的注意事項¶
對於多節點訓練,您需要指定
- --rdzv-id:一個唯一的工作 ID(由參與工作的所有節點共用)
- --rdzv-backend:- torch.distributed.elastic.rendezvous.RendezvousHandler的實作
- --rdzv-endpoint:會合後端執行的端點;通常採用- 主機:埠的形式。
目前支援開箱即用的 c10d(推薦)、etcd-v2 和 etcd(舊版)會合後端。若要使用 etcd-v2 或 etcd,請設定啟用 v2 API 的 etcd 伺服器(例如 --enable-v2)。
警告
etcd-v2 和 etcd 會合使用 etcd API v2。您必須在 etcd 伺服器上啟用 v2 API。我們的測試使用 etcd v3.4.3。
警告
對於基於 etcd 的會合,我們建議使用 etcd-v2,而不是功能相同的 etcd,但使用的是修改過的實作。etcd 處於維護模式,並將在未來版本中移除。
定義¶
- 節點- 一個實體執行個體或容器;對應到工作管理器處理的單位。
- 工作器- 分散式訓練上下文中的工作器。
- 工作器群組- 執行相同函數(例如訓練器)的工作器集合。
- 本地工作器群組- 在同一個節點上運行的部分工作器群組工作器。
- RANK- 工作器在工作器群組中的排名。
- WORLD_SIZE- 工作器群組中的工作器總數。
- LOCAL_RANK- 工作器在本地工作器群組中的排名。
- LOCAL_WORLD_SIZE- 本地工作器群組的大小。
- rdzv_id- 一個使用者定義的 ID,用於唯一識別工作的工作器群組。每個節點都使用此 ID 作為特定工作器群組的成員加入。
- rdzv_backend- 會合的後端(例如- c10d)。這通常是一個強一致性的鍵值儲存庫。
- rdzv_endpoint- 會合後端端點;通常採用- <主機>:<埠>的形式。
一個 節點 運行 LOCAL_WORLD_SIZE 個工作器,這些工作器構成一個 本地工作器群組。工作中所有節點中所有 本地工作器群組 的聯合構成 工作器群組。
環境變數¶
以下環境變數可在您的腳本中使用
- LOCAL_RANK- 本地排名。
- RANK- 全域排名。
- GROUP_RANK- 工作器群組的排名。介於 0 到- max_nnodes之間的數字。當每個節點運行一個工作器群組時,這就是節點的排名。
- ROLE_RANK- 工作器在具有相同角色的所有工作器中的排名。工作器的角色在- WorkerSpec中指定。
- LOCAL_WORLD_SIZE- 本地世界大小(例如,本地運行的 worker 數量);等於在- torchrun上指定的- --nproc-per-node。
- WORLD_SIZE- 世界大小(工作中的工作器總數)。
- ROLE_WORLD_SIZE- 使用- WorkerSpec中指定的相同角色啟動的工作器總數。
- MASTER_ADDR- 運行排名為 0 的工作器的 FQDN;用於初始化 Torch Distributed 後端。
- MASTER_PORT-- MASTER_ADDR上可用於託管 C10d TCP 儲存庫的埠。
- TORCHELASTIC_RESTART_COUNT- 到目前為止,工作器群組重新啟動的次數。
- TORCHELASTIC_MAX_RESTARTS- 配置的最大重新啟動次數。
- TORCHELASTIC_RUN_ID- 等於會合- run_id(例如,唯一的工作 ID)。
- PYTHON_EXEC- 系統可執行檔覆寫。如果提供,則 Python 使用者腳本將使用- PYTHON_EXEC的值作為可執行檔。預設情況下使用 sys.executable。
部署¶
- (C10d 後端不需要)啟動會合後端伺服器並取得端點(作為 - --rdzv-endpoint傳遞給啟動器腳本)
- 單節點多工作器:在主機上啟動啟動器以啟動代理進程,該進程會建立並監控本地工作器群組。 
- 多節點多工作器:在參與訓練的所有節點上使用相同的參數啟動啟動器。 
當使用工作/叢集管理器時,多節點工作的進入點命令應該是這個啟動器。
故障模式¶
- 工作器故障:對於具有 - n個工作器的訓練工作,如果- k<=n個工作器故障,則所有工作器都會停止並重新啟動,最多- max_restarts次。
- 代理故障:代理故障會導致本地工作器群組故障。由工作管理器決定是使整個工作失敗(群組語義)還是嘗試替換節點。代理支援這兩種行為。 
- 節點故障:與代理故障相同。 
成員變更¶
- 節點離開(縮減):代理會收到離開通知,所有現有的工作器都會停止,會形成一個新的 - 工作器群組,並且所有工作器都會使用新的- RANK和- WORLD_SIZE啟動。
- 節點到達(擴展):新的節點會被允許加入工作,所有現有的工作器都會停止,會形成一個新的 - 工作器群組,並且所有工作器都會使用新的- RANK和- WORLD_SIZE啟動。
重要注意事項¶
- 這個工具和多進程分散式(單節點或多節點)GPU 訓練目前只有在使用 NCCL 分散式後端時才能達到最佳效能。因此,NCCL 後端是 GPU 訓練的推薦後端。 
- 初始化 Torch 進程群組所需的環境變數由本模組提供,您無需手動傳遞 - RANK。若要在您的訓練腳本中初始化進程群組,只需運行
>>> import torch.distributed as dist
>>> dist.init_process_group(backend="gloo|nccl")
- 在您的訓練程序中,您可以使用常規的分散式函數,也可以使用 - torch.nn.parallel.DistributedDataParallel()模組。如果您的訓練程序使用 GPU 進行訓練,並且您想使用- torch.nn.parallel.DistributedDataParallel()模組,以下是配置方法。
local_rank = int(os.environ["LOCAL_RANK"])
model = torch.nn.parallel.DistributedDataParallel(model,
                                                  device_ids=[local_rank],
                                                  output_device=local_rank)
請確保將 device_ids 參數設定為您的代碼將在其上運行的唯一 GPU 裝置 ID。這通常是進程的本地排名。換句話說,若要使用此工具,device_ids 必須是 [int(os.environ("LOCAL_RANK"))],而 output_device 必須是 int(os.environ("LOCAL_RANK"))
- 發生故障或成員變更時,所有存活的工作器都會立即被終止。請確保檢查點您的進度。檢查點的頻率應該取決於您的工作對丟失工作的容忍度。 
- 本模組僅支援同質的 - LOCAL_WORLD_SIZE。也就是說,假設所有節點都運行相同數量的本地工作器(每個角色)。
- RANK不穩定。在重新啟動之間,節點上的本地工作器可能會被分配到與之前不同的排名範圍。永遠不要對排名的穩定性或- RANK和- LOCAL_RANK之間的某些關聯性進行硬編碼假設。
- 當使用彈性( - min_size!=max_size)時,不要對- WORLD_SIZE進行硬編碼假設,因為世界大小可能會隨著節點被允許離開和加入而改變。
- 建議您的腳本具有以下結構 
def main():
  load_checkpoint(checkpoint_path)
  initialize()
  train()
def train():
  for batch in iter(dataset):
    train_step(batch)
    if should_checkpoint:
      save_checkpoint(checkpoint_path)
- (推薦)在工作器出錯時,此工具將摘要錯誤的詳細資訊(例如,時間、排名、主機、PID、回溯等)。在每個節點上,第一個錯誤(按時間戳記)會被啟發式地報告為「根本原因」錯誤。若要取得回溯作為此錯誤摘要列印輸出的一部分,您必須在訓練腳本中裝飾您的主要進入點函數,如下例所示。如果沒有裝飾,則摘要將不包含異常的回溯,並且只會包含退出代碼。有關 torchelastic 錯誤處理的詳細資訊,請參閱:https://pytorch.com.tw/docs/stable/elastic/errors.html 
from torch.distributed.elastic.multiprocessing.errors import record
@record
def main():
    # do train
    pass
if __name__ == "__main__":
    main()