分布式多节点作业#
SkyPilot 支持多节点集群供应和在多个节点上进行分布式执行。
例如,这里有一个简单的示例,展示如何在 2 个节点上使用 PyTorch 的分布式数据并行 (DDP) 来训练一个类似 GPT 的模型(灵感来自 Karpathy 的 minGPT)。
name: minGPT-ddp
resources:
accelerators: A100:8
num_nodes: 2
setup: |
git clone --depth 1 https://github.com/pytorch/examples || true
cd examples
git filter-branch --prune-empty --subdirectory-filter distributed/minGPT-ddp
# SkyPilot's default image on AWS/GCP has CUDA 11.6 (Azure 11.5).
uv venv --python 3.10
source .venv/bin/activate
uv pip install -r requirements.txt "numpy<2" "torch==1.12.1+cu113" --extra-index-url https://download.pytorch.org/whl/cu113
run: |
cd examples
source .venv/bin/activate
cd mingpt
export LOGLEVEL=INFO
MASTER_ADDR=$(echo "$SKYPILOT_NODE_IPS" | head -n1)
echo "Starting distributed training, head node: $MASTER_ADDR"
torchrun \
--nnodes=$SKYPILOT_NUM_NODES \
--nproc_per_node=$SKYPILOT_NUM_GPUS_PER_NODE \
--master_addr=$MASTER_ADDR \
--node_rank=${SKYPILOT_NODE_RANK} \
--master_port=8008 \
main.py
在上面,
num_nodes: 2
指定了此作业将在 2 个节点上运行,每个节点有 8 个 A100;run
部分中高亮显示的行展示了一些常用于启动分布式训练的环境变量,下方将进行解释。
注意
如果您遇到错误 [Errno 24] Too many open files
,这表明您的进程已超出系统允许的最大打开文件描述符数量。这通常发生在负载较高的场景中,例如启动大量节点,例如 100 个。
要解决此问题,请运行以下命令,然后重试
ulimit -n 65535
您可以在我们的 GitHub 仓库中找到更多分布式训练示例(包括使用 rdvz 后端进行 pytorch 训练)。
环境变量#
SkyPilot 暴露了这些可以在作业的 run
命令中访问的环境变量
SKYPILOT_NODE_RANK
:执行作业的节点的 rank(一个从 0 到num_nodes-1
的整数 ID)。SKYPILOT_NODE_IPS
:一个字符串,包含为执行作业而预留的节点的 IP 地址,每行一个 IP 地址。SKYPILOT_NUM_NODES
:为作业预留的节点数量,可以通过num_nodes: <n>
指定。与echo "$SKYPILOT_NODE_IPS" | wc -l
的值相同。SKYPILOT_NUM_GPUS_PER_NODE
:每个节点上为执行作业预留的 GPU 数量;与accelerators: <name>:<count>
中的计数相同(如果是小数则向上取整)。
更多详细信息请参阅SkyPilot 环境变量。
启动多节点作业(新集群)#
使用 sky launch
在新集群上启动多节点作业时,按顺序发生以下步骤
节点被供应。(屏障)
工作目录/文件挂载同步到所有节点。(屏障)
setup
命令在所有节点上执行。(屏障)run
命令在所有节点上执行。
使用 sky jobs launch
启动托管多节点作业时,行为相同。
启动多节点作业(现有集群)#
使用 sky launch
在现有集群上启动多节点作业时,集群中的节点数量可能多于当前作业的 num_nodes
要求。
按顺序发生以下步骤
SkyPilot 检查所有节点上的运行时是否最新。(屏障)
工作目录/文件挂载同步到所有节点。(屏障)
setup
命令在集群的所有节点上执行。(屏障)run
命令在调度执行作业的部分节点上执行,这部分节点数量可能少于集群总数。
提示
要跳过重新运行 setup 命令,可以使用 sky launch --no-setup ...
(执行上述步骤 1、2、4)或 sky exec
(执行步骤 2(仅限工作目录)和步骤 4)。
仅在主节点上执行作业#
要仅在主节点上执行作业(对于 mpirun
等工具来说是常见场景),可以使用 SKYPILOT_NODE_RANK
环境变量,如下所示
...
num_nodes: <n>
run: |
if [ "${SKYPILOT_NODE_RANK}" == "0" ]; then
# Launch the head-only command here.
fi
SSH 到工作节点#
除了主节点,多节点集群中工作节点的 SSH 配置值也会添加到 ~/.ssh/config
文件中,格式为 <cluster_name>-worker<n>
。如果需要,这允许您直接 SSH 到工作节点。
# Assuming 3 nodes in a cluster named mycluster
# Head node.
$ ssh mycluster
# Worker nodes.
$ ssh mycluster-worker1
$ ssh mycluster-worker2
执行分布式 Ray 程序#
要在多个节点上执行分布式 Ray 程序,您可以下载训练脚本并启动作业 yaml 文件
$ wget https://raw.githubusercontent.com/skypilot-org/skypilot/master/examples/distributed_ray_train/train.py
$ # Use a cluster (ideal for interactive development)
$ sky launch ray_train.yaml
$ # Use a managed job (ideal for production, scale-out runs)
$ sky jobs launch ray_train.yaml
resources:
accelerators: L4:2
memory: 64+
num_nodes: 2
workdir: .
setup: |
conda activate ray
if [ $? -ne 0 ]; then
conda create -n ray python=3.10 -y
conda activate ray
fi
pip install "ray[train]"
pip install tqdm
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
run: |
sudo chmod 777 -R /var/tmp
HEAD_IP=`echo "$SKYPILOT_NODE_IPS" | head -n1`
if [ "$SKYPILOT_NODE_RANK" == "0" ]; then
ps aux | grep ray | grep 6379 &> /dev/null || ray start --head --disable-usage-stats --port 6379
sleep 5
python train.py --num-workers $SKYPILOT_NUM_NODES
else
sleep 5
ps aux | grep ray | grep 6379 &> /dev/null || ray start --address $HEAD_IP:6379 --disable-usage-stats
# Add sleep to after `ray start` to give ray enough time to daemonize
sleep 5
fi
警告
使用 Ray 时,请避免调用 ray stop
,因为它也会导致 SkyPilot 运行时停止。