AWS Machine Learning Blog

Lend and borrow resources across teams with AWS Batch’s quota management for SageMaker Training jobs

8.5内容质量
Lend and borrow resources across teams with AWS Batch’s quota management for SageMaker Training jobs

TL;DR · AI 摘要

AWS Batch推出配额管理功能,允许跨团队共享GPU资源,提升SageMaker训练作业的利用率。

核心要点

  • AWS Batch配额管理支持RESERVE/LEND/LEND_AND_BORROW三种资源分配策略
  • 虚拟队列机制自动处理跨团队资源借贷和抢占,减少人工干预
  • 通过SageMaker Python SDK可配置配额共享,优先执行高优先级任务

结构提纲

按章节快速跳转。

  1. AWS Batch新功能解决多团队AI/ML环境下的GPU资源协调问题

  2. 通过定义配额份额实现资源分配,支持三种资源共享策略

  3. 配额份额作为虚拟队列嵌套在作业队列中,自动处理资源抢占

  4. 使用SageMaker Python SDK设置配额份额和优先级规则

  5. 演示如何配置跨团队资源借贷和高优先级任务抢占

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • AWS Batch配额管理
    • 核心机制
      • 配额份额策略
      • 虚拟队列嵌套
      • 跨份额抢占
    • 使用场景
      • 多团队GPU共享
      • 高优先级任务调度

金句 / Highlights

值得收藏与分享的关键句。

#AWS#机器学习#资源管理#SageMaker#配额管理
打开原文

使用 AWS Batch 的配额管理在 SageMaker 训练作业中跨团队共享资源 | 人工智能

使用 AWS Batch 的配额管理在 SageMaker 训练作业中跨团队共享资源

随着 AWS Batch 对 Amazon SageMaker 训练作业的支持发布,客户获得了一种全新的托管方式,可用于排队、调度和重试机器学习(ML)训练工作负载,而无需构建自己的基础设施。他们改用 AWS Batch 的排队和调度功能。随着组织扩展人工智能和机器学习(AI/ML)运营并引入更多团队,协调对共享图形处理单元(GPU)容量的访问可能会为管理员带来额外的沟通、协调和配置负担。这种负担包括设置独立队列、调整容量限制以及仔细协调合适的工作负载以在合适的时间获取所需资源。AWS Batch 的核心价值主张是帮助客户提高计算资源利用率,随着训练环境的扩展,利用现有容量实现更多目标的机会也在增加。

从管理多团队训练环境的客户反馈出发,我们收到了一致的请求:提供一种方法,按团队或项目定义资源分配,自动共享空闲容量,并优先运行最高优先级的工作负载。这一需求促使我们开发了配额管理功能,这是 AWS Batch 的一项新调度能力。管理员可以使用它将计算容量划分为按团队、项目或工作负载组织的配额份额。每个配额份额使用可配置的资源共享策略,在最大化 GPU 利用率的同时,在最关键的时候尊重每个团队的分配。

本文将展示配额管理的工作原理,包括如何使用借贷策略配置配额份额、设置队内抢占以优先处理高优先级工作负载,以及如何使用 SageMaker Python SDK 开始使用。

配额份额与抢占

管理员可以通过为独立实体(如单个团队或项目)定义配额份额来分配和共享受限的 GPU 资源。每个配额份额包括计算配额(容量限制)和空闲计算的资源共享策略。这些策略决定空闲计算资源是否在任务到达前保留(RESERVE),是否借给有可用任务的其他配额份额(LEND),或在空闲时出借、在有任务需要时借入(LEND_AND_BORROW)。

配额份额作为虚拟队列,在关联的作业队列中分层嵌套运行。在为作业队列调度任务时,AWS Batch 会优先处理未达到容量限制的配额份额。当任务到达已借出容量的配额份额时,AWS Batch 会执行跨份额抢占。这会回收出借配额份额的资源,管理员无需自行追踪借用容量的任务并终止它们。如果任务到达的配额份额已达到或超过其容量限制,AWS Batch 会检查是否有其他配额份额可借用容量。如果有,工作负载可以使用原本空闲的容量运行。

你可以在配置配额共享时启用基于优先级的共享内抢占。与跨共享抢占在作业到达出借配额共享时回收已出借容量不同,共享内抢占会中断处于SCHEDULED、STARTING或RUNNING状态的低优先级作业。这可以让队列前端的高优先级作业更早开始运行。

先决条件

在继续本示例之前,你必须拥有一个具有创建和管理AWS Batch资源权限的AWS账户。关于本示例,请参阅调用AWS Batch和SageMaker API所需的示例IAM权限。

本示例使用SageMaker Python SDK v3。请完成安装兼容版本的SageMaker Python SDK所需的设置:

code
!pip install sagemaker

配置配额管理资源

使用新的配额管理功能需要创建包含quotaSharePolicy的调度策略、以特定实例指定容量限制的服务环境,以及连接两者的SageMaker训练作业队列。之后,你可以将配额共享关联到作业队列。用户指南提供了使用AWS命令行界面(AWS CLI)和控制台配置配额管理资源和配额共享的示例。一个完整的配额管理与SageMaker Python SDK v3中aws_batch模块集成的示例包含在示例笔记本中。在此示例中,我们将逐步展示代码片段以总结关键组件,并使用笔记本中的辅助函数创建调度策略、服务环境、作业队列和三个配额共享。

