Оптимизируйте стоимость развертывания моделей основы Amazon SageMaker JumpStart с помощью асинхронных конечных точек Amazon SageMaker

Оптимизируйте стоимость развертывания моделей Amazon SageMaker JumpStart с помощью асинхронных конечных точек SageMaker.

Успех применения генеративных приложений искусственного интеллекта во множестве отраслей привлек внимание и интерес компаний со всего мира, которые стремятся воспроизвести и превзойти достижения конкурентов или решить новые и увлекательные задачи. Эти клиенты изучают базовые модели, такие как TII Falcon, Stable Diffusion XL или GPT-3.5 от OpenAI, в качестве движков, обеспечивающих развитие генеративного искусственного интеллекта.

Базовые модели – это класс моделей генеративного искусственного интеллекта, способных понимать и генерировать контент, похожий на человеческий, благодаря огромным объемам неструктурированных данных, на которых они были обучены. Эти модели революционизировали различные задачи компьютерного зрения (CV) и обработки естественного языка (NLP), включая генерацию изображений, перевод и ответы на вопросы. Они служат строительными блоками для многих приложений искусственного интеллекта и стали неотъемлемым компонентом разработки передовых интеллектуальных систем.

Однако развертывание базовых моделей может сопровождаться значительными трудностями, особенно с точки зрения затрат и потребностей в ресурсах. Эти модели известны своими размерами, часто состоящими из сотен миллионов или даже миллиардов параметров. Их большой размер требует обширных вычислительных ресурсов, включая мощное оборудование и значительную память. Фактически, развертывание базовых моделей обычно требует как минимум одну (а часто несколько) графических процессоров (GPU) для эффективной обработки вычислительной нагрузки. Например, модель TII Falcon-40B Instruct требует как минимум экземпляр ml.g5.12xlarge для успешной загрузки в память, но работает лучше с более крупными экземплярами. В результате возврат на инвестиции (ROI) при развертывании и поддержке этих моделей может быть слишком низким для подтверждения бизнес-ценности, особенно во время циклов разработки или при работе с периодическими нагрузками. Это связано с расходами на работу экземпляров, оснащенных графическими процессорами, в течение длительных сеансов, потенциально 24/7.

В начале этого года мы объявили о Amazon Bedrock, серверном API для доступа к базовым моделям от Amazon и наших партнеров по генеративному искусственному интеллекту. Хотя он находится в режиме частного превью, его серверное API позволяет использовать базовые модели от Amazon, Anthropic, Stability AI и AI21, не развертывая собственные точки доступа. Однако модели с открытым исходным кодом от сообществ, таких как Hugging Face, стали набирать обороты, и не все они были доступны через Amazon Bedrock.

В этом посте мы рассматриваем эти ситуации и решаем проблему высоких затрат на развертывание больших базовых моделей на асинхронные точки входа Amazon SageMaker с помощью Amazon SageMaker JumpStart. Это может помочь сократить затраты на архитектуру, позволяя точке входа работать только тогда, когда запросы находятся в очереди и имеют небольшой срок жизни, а также масштабироваться до нуля, когда нет запросов, ожидающих обслуживания. Это звучит замечательно для многих случаев использования, однако точка входа, масштабированная до нуля, будет иметь время холодного старта перед возможностью предоставления выводов.

Обзор решения

Следующая диаграмма иллюстрирует архитектуру нашего решения.

Развертываемая нами архитектура очень проста:

  • Пользовательский интерфейс представляет собой блокнот, который может быть заменен веб-интерфейсом, созданным на основе Streamlit или подобной технологии. В нашем случае блокнот является блокнотом Amazon SageMaker Studio, работающим на экземпляре ml.m5.large с ядром PyTorch 2.0 Python 3.10 CPU.
  • Блокнот запрашивает точку входа тремя способами: SageMaker Python SDK, AWS SDK для Python (Boto3) и LangChain.
  • Точка входа работает асинхронно на SageMaker, и на точке входа мы развертываем модель Falcon-40B Instruct. В настоящее время она является передовой моделью в области инструкций и доступна в SageMaker JumpStart. Одним API-вызовом мы можем развернуть модель на точке входа.

Что такое асинхронное вывод SageMaker

Асинхронный вывод SageMaker является одним из четырех вариантов развертывания в SageMaker, наряду с реальными точками входа, пакетным выводом и бессерверным выводом. Чтобы узнать больше о различных вариантах развертывания, см. Развертывание моделей для вывода.

