集群作业队列#
SkyPilot的作业队列允许多个作业在集群上调度。
入门指南#
每个由sky exec提交的任务都会自动排队并安排在现有集群上执行:
# Launch the job 5 times.
sky exec mycluster task.yaml -d
sky exec mycluster task.yaml -d
sky exec mycluster task.yaml -d
sky exec mycluster task.yaml -d
sky exec mycluster task.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
多节点任务#
作业队列也支持在多个节点上运行的作业。
首先,创建一个 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 字段用于指定需要多少个节点。
接下来,创建一个 task.yaml 来指定每个任务:
num_nodes: 2
resources:
accelerators: H100:4
run: |
# Run training script.
...
这指定了一个需要在2个节点上运行的任务,每个节点必须有4个空闲的H100。
使用 sky exec mycluster task.yaml 提交此任务,该任务将由作业队列正确调度。
详情请参见分布式多节点作业。
使用 CUDA_VISIBLE_DEVICES#
环境变量 CUDA_VISIBLE_DEVICES 将自动设置为分配给每个节点上每个任务的设备。此变量在任务的 run 命令被调用时设置。
例如,上面的task.yaml在每个有8个GPU的节点上启动一个4-GPU任务,因此任务的run命令将使用填充了4个设备ID的CUDA_VISIBLE_DEVICES来调用。
如果你的run命令使用Docker/docker run,只需传递--gpus=all;
正确的环境变量将在容器内设置(只会设置分配的设备ID)。
示例:网格搜索#
向集群提交具有不同超参数的多个试验:
$ sky exec mycluster --gpus H100:1 -d -- python train.py --lr 1e-3
$ sky exec mycluster --gpus H100:1 -d -- python train.py --lr 3e-3
$ sky exec mycluster --gpus H100:1 -d -- python train.py --lr 1e-4
$ sky exec mycluster --gpus H100:1 -d -- python train.py --lr 1e-2
$ sky exec mycluster --gpus H100:1 -d -- python train.py --lr 1e-6
使用的选项:
--gpus: 指定每个作业的资源需求。-d/--detach: 将运行和日志记录从终端分离,允许多个试验同时运行。
如果集群上只有4个H100 GPU,SkyPilot将排队1个作业,而其他4个作业并行运行。一旦一个作业完成,下一个作业将立即开始执行。 有关SkyPilot调度行为的更多详细信息,请参见下方。
提示
你也可以使用环境变量为每个试验设置不同的参数。
示例:部分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的调度器有两个目标:
防止资源过度分配:SkyPilot 使用任务的资源要求在集群上调度作业——这些要求可以在任务的 YAML 文件的
resources字段中指定,或者通过sky execCLI 命令的--gpus选项指定。SkyPilot 在确保集群中没有资源被过度分配的情况下,尊重这些资源要求。例如,如果一个节点有 4 个 GPU,它不能承载一组任务,这些任务的 GPU 需求总和超过 4。最小化资源闲置:如果资源处于闲置状态,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 task 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;所有其他任务都在等待(没有可用的GPU)。前两个
sky exec作业(job2, job3)随后开始运行,每个作业占用1个GPU。第三个作业(job4)将会挂起,因为它需要4个GPU,而目前只有2个空闲的GPU可用。
第四个作业(job5)将开始运行,因为其需求已通过2个空闲的GPU得到满足。
一旦除了job5之外的所有任务完成,集群的4个GPU将再次空闲,job4将从待定状态转变为运行状态。
因此,我们可能会在这个集群上看到以下作业状态:
$ 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