此处配置的三个配额共享代表三个不同的项目。每个配额共享都设置了相同的容量限制:一个ml.g5.xlarge实例。QS1配额共享代表后台作业。对于该项目,你希望首先运行最重要的后台作业,并尽可能借用可用的空闲容量。在此配额共享中,没有作业是紧急的,中断操作是可以接受的,因为所有作业都使用检查点。该配额共享使用LEND_AND_BORROW资源共享策略,并启用了共享内抢占。这样,同一配额共享中的高优先级作业可以抢占低优先级作业的运行。

code
from sagemaker.train.aws_batch.boto_client import get_batch_boto_client
from utils.aws_batch_resource_management import AwsBatchResourceManager, QuotaShareConfig, create_quota_management_resources

INSTANCE_TYPE = "ml.g5.xlarge"

# 创建调度策略、服务环境、作业队列和配额共享
resource_manager = AwsBatchResourceManager(get_batch_boto_client())
qs1 = QuotaShareConfig(
    name="QS1",
    capacity_unit=INSTANCE_TYPE,
    max_capacity=1,
    in_share_preemption=True,
    sharing_strategy="LEND_AND_BORROW",
    borrow_limit=200
)

QS2代表中优先级工作负载。选择此配置的团队更倾向于等待容量变得可用,而不是承受额外的中断。这些中断可能来自借用容量被回收,或由于高优先级作业提交导致的共享内抢占。这对于较短的作业或大多数提交作业优先级相似的情况是合适的。配额共享仍然可以从作业调度时考虑作业优先级中受益。提交的作业会触发AWS Batch回收运行这些作业所需的任何已出借容量。

code
qs2 = QuotaShareConfig(
    name="QS2",
    capacity_unit=INSTANCE_TYPE,
    max_capacity=1,
    in_share_preemption=False,
    sharing_strategy="LEND"
)

QS3 代表需要尽可能快速启动且中断最少的工作负载。它配置为保留容量,既不向其他配额共享组出借也不借用容量。由于其工作负载不会超出容量限制,因此不会发生跨共享组的抢占。同时通过关闭共享内抢占功能,只要容量限制未改变,提交到该配额共享组的工作负载将不会被 AWS Batch 抢占。

code
qs3 = QuotaShareConfig(
    name="QS3",
    capacity_unit=INSTANCE_TYPE,
    max_capacity=1,
    in_share_preemption=False,
    sharing_strategy="RESERVE"
)

这些配额共享组配置是示例笔记本中 create_quota_management_resources 函数的输入参数,该函数还会使用选定的常量名称配置相应的调度策略、服务环境和作业队列。

code
SCHEDULING_POLICY_NAME = "my-qm-scheduling-policy"
JOB_QUEUE_NAME = "my-sm-training-qm-jq"
SERVICE_ENVIRONMENT_NAME = "my-sm-training-qm-se"

resources = create_quota_management_resources(
    resource_manager=resource_manager,
    scheduling_policy_name=SCHEDULING_POLICY_NAME,
    job_queue_name=JOB_QUEUE_NAME,
    service_environment_name=SERVICE_ENVIRONMENT_NAME,
    capacity_unit=INSTANCE_TYPE,
    max_capacity=3,
    quota_share_configs=[qs1, qs2, qs3]
)

向 QS1 提交 SageMaker 训练任务

SageMaker Python SDK 中的 aws_batch 模块已扩展,支持将 SageMaker 训练任务编程式提交到启用配额管理的 AWS Batch 作业队列。为演示这些新功能,我们使用一个简单的 Hello World ModelTrainer 提交到作业队列。以下代码片段根据所选区域和实例类型确定要使用的镜像 URI。

code
import logging

logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logging.getLogger("botocore.client").setLevel(level=logging.WARN)
logger = logging.getLogger(__name__)

from sagemaker.core.helper.session_helper import Session
from sagemaker.core import image_uris

session = Session()

image_uri = image_uris.retrieve(
    framework="pytorch",
    region=session.boto_session.region_name,
    version="2.5",
    instance_type=INSTANCE_TYPE,
    image_scope="training",
)

我们在基础的 Hello World 模型训练器示例中使用这个镜像 URI:

code
from sagemaker.train.model_trainer import ModelTrainer
from sagemaker.train.configs import SourceCode, Compute, StoppingCondition

TRAINING_JOB_NAME = "hello-world-simple-job"
MAX_RUN_TIME = 300

source_code = SourceCode(command="echo 'Hello World'")

model_trainer = ModelTrainer(
    training_image=image_uri,
    source_code=source_code,
    base_job_name=TRAINING_JOB_NAME,
    compute=Compute(instance_type=INSTANCE_TYPE, instance_count=INSTANCE_COUNT),
    stopping_condition=StoppingCondition(max_runtime_in_seconds=MAX_RUN_TIME),
)