Асинхронный вывод SageMaker ставит в очередь входящие запросы и обрабатывает их асинхронно, что делает этот вариант идеальным для запросов с большим размером полезной нагрузки до 1 ГБ, длительным временем обработки и требованиями к практически реальному времени отклика. Однако основное преимущество, которое он предоставляет при работе с большими базовыми моделями, особенно во время создания концепции (POC) или во время разработки, заключается в возможности настройки асинхронного вывода для автоматического масштабирования числа экземпляров до нуля, когда нет запросов для обработки, что позволяет сэкономить затраты. Дополнительную информацию о асинхронном выводе SageMaker см. В разделе Асинхронный вывод. Ниже приведена иллюстрация этой архитектуры.

Для развертывания асинхронного эндпоинта необходимо создать объект AsyncInferenceConfig. Если вы создаете AsyncInferenceConfig без указания его аргументов, значение по умолчанию для S3OutputPath будет s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-outputs/{UNIQUE-JOB-NAME}, а для S3FailurePath будет s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-failures/{UNIQUE-JOB-NAME}.

Что такое SageMaker JumpStart

Наша модель поставляется из SageMaker JumpStart – функции SageMaker, которая ускоряет процесс обучения машинного обучения (ML), предлагая предварительно обученные модели, шаблоны решений и примеры блокнотов. Он предоставляет доступ к широкому спектру предварительно обученных моделей для разных типов задач, позволяя вам начать выполнение своих задач ML на прочной основе. SageMaker JumpStart также предлагает шаблоны решений для распространенных случаев использования и примеры блокнотов для обучения. С помощью SageMaker JumpStart вы можете сократить время и усилия, необходимые для начала выполнения ваших проектов ML, благодаря запуску решения в один клик и обширным ресурсам для практического опыта ML.

На следующем снимке экрана показан пример лишь некоторых моделей, доступных в пользовательском интерфейсе SageMaker JumpStart.

Развернуть модель

На первом этапе мы развертываем модель в SageMaker. Для этого мы можем использовать пользовательский интерфейс SageMaker JumpStart или SageMaker Python SDK, который предоставляет API, которое можно использовать для развертывания модели на асинхронном эндпоинте:

%%time
from sagemaker.jumpstart.model import JumpStartModel, AsyncInferenceConfig
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer

model_id, model_version = "huggingface-llm-falcon-40b-instruct-bf16", "*"
my_model = JumpStartModel(model_id=model_id)
predictor = my_model.deploy(
    initial_instance_count=0,
    instance_type="ml.g5.12xlarge",
    async_inference_config=AsyncInferenceConfig()
)

Этот вызов может занять примерно 10 минут. В этот период времени запускается эндпоинт, контейнер вместе с артефактами модели загружается на эндпоинт, конфигурация модели загружается из SageMaker JumpStart, затем асинхронный эндпоинт выставляется через DNS-эндпоинт. Чтобы убедиться, что наш эндпоинт может масштабироваться до нуля, мы должны настроить автомасштабирование на асинхронном эндпоинте с помощью Application Auto Scaling. Вам необходимо сначала зарегистрировать вариант вашего эндпоинта с Application Auto Scaling, задать масштабируемую политику, а затем применить политику масштабирования. В этой конфигурации мы используем пользовательскую метрику с помощью CustomizedMetricSpecification, называемую ApproximateBacklogSizePerInstance, как показано в следующем коде. Для подробного списка метрик Amazon CloudWatch, доступных для вашего асинхронного эндпоинта вывода, обратитесь к разделу “Мониторинг с помощью CloudWatch”.

import boto3

client = boto3.client("application-autoscaling")
resource_id = "endpoint/" + my_model.endpoint_name + "/variant/" + "AllTraffic"

# Настройка автомасштабирования на асинхронном эндпоинте до нулевого количества экземпляров
response = client.register_scalable_target(
    ServiceNamespace="sagemaker",
    ResourceId=resource_id,
    ScalableDimension="sagemaker:variant:DesiredInstanceCount",
    MinCapacity=0, # Минимальное количество экземпляров, до которого мы хотим масштабироваться - масштабирование до 0 для прекращения расходов
    MaxCapacity=1, # Максимальное количество экземпляров, до которого мы хотим масштабироваться - масштабирование до 1 максимума достаточно для разработки
)

