1、分布式訓練時,包括train.py的全部的代碼都會在每個gpu上運行嗎?
- 在分布式訓練(如使用 PyTorch 的 DistributedDataParallel,DDP)時,每個 GPU 上運行的進程會執行 train.py 的全部代碼,但通過分布式機制(如 rank、world_size、torch.distributed 等)控制不同進程的行為,確保它們協作完成訓練任務。
- 每個 GPU 對應一個獨立的進程,每個進程都會從頭到尾完整執行 train.py 的代碼(包括數據加載、模型初始化、前向/反向傳播等)。但通過條件判斷和分布式通信,不同進程會執行不同的邏輯分支(例如:僅 rank=0 的進程保存模型、打印日志等)。
2、解釋下面分布式訓練的啟動代碼
CONFIG=$1
GPUS=$2
PORT=${PORT:-28651}PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
python3 -m torch.distributed.launch --nproc_per_node=$GPUS --master_port=$PORT \$(dirname "$0")/train.py $CONFIG --launcher pytorch ${@:3}
這段代碼是一個用于啟動分布式訓練的 Bash 腳本,通常用于 PyTorch 的 DistributedDataParallel (DDP) 訓練。它通過 torch.distributed.launch 啟動多個進程(每個 GPU 一個進程),并傳遞必要的參數。
3、torch.distributed.launch后面接的train.py的位置可以任意嗎?
Python 解釋器在執行腳本時,會根據提供的路徑(絕對路徑、相對路徑或模塊名)動態定位文件,只要路徑有效即可。torch.distributed.launch 只是將 train.py 的路徑傳遞給 Python 解釋器,由解釋器負責加載文件,因此路徑格式只需符合 Python 的規則即可。
torch.distributed.launch 后面接的訓練腳本名稱 可以是任意有效的 Python 腳本文件名,只需滿足以下條件:
后綴必須是 .py:因為 torch.distributed.launch 最終會調用 Python 解釋器執行該文件。
文件名允許任意命名:如 train.py、main.py、custom_script.py 均可,只需文件內容符合訓練邏輯。
4、解釋下面分布式訓練的初始化代碼
dist_params = dict(backend="nccl")
init_dist(args.launcher, timeout=timedelta(seconds=3600), **cfg.dist_params)
- 指定啟動器為pytorch,指定gpu間的通信為"nccl",設置通信超時為1小時,定義一個字典 dist_params,指定分布式訓練的后端通信庫為 NCCL(NVIDIA Collective Communications Library)。“nccl” 指定分布式訓練使用的通信后端,nccl 是 NVIDIA GPU 間高效通信的庫,適用于多 GPU 訓練。
- 底層實現(PyTorch 分布式核心)
init_dist 函數內部通常會調用 PyTorch 的 torch.distributed.init_process_group,關鍵邏輯如下:
import torch.distributed as dist
def init_dist(launcher, **kwargs):if launcher == "pytorch":dist.init_process_group(**kwargs) # 實際初始化分布式環境elif launcher == "slurm":# SLURM 集群的特殊處理...
init_process_group 的關鍵參數
backend:通信后端(如 “nccl”)。
init_method:進程組初始化方式(如 “env://” 表示通過環境變量自動發現)。
world_size:全局進程數(通常由啟動器自動設置)。
rank:當前進程的全局編號(由啟動器自動設置)。
進程組操作的超時時間(timeout) 是指分布式進程組(Process Group)在執行集體通信操作(如梯度同步、數據廣播等)時的最大等待時間。如果操作在指定時間內未完成,會觸發超時錯誤(torch.distributed.DistBackendError)。
5、梯度同步
梯度同步的基本流程
(1) 前向傳播
每個 GPU 獨立處理自己分配到的數據(一個 mini-batch 的子集),計算 本地損失(local loss)。
注意:每個 GPU 的損失是基于其本地數據計算的,不是全局所有數據的平均損失。
(2) 反向傳播
每個 GPU 根據本地損失計算 本地梯度(即對模型參數的偏導數)。
此時各 GPU 的梯度可能不同(因數據不同)。
(3) 梯度同步(關鍵步驟)
通過 All-Reduce 操作(通常是求和或平均)將所有 GPU 的梯度同步,得到全局一致的梯度。
同步后的梯度 = 所有 GPU 本地梯度的均值(若使用 平均)或總和(若使用 求和)。
(4) 參數更新
所有 GPU 使用同步后的全局梯度更新模型參數(保證所有 GPU 的模型始終保持一致)。
6、既然每個gpu獨立計算本地損失,那每次訓練迭代后,可視化的損失是如何計算的
在分布式訓練中,可視化的損失值通常是通過對多個 GPU 的本地損失進行聚合計算得到的。具體計算方式和實現邏輯如下:
損失計算的基本流程
在分布式訓練(如 PyTorch 的 DistributedDataParallel)中,每個 GPU 獨立處理一部分數據(batch_size / num_gpus),并按以下步驟計算損失:
前向傳播:
每個 GPU 用當前模型參數計算其本地數據的預測結果。
計算 本地損失(如交叉熵、MSE),假設為 loss_local。
反向傳播:
根據本地損失計算梯度(loss_local.backward())。
通過 All-Reduce 同步梯度(梯度取平均或求和,取決于配置)。
損失聚合:
為了可視化或日志記錄,需要將所有 GPU 的本地損失聚合為 全局損失。
2. 損失聚合的常見方法
(1) 直接求平均(默認推薦)
公式:
global_loss=1N∑i=1Nloss_locali
global_loss=N1?i=1∑N?loss_locali?
NN 是 GPU 數量(world_size)。
物理意義:所有 GPU 本地損失的均值,等價于單卡使用全局 batch 計算的損失。
PyTorch 實現:
import torch.distributed as dist
# 計算本地損失(每個 GPU 的 batch 是總 batch 的一部分)
loss_local = criterion(output, target)
# 聚合所有 GPU 的損失(求平均)
dist.all_reduce(loss_local, op=dist.ReduceOp.SUM) # 先求和
global_loss = loss_local / dist.get_world_size() # 再除以 GPU 數量