要在 SageMaker Python SDK 中使用作业队列,请将队列名称传递给 aws_batch 模块中 TrainingQueue 构造函数。

code
from sagemaker.train.aws_batch.training_queue import TrainingQueue, TrainingQueuedJob

# 使用 SageMaker Python SDK 构造队列对象
queue = TrainingQueue(JOB_QUEUE_NAME)
logger.info(f"Using queue: {queue.queue_name}")

我们随后可以向 QS1(我们的后台任务配额共享)提交三个任务。第一个提交的任务具有最高优先级,其次是中等优先级任务,最后是最低优先级任务。由于当前 QS1 和 QS2 中都没有运行中的任务,应有两实例规模的任务开始运行,对应于最先提交的两个任务(因为它们具有相对最高的优先级)。需要注意的是,由于这是一个简单的“Hello World”训练任务,它不需要数据,但通常 ModelTrainer 需要数据来进行训练。

code
from utils.aws_batch_resource_management import JobStatus, await_jobs, list_jobs_by_quota_share

# 向 QS1 提交三个任务,设置不同优先级以保证调度顺序
qs1_job_high: TrainingQueuedJob = queue.submit(job_name="qs1_job_high", training_job=model_trainer, quota_share_name=qs1.name, priority=3, inputs=None)
qs1_job_med: TrainingQueuedJob = queue.submit(job_name="qs1_job_med", training_job=model_trainer, quota_share_name=qs1.name, priority=2, inputs=None)
qs1_job_low: TrainingQueuedJob = queue.submit(job_name="qs1_job_low", training_job=model_trainer, quota_share_name=qs1.name, priority=1, inputs=None)

logger.info(f"Submitted jobs: {qs1_job_high.job_name}, {qs1_job_med.job_name}, {qs1_job_low.job_name}")
logger.info(f"Waiting for jobs to transition...")

# qs1_job_high 首先使用 QS1 的容量进行调度,qs1_job_med 第二个调度时借用 QS2 的空闲容量
await_jobs([([qs1_job_high, qs1_job_med], JobStatus.dispatched() | JobStatus.terminal())])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())

向 QS2 提交任务会触发跨配额共享抢占以回收借用的容量

拥有 QS2 的团队可能会发现他们有需要执行的工作并提交任务到 QS2。这样做会触发从 QS1 抢占容量(当前 QS1 正在借用这些容量,QS3 的容量未配置为可被借用)。这是一种跨配额共享抢占。

code
# 向 QS2 提交任务时,会从 QS1 抢占其容量
qs2_job_1: TrainingQueuedJob = queue.submit(job_name="qs2_job_1", training_job=model_trainer, quota_share_name=qs2.name, priority=1, inputs=None)

logger.info(f"Submitted job {qs2_job_1.job_name}")
logger.info(f"Waiting for jobs to transition...")

await_jobs([
    ([qs2_job_1], JobStatus.dispatched() | JobStatus.terminal()),
    ([qs1_job_med], {JobStatus.RUNNABLE}) # 最低优先级的 QS1 任务将被抢占
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())

在 QS1 中更新任务优先级会触发同配额共享抢占以运行高优先级任务

如果科学家发现 QS1 中仍处于 RUNNABLE 状态的 qs1_job_low 任务由于优先级变化需要立即运行,他们可以使用新的 UpdateServiceJob API 来提高 QS1 中已提交任务的优先级。由于没有可用容量可供借用,这将触发同配额共享抢占,使当前运行的任务被抢占,从而使 qs1_job_low 开始运行。

code
# 将 qs1_job_low 更新为 QS1 中优先级最高的任务
qs1_job_low.update(scheduling_priority=4)

logger.info(f"Updated job {qs1_job_low.job_name} to increase its priority")
logger.info(f"Waiting for jobs to transition...")
python
await_jobs([
    ([qs1_job_low], JobStatus.dispatched() | JobStatus.terminal()),
    ([qs1_job_high], {JobStatus.RUNNABLE}) # 高优先级任务将在同一配额份额内抢占低优先级任务
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())

(可选) 清理创建的资源

要清理本文创建的资源,请运行以下代码:

code
from utils.aws_batch_resource_management import delete_resources

delete_resources(resource_manager, resources)

结论

在本文中,我们介绍了AWS Batch的配额管理这一新调度功能,以及如何将其与SageMaker训练任务结合使用,并指导您如何为自己的项目设置配额份额。如需更多详细信息,请参阅《AWS Batch配额管理用户指南》。

通过使用带配额管理的AWS Batch,您的组织可以提高计算资源利用率,并更有效地优先安排团队和工作负载,从而为基础设施管理员和机器学习科学家节省时间。通过实施配额管理,您的团队可以专注于其工作负载,减少在管理和协调基础设施上花费的时间。这一功能与Amazon SageMaker AI训练计划结合使用时尤为强大,使您的组织能够在需要的时间段内预留所需数量的资源容量。通过将AWS Batch与SageMaker AI结合使用,您可以充分利用训练计划。我们鼓励您尝试这一新功能,让它在您的运营中产生实际影响。

作者简介

'"`