response = client.put_scaling_policy(
    PolicyName="Invocations-ScalingPolicy",
    ServiceNamespace="sagemaker",  # Пространство имен AWS-службы, предоставляющей ресурс.
    ResourceId=resource_id,  # Имя эндпоинта
    ScalableDimension="sagemaker:variant:DesiredInstanceCount",  # SageMaker поддерживает только количество экземпляров
    PolicyType="TargetTrackingScaling",  # 'StepScaling'|'TargetTrackingScaling'
    TargetTrackingScalingPolicyConfiguration={
        "TargetValue": 5.0,  # Целевое значение для метрики - здесь метрика - SageMakerVariantInvocationsPerInstance
        "CustomizedMetricSpecification": {
            "MetricName": "ApproximateBacklogSizePerInstance",
            "Namespace": "AWS/SageMaker",
            "Dimensions": [{"Name": "EndpointName", "Value": my_model.endpoint_name}],
            "Statistic": "Average",
        },
        "ScaleInCooldown": 600,  # Количество времени, в секундах, после завершения операции масштабирования вниз, перед тем как может начаться другая операция масштабирования вниз.
        "ScaleOutCooldown": 300,  # ScaleOutCooldown - Количество времени, в секундах, после завершения операции масштабирования вверх, перед тем как может начаться другая операция масштабирования вверх.
        # 'DisableScaleIn': True|False - указывает, отключено ли масштабирование вниз политикой отслеживания целевой нагрузки.
        # Если значение true, масштабирование вниз отключено и политика отслеживания целевой нагрузки не будет удалять ресурсы масштабируемого ресурса.
    },
)

Вы можете проверить, что этот политика была успешно установлена, перейдя в консоль SageMaker, выбрав Endpoints в разделе Inference в левой панели навигации и ища развернутый только что конечной точки.

Вызовите асинхронную конечную точку

Для вызова конечной точки вам необходимо разместить полезную нагрузку запроса в Amazon Simple Storage Service (Amazon S3) и предоставить указатель на эту полезную нагрузку как часть запроса InvokeEndpointAsync. При вызове SageMaker ставит запрос в очередь на обработку и возвращает идентификатор и местоположение вывода в качестве ответа. После обработки SageMaker помещает результат в местоположение Amazon S3. Вы также можете выбрать опциональное получение уведомлений об успехе или ошибке с помощью Amazon Simple Notification Service (Amazon SNS).

SageMaker Python SDK

После завершения развертывания он возвращает объект AsyncPredictor. Чтобы выполнить асинхронное вывод, вам необходимо загрузить данные в Amazon S3 и использовать метод predict_async() с URI S3 в качестве входных данных. Он вернет объект AsyncInferenceResponse, и вы можете проверить результат с помощью метода get_response().

Кроме того, если вы хотите периодически проверять результат и возвращать его после генерации, используйте метод predict(). Мы используем этот второй метод в следующем коде:

import time

# Вызов асинхронной конечной точки с помощью SageMaker Python SDK
def query_endpoint(payload):
    """Запрос конечной точки и печать ответа"""
    response = predictor.predict_async(
        data=payload,
        input_path="s3://{}/{}".format(bucket, prefix),
    )
    while True:
        try:
            response = response.get_result()
            break
        except:
            print("Вывод еще не готов ...")
            time.sleep(5)
    print(f"\033[1m Вход:\033[0m {payload['inputs']}")
    print(f"\033[1m Вывод:\033[0m {response[0]['generated_text']}")
    
query_endpoint(payload)

Boto3

Теперь давайте рассмотрим метод invoke_endpoint_async из клиента sagemaker-runtime Boto3. Он позволяет разработчикам асинхронно вызывать конечную точку SageMaker, предоставляя токен для отслеживания прогресса и получения ответа позже. Boto3 не предлагает способ ожидания завершения асинхронного вывода, как это делает операция get_result() SageMaker Python SDK. Поэтому мы воспользуемся тем, что Boto3 будет сохранять результат вывода в Amazon S3 в response["OutputLocation"]. Мы можем использовать следующую функцию для ожидания записи файла вывода в Amazon S3:

import json
import time
import boto3
from botocore.exceptions import ClientError

s3_client = boto3.client("s3")

# Ожидание генерации прогноза
def wait_inference_file(bucket, prefix):
    while True:
        try:
            response = s3_client.get_object(Bucket=bucket, Key=prefix)
            break
        except ClientError as ex:
            if ex.response['Error']['Code'] == 'NoSuchKey':
                print("Ожидание генерации файла...")
                time.sleep(5)
                next
            else:
                raise
        except Exception as e:
            print(e.__dict__)
            raise
    return response

Теперь с помощью этой функции мы можем запросить конечную точку:

# Вызов асинхронной конечной точки с помощью Boto3 SDK
import boto3

sagemaker_client = boto3.client("sagemaker-runtime")

# Функция запроса конечной точки
def query_endpoint_boto3(payload):
    """Запрос конечной точки и печать ответа"""
    response = sagemaker_client.invoke_endpoint_async(
        EndpointName=my_model.endpoint_name,
        InputLocation="s3://{}/{}".format(bucket, prefix),
        ContentType="application/json",
        Accept="application/json"
    )
    output_url = response["OutputLocation"]
    output_prefix = "/".join(output_url.split("/")[3:])
    # Чтение байтов файла из S3 по output_url с помощью Boto3
    output = wait_inference_file(bucket, output_prefix)
    output = json.loads(output['Body'].read())[0]['generated_text']
    # Вывод результата
    print(f"\033[1m Вход:\033[0m {payload['inputs']}")
    print(f"\033[1m Вывод:\033[0m {output}")

