分布式多节点作业#

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新集群上启动多节点作业时,按顺序发生以下步骤

  1. 节点被供应。(屏障)

  2. 工作目录/文件挂载同步到所有节点。(屏障)

  3. setup 命令在所有节点上执行。(屏障)

  4. run 命令在所有节点上执行。

使用 sky jobs launch 启动托管多节点作业时,行为相同。

启动多节点作业(现有集群)#

使用 sky launch现有集群上启动多节点作业时,集群中的节点数量可能多于当前作业的 num_nodes 要求。

按顺序发生以下步骤

  1. SkyPilot 检查所有节点上的运行时是否最新。(屏障)

  2. 工作目录/文件挂载同步到所有节点。(屏障)

  3. setup 命令在集群的所有节点上执行。(屏障)

  4. 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

SSH 访问仅适用于集群(专为交互式开发设计),不适用于托管作业(专为生产和横向扩展运行设计)。

执行分布式 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 运行时停止。