Presta y solicita recursos entre equipos con la administración de cuotas de AWS Batch para trabajos de entrenamiento de SageMaker
Lend and borrow resources across teams with AWS Batch’s quota management for SageMaker Training jobs
Michelle Goodstein
Con el lanzamiento del soporte de AWS Batch para trabajos de entrenamiento de Amazon SageMaker, los clientes obtuvieron una nueva forma completamente administrada de poner en cola, programar y reintentar cargas de trabajo de entrenamiento de aprendizaje automático (ML) sin tener que construir su propia infraestructura. En su lugar, utilizan las características de cola y programación de AWS Batch. A medida que las organizaciones escalan sus operaciones de inteligencia artificial y aprendizaje automático (AI/ML) y contratan a más equipos, coordinar el acceso a la capacidad compartida de procesamiento gráfico (GPU) puede introducir sobrecarga adicional de comunicación, coordinación y configuración para los administradores. Esta sobrecarga incluye la configuración de colas separadas, el ajuste de los límites de capacidad y la orquestación cuidadosa de las cargas de trabajo adecuadas para obtener los recursos adecuados en el momento adecuado. Un valor central de la propuesta de AWS Batch es ayudar a los clientes a aumentar la utilización de su capacidad de cómputo, y a medida que crecen los entornos de entrenamiento, también lo hace la oportunidad de hacer más con la capacidad existente.
Trabajando hacia atrás desde los clientes que administran entornos de entrenamiento multi-equipo, escuchamos una solicitud consistente: dános una forma de definir asignaciones por equipo o proyecto, compartir la capacidad inactiva automáticamente y ejecutar nuestras cargas de trabajo de mayor prioridad primero. Esta solicitud nos llevó a construir administración de cuotas, una nueva capacidad de programación para AWS Batch. Los administradores pueden utilizarla para dividir la capacidad de cómputo en acciones de cuota, organizadas por equipo, proyecto o carga de trabajo. Cada acción de cuota utiliza estrategias de compartición de recursos configurables que maximizan la utilización de GPU mientras honran la asignación de cada equipo cuando más importa.
Esta publicación muestra cómo funciona la administración de cuotas, incluyendo cómo configurar acciones de cuota con estrategias de préstamo y préstamo, configurar la preemption dentro de la acción para cargas de trabajo de prioridad y comenzar a usar el SDK de Python de SageMaker.
Acciones de cuota y preemption
Los administradores pueden asignar y compartir recursos de GPU limitados definiendo una acción de cuota para entidades separadas, como equipos o proyectos individuales. Cada acción de cuota incluye cuotas de cómputo (límites de capacidad) y estrategias de compartición de recursos para cómputo inactivo. Estas estrategias determinan si el cómputo inactivo se reserva hasta que lleguen los trabajos (RESERVE), se presta a otras acciones de cuota que tienen trabajo disponible (LEND), o se presta cuando está inactivo y se solicita cuando la acción tiene trabajo que podría beneficiarse (LEND_AND_BORROW).
Una cuota compartida opera como una cola virtual anidada jerárquicamente dentro de una cola de trabajos asociada. Al programar trabajos para una cola de trabajos, AWS Batch prioriza las cuotas compartidas que están bajo sus límites de capacidad a medida que itera a través de las cuotas compartidas asociadas. Si los trabajos llegan a una cuota compartida que ha prestado su capacidad, AWS Batch realiza una preemption entre cuotas compartidas. Esto recupera recursos para la cuota compartida prestamista, por lo que los administradores no necesitan rastrear los trabajos que prestan capacidad y terminarlos por su cuenta. Si los trabajos llegan a una cuota compartida que está en o por encima de su límite de capacidad, AWS Batch verifica si hay capacidad disponible para prestar de otra cuota compartida. Si es así, las cargas de trabajo pueden ejecutarse utilizando la capacidad que de otro modo estaría inactiva.
Puede activar la preemption basada en prioridad dentro de una cuota compartida cuando configure una cuota compartida. Donde la preemption entre cuotas compartidas recupera la capacidad prestada a medida que llegan trabajos a una cuota compartida prestamista, la preemption dentro de una cuota compartida anula los trabajos de prioridad inferior que están en el estado PROGRAMADO, INICIANDO o EJECUTANDO. Esto permite que los trabajos de prioridad más alta al frente de la cola comiencen a ejecutarse antes.
Requisitos previos
Antes de continuar con este ejemplo, debe tener una cuenta de AWS con permisos para crear y administrar recursos de AWS Batch. Para este ejemplo, consulte los permisos de IAM de ejemplo necesarios para invocar las API de AWS Batch y SageMaker.
El ejemplo utiliza el SDK de Python de SageMaker v3. Complete la configuración necesaria para instalar una versión compatible del SDK de Python de SageMaker:
!pip install sagemaker
Configuración de recursos de administración de cuotas
Usar las nuevas capacidades de administración de cuotas requiere crear una Scheduling Policy que contiene un quotaSharePolicy, un Service Environment que especifica sus límites de capacidad en términos de instancias específicas, y una cola de trabajos de entrenamiento de SageMaker que está conectada a ambos. Después de eso, puede asociar acciones de cuota a una cola de trabajos. La guía del usuario tiene ejemplos de AWS Command Line Interface (AWS CLI) y consola para configurar recursos de administración de cuotas y acciones de cuota. Un ejemplo de extremo a extremo de administración de cuotas integrada con el módulo aws_batch en el SDK de Python de SageMaker v3 se contiene en una libreta de ejemplo. En este ejemplo, pasamos por fragmentos de código que resumen los componentes clave y usamos las funciones de ayuda de la libreta para crear una Scheduling Policy, Service Environment, Job Queue y tres Acciones de Cuota.
Las tres acciones de cuota configuradas aquí representan tres proyectos diferentes. Cada una tiene el mismo límite de capacidad establecido: una sola instancia ml.g5.xlarge. La acción de cuota QS1 representa trabajos en segundo plano. Para este proyecto, desea ejecutar el trabajo en segundo plano más importante primero y tomar tantas capacidades de repuesto como estén disponibles. Dentro de esta acción de cuota, no hay trabajos urgentes y las preempciones son aceptables porque todos los trabajos utilizan puntos de control. Esta acción de cuota utiliza la estrategia de LEND_AND_BORROW de compartición de recursos y tiene la preempción dentro de la acción de cuota activada. Los trabajos de mayor prioridad dentro de la misma acción de cuota pueden entonces preemptions a los trabajos en ejecución que tienen menor prioridad.
QS2 representa cargas de trabajo de prioridad media. Los equipos que eligen esta configuración prefieren esperar a que se disponga de capacidad en lugar de soportar preemptions adicionales. Esas preemptions provienen de la capacidad prestada que se reclama o de preemptions dentro de la participación debido a la presentación de trabajos de prioridad más alta. Esto es adecuado para trabajos más cortos, o cuando la mayoría de los trabajos presentados tienen prioridades similares. La participación de cuota aún se beneficia de que se tenga en cuenta la prioridad del trabajo en el momento del despacho del trabajo. Los trabajos presentados desencadenan que AWS Batch recupere cualquier capacidad prestada necesaria para ejecutar los trabajos.
QS3 representa cargas de trabajo que necesitan iniciarse lo más rápido posible con mínimas interrupciones. Está configurado para reservar capacidad y no prestar ni tomar prestada capacidad a otras participaciones de cuota. No experimenta preemptions entre participaciones, porque sus cargas de trabajo no exceden los límites de capacidad. Al desactivar también la preemption dentro de la participación, las cargas de trabajo presentadas a esta participación de cuota no son interrumpidas por AWS Batch siempre y cuando el límite de capacidad no cambie.
Estas configuraciones de participación de cuota son entradas para la función create_quota_management_resources en la libreta de muestra, que también configura la política de programación, el entorno de servicio y la cola de trabajos correspondientes con los nombres constantes elegidos.
Presentar trabajos de entrenamiento de SageMaker a QS1
El módulo aws_batch dentro del SDK de Python de SageMaker se ha extendido para permitir la presentación programática de trabajos de entrenamiento de SageMaker a una cola de trabajos de AWS Batch habilitada para la administración de cuotas. Para demostrar estas nuevas capacidades, usamos un ejemplo de entrenador de modelo de "hola mundo" ModelTrainer que se presenta a la cola de trabajos. El siguiente fragmento de código identifica una URI de imagen para usar en función de la región y el tipo de instancia seleccionados.
Para usar la cola de trabajos dentro del SDK de Python de SageMaker, proporcione el nombre de la cola al constructor TrainingQueue dentro del módulo aws_batch.
from sagemaker.train.aws_batch.training_queue import TrainingQueue, TrainingQueuedJob
# Construct the queue object using the SageMaker Python SDK
queue = TrainingQueue(JOB_QUEUE_NAME)
logger.info(f"Using queue: {queue.queue_name}")
Podemos enviar tres trabajos a QS1, nuestra cuota de compartición de trabajos en segundo plano. El primer trabajo enviado tiene la mayor prioridad, seguido del trabajo de prioridad media y luego del trabajo de prioridad más baja. Como actualmente no se está ejecutando nada en QS1 o QS2, deberían iniciarse dos instancias de trabajos, correspondientes al primer y segundo trabajo enviado (ya que tenían la prioridad relativa más alta). Tenga en cuenta que, como este es solo un trabajo de entrenamiento de "hola mundo", no requiere datos, pero normalmente un ModelTrainer requiere datos para realizar el entrenamiento.
from utils.aws_batch_resource_management import JobStatus, await_jobs, list_jobs_by_quota_share
# Submit three jobs to QS1, all with different priorities to guarantee dispatch ordering.
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 is dispatched first using capacity from QS1, and qs1_job_med is dispatched second borrowing idle capacity from 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())
Enviar trabajos a QS2 desencadena la preemption entre comparticiones para recuperar capacidad prestada
El equipo que posee QS2 puede descubrir que tiene trabajo por realizar y enviar un trabajo a QS2. Al hacerlo, se desencadena una preemption de capacidad desde QS1, que actualmente está prestando esa capacidad (la capacidad de QS3 no está configurada para ser prestada). Esto es una preemption entre comparticiones.
# When a job is submitted to QS2, it will preempt its capacity back from 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}) # Lowest priority QS1 job will be preempted
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())
Actualizar prioridades de trabajos en QS1 desencadena la preemption dentro de la compartición para ejecutar trabajos de mayor prioridad
Si un científico se da cuenta de que el trabajo qs1_job_low en QS1, que todavía es EJECUTABLE, necesita comenzar a ejecutarse ahora debido a los cambios de prioridad, puede utilizar la nueva API UpdateServiceJob para aumentar la prioridad de un trabajo ya enviado en QS1. Como no hay capacidad disponible para prestar, esto inicia una preemption dentro de la compartición, para que el trabajo que se está ejecutando actualmente sea interrumpido y qs1_job_low pueda comenzar.
# Updating qs1_job_low to be the highest priority job in 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...")
await_jobs([
([qs1_job_low], JobStatus.dispatched() | JobStatus.terminal()),
([qs1_job_high], {JobStatus.RUNNABLE}) # High priority job will preempt lower priority jobs within the same quota share
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())
(Opcional) Limpiar recursos creados
Para limpiar los recursos creados en esta publicación, ejecute el siguiente código:
from utils.aws_batch_resource_management import delete_resources
delete_resources(resource_manager, resources)
Conclusión
En esta publicación, cubrimos la administración de cuotas, una nueva capacidad de programación en AWS Batch, y cómo utilizarla con trabajos de entrenamiento de SageMaker y comenzar a configurar comparticiones de cuotas para sus propios proyectos. Para obtener más detalles, consulte la guía de usuario de administración de cuotas de AWS Batch.
AWS Batch con gestión de cuotas puede ayudar a su organización a aumentar la utilización de cómputo y a priorizar de manera más efectiva a sus equipos y cargas de trabajo, liberando tiempo para sus administradores de infraestructura y científicos de ML. Al implementar la gestión de cuotas, sus equipos pueden centrarse en sus cargas de trabajo y reducir el tiempo dedicado a la gestión y coordinación de infraestructura. Esta capacidad es especialmente poderosa con los planes de entrenamiento de AI de Amazon SageMaker, para que su organización pueda reservar capacidad en la cantidad que necesite, durante el tiempo que la necesite. Al utilizar AWS Batch con SageMaker AI, puede aprovechar al máximo el plan de entrenamiento. Le animamos a probar esta nueva capacidad para que tenga un impacto significativo en sus operaciones.
Sobre los autores
With the launch of AWS Batch support for Amazon SageMaker Training jobs, customers gained a new fully managed way to queue, schedule, and retry machine learning (ML) training workloads without building their own infrastructure. Instead, they use the queuing and scheduling features of AWS Batch. As organizations scale their artificial intelligence and machine learning (AI/ML) operations and onboard more teams, coordinating access to shared graphics processing unit (GPU) capacity can introduce additional communication, coordination, and configuration overhead for administrators. This overhead includes setting up separate queues, adjusting capacity limits, and carefully orchestrating the right workloads to get the right resources at the right time. A core value proposition of AWS Batch is helping customers increase utilization of their compute, and as training environments grow, so does the opportunity to do more with existing capacity.
Working backward from customers managing multi-team training environments, we heard a consistent request: give us a way to define allocations per team or project, share idle capacity automatically, and run our highest-priority workloads first. This request led us to build quota management, a new scheduling capability for AWS Batch. Administrators can use it to divide compute capacity into quota shares, organized by team, project, or workload. Each quota share uses configurable resource-sharing strategies that maximize GPU utilization while honoring each team’s allocation when it matters most.
This post shows how quota management works, including how to configure quota shares with lending and borrowing strategies, set up in-share preemption for priority workloads, and get started using the SageMaker Python SDK.
Quota shares and preemption
Administrators can allocate and share constrained GPU resources by defining a quota share for separate entities, such as individual teams or projects. Each quota share includes compute quotas (capacity limits) and resource-sharing strategies for idle compute. These strategies determine whether idle compute is reserved until jobs arrive (RESERVE), lent to other quota shares that have work available (LEND), or both lent when idle and borrowed when the share has work that might benefit (LEND_AND_BORROW).
A quota share operates as a virtual queue nested hierarchically within an associated job queue. When scheduling jobs for a job queue, AWS Batch prioritizes quota shares that are under their capacity limits as it iterates through the associated quota shares. If jobs arrive in a quota share that has lent out its capacity, AWS Batch performs cross-share preemption. This reclaims resources for the lending quota share, so administrators don’t need to track down the jobs borrowing capacity and terminate them on their own. If jobs arrive in a quota share that is at or above its capacity limit, AWS Batch checks whether there’s available capacity to borrow from another quota share. If so, workloads can run using otherwise-idle capacity.
You can turn on priority-based in-share preemption when you configure a quota share. Where cross-share preemption reclaims lent capacity as jobs arrive in a lending quota share, in-share preemption preempts lower priority jobs that are in the SCHEDULED, STARTING, or RUNNING state. This allows higher priority jobs at the front of the queue to start running sooner.
Prerequisites
Before you proceed with this example, you must have an AWS account with permissions to create and manage AWS Batch resources. For this example, see the sample IAM permissions needed to invoke AWS Batch and SageMaker APIs.
The example uses the SageMaker Python SDK v3. Complete the setup required to install a compatible version of the SageMaker Python SDK:
!pip install sagemaker
Configuring quota management resources
Using the new quota management capabilities requires creating a Scheduling Policy that contains a quotaSharePolicy, a Service Environment that specifies its capacity limits in terms of specific instances, and a SageMaker Training job queue that is connected to both. After that, you can associate quota shares to a job queue. The user guide has AWS Command Line Interface (AWS CLI) and console examples for configuring quota management resources and quota shares. An end-to-end example of quota management integrated with the aws_batch module in the SageMaker Python SDK v3 is contained in a sample notebook. In this example, we step through code snippets that summarize the key components, and use the helper functions from the notebook to create a Scheduling Policy, Service Environment, Job Queue, and three Quota Shares.
The three quota shares configured here represent three different projects. Each has the same capacity limit set: a single ml.g5.xlarge instance. The QS1 quota share represents background jobs. For this project, you want to run the most important background job first and borrow as much spare capacity as is available. Within this quota share, no jobs are urgent, and preemptions are acceptable because all jobs use checkpointing. This quota share uses the LEND_AND_BORROW resource-sharing strategy and has in-share preemption turned on. Higher priority jobs within the same quota share can then preempt running jobs that are lower priority.
QS2 represents medium priority workloads. Teams choosing this configuration would prefer to wait for capacity to become available rather than endure additional preemptions. Those preemptions come from borrowed capacity being reclaimed or from in-share preemptions because of higher priority job submission. This is appropriate for shorter jobs, or when most submitted jobs have similar priorities. The quota share still benefits from job priority being taken into consideration at job dispatch. Submitted jobs trigger AWS Batch to reclaim any lent capacity needed to run the jobs.
QS3 represents workloads that need to start as quickly as possible with minimal interruptions. It’s configured to reserve capacity and neither lends nor borrows to other quota shares. It doesn’t experience cross-share preemptions, because its workloads don’t exceed their capacity limits. By also turning off in-share preemption, workloads submitted to this quota share are not preempted by AWS Batch as long as the capacity limit is unchanged.
These quota share configurations are inputs to the create_quota_management_resources function in the sample notebook, which also configures the corresponding Scheduling Policy, Service Environment, and Job Queue with the constant names chosen.
The aws_batch module within the SageMaker Python SDK has been extended to allow programmatic submission of SageMaker Training jobs to a quota-management-enabled AWS Batch job queue. To demonstrate these new capabilities, we use a Hello World ModelTrainer that’s submitted to the job queue. The following code snippet identifies an image URI to use based on the Region and instance type selected.
To use the job queue within the SageMaker Python SDK, provide the queue name to the TrainingQueue constructor within the aws_batch module.
from sagemaker.train.aws_batch.training_queue import TrainingQueue, TrainingQueuedJob
# Construct the queue object using the SageMaker Python SDK
queue = TrainingQueue(JOB_QUEUE_NAME)
logger.info(f"Using queue: {queue.queue_name}")
We can then submit three jobs to QS1, our background jobs quota share. The first job submitted has the highest priority, followed by the medium priority job, and then the lowest priority job. As nothing is currently running in QS1 or QS2, two instances’ worth of jobs should start, corresponding to the first and second jobs submitted (as they had the highest relative priority). Note that because this is only a hello world training job, it doesn’t require data, but typically a ModelTrainer requires data to perform training.
from utils.aws_batch_resource_management import JobStatus, await_jobs, list_jobs_by_quota_share
# Submit three jobs to QS1, all with different priorities to guarantee dispatch ordering.
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 is dispatched first using capacity from QS1, and qs1_job_med is dispatched second borrowing idle capacity from 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())
Submitting jobs to QS2 triggers cross-share preemption to reclaim lent capacity
The team that owns QS2 might discover they have work to perform and submit a job to QS2. Doing so triggers a preemption of capacity back from QS1, which is currently borrowing that capacity (QS3’s capacity isn’t configured to be borrowed). This is a cross-share preemption.
# When a job is submitted to QS2, it will preempt its capacity back from 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}) # Lowest priority QS1 job will be preempted
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())
Updating job priorities in QS1 triggers in-share preemption to run highest priority jobs
If a scientist realizes that the qs1_job_low job in QS1, which is still RUNNABLE, needs to begin running now because of changing priorities, they can use the new UpdateServiceJob API to increase the priority of an already submitted job in QS1. Because there’s no available capacity to borrow, this kicks off an in-share preemption, so that the job currently running is preempted and qs1_job_low can begin.
# Updating qs1_job_low to be the highest priority job in 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...")
await_jobs([
([qs1_job_low], JobStatus.dispatched() | JobStatus.terminal()),
([qs1_job_high], {JobStatus.RUNNABLE}) # High priority job will preempt lower priority jobs within the same quota share
])
list_jobs_by_quota_share(queue, [qs1.name, qs2.name, qs3.name], JobStatus.active())
(Optional) Clean up created resources
To clean up the resources created in this post, run the following code:
from utils.aws_batch_resource_management import delete_resources
delete_resources(resource_manager, resources)
Conclusion
In this post, we covered quota management, a new scheduling capability in AWS Batch, and how to use it with SageMaker Training jobs and get started setting up quota shares for your own projects. For more details, see the AWS Batch quota management user guide.
AWS Batch with quota management can help your organization increase compute utilization and more effectively prioritize your teams and workloads, freeing up time for your infrastructure admins and ML scientists. By implementing quota management, your teams can focus on their workloads and reduce time spent managing and coordinating infrastructure. This capability is especially powerful with Amazon SageMaker AI training plans, so that your organization can reserve capacity in the quantity you need, during the time you need it. By using AWS Batch with SageMaker AI, you can make full use of the training plan. We encourage you to try out this new capability so it can make a meaningful impact in your operations.
About the authors
¿Tiene un proyecto de software o plataforma SaaS en mente?
Hable directamente con nuestros arquitectos de software en SoftAndino. Le brindamos asesoría técnica y cotización inmediata sin compromiso.