query_endpoint_boto3(payload)

LangChain

LangChain – это открытая платформа, запущенная в октябре 2022 года Харрисоном Чейзом. Она упрощает разработку приложений с использованием больших языковых моделей (LLM), предоставляя интеграции с различными системами и источниками данных. LangChain позволяет производить анализ документов, суммирование, создание чат-ботов, анализ кода и многое другое. Он стал популярным благодаря вкладам сотен разработчиков и значительному финансированию от венчурных фирм. LangChain позволяет подключать внешние источники к LLM, что позволяет создавать динамические приложения, реагирующие на данные. Он предлагает библиотеки, API и документацию для упрощения процесса разработки.

LangChain предоставляет библиотеки и примеры для использования точек доступа SageMaker с его фреймворком, что упрощает использование моделей машинного обучения, размещенных на SageMaker, в качестве “мозга” цепи. Чтобы узнать больше о том, как LangChain интегрируется с SageMaker, ознакомьтесь с разделом “Точка доступа SageMaker” в документации LangChain.

Одним из ограничений текущей реализации LangChain является то, что он не поддерживает асинхронные точки доступа изначально. Чтобы использовать асинхронную точку доступа в LangChain, нам нужно определить новый класс SagemakerAsyncEndpoint, который расширяет уже доступный в LangChain класс SagemakerEndpoint. Дополнительно мы предоставляем следующую информацию:

  • Имя S3-ведра и префикс, где асинхронное вывод будет сохранять вводы (и выводы)
  • Максимальное количество секунд ожидания до истечения времени ожидания
  • Функцию updated _call() для запроса к точке доступа с помощью invoke_endpoint_async() вместо invoke_endpoint()
  • Способ пробуждения асинхронной точки доступа, если она находится в холодном запуске (масштабирование до нуля)

Чтобы ознакомиться с только что созданным классом SagemakerAsyncEndpoint, вы можете проверить файл sagemaker_async_endpoint.py, доступный на GitHub.

from typing import Dict
from langchain import PromptTemplate
from langchain.llms.sagemaker_endpoint import LLMContentHandler
from langchain.chains import LLMChain
from sagemaker_async_endpoint import SagemakerAsyncEndpoint

class ContentHandler(LLMContentHandler):
    content_type:str = "application/json"
    accepts:str = "application/json"
    len_prompt:int = 0

    def transform_input(self, prompt: str, model_kwargs: Dict) -> bytes:
        self.len_prompt = len(prompt)
        input_str = json.dumps({"inputs": prompt, "parameters": {"max_new_tokens": 100, "do_sample": False, "repetition_penalty": 1.1}})
        return input_str.encode('utf-8')

    def transform_output(self, output: bytes) -> str:
        response_json = output.read()
        res = json.loads(response_json)
        ans = res[0]['generated_text']
        return ans

chain = LLMChain(
    llm=SagemakerAsyncEndpoint(
        input_bucket=bucket,
        input_prefix=prefix,
        endpoint_name=my_model.endpoint_name,
        region_name=sagemaker.Session().boto_region_name,
        content_handler=ContentHandler(),
    ),
    prompt=PromptTemplate(
        input_variables=["query"],
        template="{query}",
    ),
)

print(chain.run(payload['inputs']))

Очистка

Когда вы закончите тестирование генерации выводов из точки доступа, не забудьте удалить точку доступа, чтобы избежать дополнительных расходов:

predictor.delete_endpoint()

Заключение

При развертывании больших моделей основы, таких как TII Falcon, важно оптимизировать затраты. Эти модели требуют мощного оборудования и значительной памяти, что приводит к высоким инфраструктурным затратам. Асинхронная инференция SageMaker, опция развертывания, которая обрабатывает запросы асинхронно, снижает расходы путем масштабирования количества экземпляров до нуля, когда нет ожидающих запросов. В этой статье мы продемонстрировали, как развернуть большие модели основы SageMaker JumpStart на асинхронных точках доступа SageMaker. Мы предоставили примеры кода, используя SageMaker Python SDK, Boto3 и LangChain, чтобы проиллюстрировать различные методы вызова асинхронных точек доступа и получения результатов. Эти техники позволяют разработчикам и исследователям оптимизировать затраты при использовании возможностей моделей основы для систем понимания языка.

Чтобы узнать больше о асинхронной инференции и SageMaker JumpStart, ознакомьтесь с следующими статьями:

  • Быстрое создание приложений, обладающих высокой точностью генеративного искусственного интеллекта на основе предприятий с использованием Amazon Kendra, LangChain и больших языковых моделей
  • Выполнение вывода компьютерного зрения на больших видео с использованием асинхронных точек доступа Amazon SageMaker