集群作业#

您可以在现有集群上运行作业,这些作业会自动排队和调度。

这非常适合在现有集群上进行交互式开发以及重用其设置。

入门#

使用 sky exec 命令向现有集群提交作业

# Launch the job 5 times.
sky exec mycluster job.yaml -d
sky exec mycluster job.yaml -d
sky exec mycluster job.yaml -d
sky exec mycluster job.yaml -d
sky exec mycluster job.yaml -d

-d / --detach 标志会将日志与终端分离,这对于并发启动许多长时间运行的作业很有用。

要显示集群的作业及其状态

# Show a cluster's jobs (job IDs, statuses).
sky queue mycluster

要显示每个作业的输出

# Stream the outputs of a job.
sky logs mycluster JOB_ID

要取消作业

# Cancel a job.
sky cancel mycluster JOB_ID

# Cancel all jobs on a cluster.
sky cancel mycluster --all

提示

sky launch 命令/CLI 在一次调用中执行许多步骤,包括向现有或新供应的集群提交作业。请参阅此处

多节点作业#

也支持在多个节点上运行的作业。

首先,创建一个 cluster.yaml 文件来指定所需的集群

num_nodes: 4
resources:
  accelerators: H100:8

workdir: ...
setup: |
  # Install dependencies.
  ...

使用 sky launch -c mycluster cluster.yaml 命令供应一个 4 节点集群(每个节点有 8 个 H100 GPU)。num_nodes 字段用于指定所需的节点数量。

接下来,创建一个 job.yaml 文件来指定每个作业

num_nodes: 2
resources:
  accelerators: H100:4

run: |
  # Run training script.
  ...

这指定了一个需要在 2 个节点上运行的作业,每个节点必须有 4 个空闲的 H100。然后您可以使用 sky exec mycluster job.yaml 命令提交此作业。

有关更多详细信息,请参阅分布式多节点作业

使用 CUDA_VISIBLE_DEVICES#

环境变量 CUDA_VISIBLE_DEVICES 会自动设置为分配给每个节点上每个作业的设备。此变量在调用作业的 run 命令时设置。

例如,上面的 job.yaml 在每个有 8 个 GPU 的节点上启动一个需要 4 个 GPU 的作业,因此在调用该作业的 run 命令时,CUDA_VISIBLE_DEVICES 将填充 4 个设备 ID。

如果您的 run 命令使用 Docker/docker run,只需传递 --gpus=all;正确的环境变量将在容器内部设置(只会设置分配的设备 ID)。

示例:分数 GPU#

要在每个 GPU 上运行多个试验,请在资源需求中使用分数 GPU。例如,使用 --gpus H100:0.5 让 2 个试验共享 1 个 GPU

$ sky exec mycluster --gpus H100:0.5 -d -- python train.py --lr 1e-3
$ sky exec mycluster --gpus H100:0.5 -d -- python train.py --lr 3e-3
...

共享 GPU 时,请确保 GPU 的内存没有超额分配(否则可能会发生内存不足错误)。

调度行为#

SkyPilot 的调度器有两个目标

  1. 防止资源超额分配:SkyPilot 使用作业的资源需求在集群上调度作业——这些需求可以在作业 YAML 的 resources 字段中指定,或者通过 sky exec CLI 命令的 --gpus 选项指定。SkyPilot 尊重这些资源需求,同时确保集群中的任何资源都不会超额分配。例如,如果一个节点有 4 个 GPU,它不能托管多个作业,这些作业的 GPU 需求总和超过 4。

  2. 最小化资源空闲:如果某个资源处于空闲状态,SkyPilot 将调度一个可以利用该资源的排队作业。

我们通过回顾教程:AI 训练来阐述调度行为。在该教程中,我们有一个作业 YAML 文件,指定了这些资源需求

# dnn.yaml
...
resources:
  accelerators: H100:4
...

由于我们在运行 sky launch -c lm-cluster dnn.yaml 时创建了一个新集群,SkyPilot 供应的集群资源与作业所需的资源完全相同。因此,lm-cluster 有 4 个 H100 GPU。

在这个初始作业正在运行时,我们提交更多作业

$ # Launch 4 jobs, perhaps with different hyperparameters.
$ # You can override the job name with `-n` (optional) and
$ # the resource requirement with `--gpus` (optional).
$ sky exec lm-cluster dnn.yaml -d -n job2 --gpus=H100:1
$ sky exec lm-cluster dnn.yaml -d -n job3 --gpus=H100:1
$ sky exec lm-cluster dnn.yaml -d -n job4 --gpus=H100:4
$ sky exec lm-cluster dnn.yaml -d -n job5 --gpus=H100:2

由于集群只有 4 个 H100 GPU,我们将看到以下事件序列

  • 初始的 sky launch 作业正在运行并占用 4 个 GPU;所有其他作业都处于 pending(等待中)状态(没有空闲 GPU)。

  • 然后前两个 sky exec 作业(job2、job3)开始运行,每个占用 1 个 GPU。

  • 第三个作业(job4)将处于 pending(等待中)状态,因为它需要 4 个 GPU,而只剩下 2 个空闲 GPU。

  • 第四个作业(job5)将开始运行,因为它的需求可以通过剩下的 2 个空闲 GPU 满足。

  • 一旦除了 job5 之外的所有作业都完成,集群的 4 个 GPU 将再次变为空闲,job4 将从 pending 状态转换为 running(运行中)状态。

因此,我们可能会在此集群上看到以下作业状态

$ sky queue lm-cluster

 ID  NAME         USER  SUBMITTED    STARTED     STATUS
 5   job5         user  10 mins ago  10 mins ago RUNNING
 4   job4         user  10 mins ago  -           PENDING
 3   job3         user  10 mins ago  9 mins ago  RUNNING
 2   job2         user  10 mins ago  9 mins ago  RUNNING
 1   huggingface  user  10 mins ago  1 min ago   SUCCEEDED