Рекомендации по нагрузочному тестированию конечных точек логического вывода Amazon SageMaker в реальном времени

Рекомендации по нагрузочному тестированию конечных точек логического вывода Amazon SageMaker в реальном времени

Исходный узел: 1889926

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

Инференс SageMaker в реальном времени идеально подходит для рабочих нагрузок, которые требуют интерактивных операций в реальном времени и малой задержки. С помощью логического вывода SageMaker в реальном времени вы можете развертывать конечные точки REST, которые поддерживаются экземпляром определенного типа с определенным объемом вычислений и памяти. Развертывание конечной точки SageMaker в реальном времени — это только первый шаг на пути к производству для многих клиентов. Мы хотим иметь возможность максимизировать производительность конечной точки для достижения целевого количества транзакций в секунду (TPS) при соблюдении требований к задержке. Большая часть оптимизации производительности для логического вывода заключается в том, чтобы убедиться, что вы выбрали правильный тип экземпляра и считаете, что поддерживаете конечную точку.

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

Сначала мы сравним производительность нашей модели на одном экземпляре, чтобы определить, сколько TPS она может обрабатывать в соответствии с нашими допустимыми требованиями к задержке. Затем мы экстраполируем результаты, чтобы решить, сколько экземпляров нам нужно для обработки нашего производственного трафика. Наконец, мы моделируем трафик производственного уровня и настраиваем нагрузочные тесты для конечной точки SageMaker в реальном времени, чтобы убедиться, что наша конечная точка может справиться с нагрузкой производственного уровня. Весь набор кода для примера доступен в следующем Репозиторий GitHub.

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

Для этого поста мы развертываем предварительно обученный Обнимающее лицо Модель DistilBERT из Обниматься Face Hub. Эта модель может выполнять ряд задач, но мы отправляем полезную нагрузку специально для анализа настроений и классификации текста. С этим образцом полезной нагрузки мы стремимся достичь 1000 TPS.

Развертывание конечной точки в реальном времени

В этом посте предполагается, что вы знакомы с тем, как развернуть модель. Ссылаться на Создайте свою конечную точку и разверните свою модель чтобы понять внутренности размещения конечной точки. На данный момент мы можем быстро указать на эту модель в Hugging Face Hub и развернуть конечную точку в реальном времени с помощью следующего фрагмента кода:

# Hub Model configuration. https://huggingface.co/models
hub = { 'HF_MODEL_ID':'distilbert-base-uncased', 'HF_TASK':'text-classification'
} # create Hugging Face Model Class
huggingface_model = HuggingFaceModel(
transformers_version='4.17.0',
pytorch_version='1.10.2',
py_version='py38',
env=hub,
role=role,
) # deploy model to SageMaker Inference
predictor = huggingface_model.deploy(
initial_instance_count=1, # number of instances
instance_type='ml.m5.12xlarge' # ec2 instance type
)

Давайте быстро протестируем нашу конечную точку с образцом полезной нагрузки, которую мы хотим использовать для нагрузочного тестирования:


import boto3
import json
client = boto3.client('sagemaker-runtime')
content_type = "application/json"
request_body = {'inputs': "I am super happy right now."}
data = json.loads(json.dumps(request_body))
payload = json.dumps(data)
response = client.invoke_endpoint(
EndpointName=predictor.endpoint_name,
ContentType=content_type,
Body=payload)
result = response['Body'].read()
result

Обратите внимание, что мы поддерживаем конечную точку, используя один Эластичное вычислительное облако Amazon (Amazon EC2) экземпляр типа ml.m5.12xlarge, который содержит 48 виртуальных ЦП и 192 ГиБ памяти. Количество виртуальных ЦП является хорошим показателем параллелизма, который может поддерживать экземпляр. Как правило, рекомендуется протестировать различные типы экземпляров, чтобы убедиться, что у нас есть экземпляр с правильно используемыми ресурсами. Полный список экземпляров SageMaker и соответствующих им вычислительных мощностей для логического вывода в реальном времени см. Цены на Amazon SageMaker.

Метрики для отслеживания

Прежде чем мы приступим к нагрузочному тестированию, важно понять, какие показатели отслеживать, чтобы понять разбивку производительности вашей конечной точки SageMaker. CloudWatch — это основной инструмент ведения журналов, который SageMaker использует для понимания различных показателей, описывающих производительность вашей конечной точки. Вы можете использовать журналы CloudWatch для отладки вызовов конечных точек; здесь собраны все операторы регистрации и печати, которые есть в вашем коде вывода. Для получения дополнительной информации см. Как работает Amazon CloudWatch.

Существует два разных типа метрик, которые CloudWatch охватывает для SageMaker: метрики уровня экземпляра и метрики вызовов.

Метрики на уровне экземпляра

Первый набор параметров, которые следует учитывать, — это метрики уровня экземпляра: CPUUtilization и MemoryUtilization (для экземпляров на базе GPU, GPUUtilization). Для CPUUtilization, сначала в CloudWatch вы можете увидеть проценты выше 100 %. Важно осознавать для CPUUtilization, отображается сумма всех ядер ЦП. Например, если экземпляр за вашей конечной точкой содержит 4 виртуальных ЦП, это означает, что диапазон использования составляет до 400 %. MemoryUtilization, с другой стороны, находится в диапазоне 0–100%.

В частности, вы можете использовать CPUUtilization чтобы получить более глубокое представление о том, есть ли у вас достаточное или даже избыточное количество оборудования. Если у вас есть малоиспользуемый инстанс (менее 30%), вы потенциально можете уменьшить масштаб своего типа инстанса. И наоборот, если вы используете около 80–90%, было бы лучше выбрать инстанс с большей вычислительной мощностью/памятью. Из наших тестов мы предполагаем, что использование вашего оборудования составляет около 60–70%.

Метрики вызова

Как следует из названия, метрики вызовов — это место, где мы можем отслеживать сквозную задержку любых вызовов к вашей конечной точке. Вы можете использовать метрики вызовов для регистрации количества ошибок и типов ошибок (5xx, 4xx и т. д.), с которыми может столкнуться ваша конечная точка. Что еще более важно, вы можете понять разбивку задержек ваших вызовов конечной точки. Многое из этого можно зафиксировать с помощью ModelLatency и OverheadLatency метрики, как показано на следующей диаграмме.

Задержки

Ассоциация ModelLatency метрика фиксирует время, которое занимает вывод в контейнере модели за конечной точкой SageMaker. Обратите внимание, что контейнер модели также включает любой пользовательский код вывода или сценарии, которые вы передали для вывода. Эта единица фиксируется в микросекундах в качестве метрики вызова, и обычно вы можете графически отображать процентиль по CloudWatch (p99, p90 и т. д.), чтобы увидеть, соответствуете ли вы целевой задержке. Обратите внимание, что на задержку модели и контейнера могут повлиять несколько факторов, например следующие:

  • Пользовательский сценарий вывода – Независимо от того, реализовали ли вы свой собственный контейнер или использовали контейнер на основе SageMaker с настраиваемыми обработчиками вывода, рекомендуется профилировать ваш скрипт, чтобы отлавливать любые операции, которые специально увеличивают вашу задержку.
  • Протокол связи – Рассмотрите возможность подключения REST и gRPC к серверу модели в контейнере модели.
  • Оптимизация каркаса модели – Это специфично для фреймворка, например, с TensorFlow, существует ряд переменных среды, которые вы можете настроить для TF Serving. Обязательно проверьте, какой контейнер вы используете, и есть ли какие-либо оптимизации для конкретной платформы, которые вы можете добавить в скрипт или в качестве переменных среды для внедрения в контейнер.

OverheadLatency измеряется с момента, когда SageMaker получает запрос, до момента, когда он возвращает ответ клиенту, за вычетом задержки модели. Эта часть в значительной степени находится вне вашего контроля и подпадает под действие накладных расходов SageMaker.

Сквозная задержка в целом зависит от множества факторов и не обязательно является суммой ModelLatency плюс OverheadLatency. Например, если ваш клиент делает InvokeEndpoint Вызов API через Интернет, с точки зрения клиента, сквозная задержка будет Интернет + ModelLatency + OverheadLatency. Таким образом, при нагрузочном тестировании вашей конечной точки, чтобы точно оценить саму конечную точку, рекомендуется сосредоточиться на метриках конечной точки (ModelLatency, OverheadLatencyкачества InvocationsPerInstance) для точного сравнения конечной точки SageMaker. Любые проблемы, связанные со сквозной задержкой, могут быть изолированы отдельно.

Несколько вопросов, которые следует учитывать при сквозной задержке:

  • Где находится клиент, который вызывает вашу конечную точку?
  • Существуют ли какие-либо промежуточные уровни между вашим клиентом и средой выполнения SageMaker?

Автоматическое масштабирование

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

Распространенным вариантом является целевое отслеживание, при котором вы можете указать метрику CloudWatch или пользовательскую метрику, которую вы определили, и масштабировать на ее основе. Частое использование автоматического масштабирования — отслеживание InvocationsPerInstance метрика. После того, как вы определили узкое место на определенном TPS, вы часто можете использовать его в качестве метрики для масштабирования до большего количества экземпляров, чтобы иметь возможность обрабатывать пиковые нагрузки трафика. Чтобы получить более подробную информацию об автоматически масштабируемых конечных точках SageMaker, см. Настройка конечных точек логического вывода с автоматическим масштабированием в Amazon SageMaker.

Тестирование нагрузки

Хотя мы используем Locust, чтобы показать, как мы можем загружать тесты в масштабе, если вы пытаетесь правильно определить размер экземпляра за вашей конечной точкой, Рекомендатор вывода SageMaker является более эффективным вариантом. При использовании сторонних инструментов нагрузочного тестирования вам придется вручную развертывать конечные точки в разных экземплярах. С помощью Inference Recommender вы можете просто передать массив типов экземпляров, для которых вы хотите загрузить тест, и SageMaker начнет работать. работе для каждого из этих случаев.

саранча

Для этого примера мы используем саранча, инструмент нагрузочного тестирования с открытым исходным кодом, который можно реализовать с помощью Python. Locust похож на многие другие инструменты нагрузочного тестирования с открытым исходным кодом, но имеет несколько конкретных преимуществ:

  • Простота установки — Как мы показываем в этом посте, мы передадим простой скрипт Python, который можно легко реорганизовать для вашей конкретной конечной точки и полезной нагрузки.
  • Распределенный и масштабируемый – Саранча основана на событиях и использует Gevent под капотом. Это очень полезно для тестирования высокопараллельных рабочих нагрузок и имитации тысяч одновременных пользователей. Вы можете достичь высокого TPS с помощью одного процесса, работающего с Locust, но он также имеет генерация распределенной нагрузки функция, которая позволяет вам масштабироваться до нескольких процессов и клиентских машин, как мы рассмотрим в этом посте.
  • Метрики саранчи и пользовательский интерфейс – Locust также фиксирует сквозную задержку в качестве метрики. Это может помочь дополнить ваши метрики CloudWatch, чтобы нарисовать полную картину ваших тестов. Все это фиксируется в пользовательском интерфейсе Locust, где вы можете отслеживать одновременных пользователей, рабочих и многое другое.

Чтобы лучше понять Locust, ознакомьтесь с их документации.

Настройка Amazon EC2

Вы можете настроить Locust в любой совместимой для вас среде. Для этого поста мы настроили экземпляр EC2 и установили там Locust для проведения наших тестов. Мы используем экземпляр c5.18xlarge EC2. Также следует учитывать вычислительную мощность на стороне клиента. Иногда, когда у вас заканчивается вычислительная мощность на стороне клиента, это часто не фиксируется и ошибочно принимается за ошибку конечной точки SageMaker. Важно разместить клиент в месте с достаточной вычислительной мощностью, которая может справиться с нагрузкой, которую вы тестируете. Для нашего экземпляра EC2 мы используем AMI Ubuntu Deep Learning, но вы можете использовать любой AMI, если вы можете правильно настроить Locust на машине. Чтобы понять, как запустить инстанс EC2 и подключиться к нему, обратитесь к руководству. Начните работу с инстансами Amazon EC2 Linux.

Пользовательский интерфейс Locust доступен через порт 8089. Мы можем открыть его, настроив правила группы безопасности для входящего трафика для экземпляра EC2. Мы также открываем порт 22, чтобы мы могли подключиться к инстансу EC2 по SSH. Рассмотрите возможность ограничения источника до определенного IP-адреса, с которого вы получаете доступ к экземпляру EC2.

Группы безопасности

После того, как вы подключитесь к своему инстансу EC2, мы настроим виртуальную среду Python и установим API Locust с открытым исходным кодом через интерфейс командной строки:

virtualenv venv #venv is the virtual environment name, you can change as you desire
source venv/bin/activate #activate virtual environment
pip install locust

Теперь мы готовы работать с Locust для нагрузочного тестирования нашей конечной точки.

Саранчовые испытания

Все тесты с нагрузкой на саранчу проводятся на основе Файл саранчи что вы предоставляете. Этот файл Locust определяет задачу для нагрузочного теста; здесь мы определяем наш Boto3 вызов API invoke_endpoint, Смотрите следующий код:

config = Config(
retries = { 'max_attempts': 0, 'mode': 'standard'
}
) self.sagemaker_client = boto3.client('sagemaker-runtime',config=config)
self.endpoint_name = host.split('/')[-1]
self.region = region
self.content_type = content_type
self.payload = payload

В предыдущем коде настройте параметры вызова конечной точки вызова в соответствии с вызовом конкретной модели. Мы используем InvokeEndpoint API, использующий следующий фрагмент кода в файле Locust; это наша точка запуска нагрузочного теста. Используемый нами файл Locust: саранча_script.py.

def send(self): request_meta = { "request_type": "InvokeEndpoint", "name": "SageMaker", "start_time": time.time(), "response_length": 0, "response": None, "context": {}, "exception": None,
}
start_perf_counter = time.perf_counter() try:
response = self.sagemaker_client.invoke_endpoint(
EndpointName=self.endpoint_name,
Body=self.payload,
ContentType=self.content_type
)
response_body = response["Body"].read()

Теперь, когда у нас есть готовый сценарий Locust, мы хотим запустить распределенные тесты Locust, чтобы провести стресс-тестирование нашего единственного экземпляра, чтобы узнать, какой объем трафика может обрабатывать наш экземпляр.

Распределенный режим Locust немного сложнее, чем однопроцессный тест Locust. В распределенном режиме у нас есть один основной и несколько рабочих процессов. Основной рабочий инструктирует рабочих о том, как создавать и контролировать одновременных пользователей, отправляющих запрос. В нашем распределенный.sh script мы видим по умолчанию, что 240 пользователей будут распределены по 60 воркерам. Обратите внимание, что --headless флаг в интерфейсе командной строки Locust удаляет функцию пользовательского интерфейса Locust.

#replace with your endpoint name in format https://<<endpoint-name>>
export ENDPOINT_NAME=https://$1 export REGION=us-east-1
export CONTENT_TYPE=application/json
export PAYLOAD='{"inputs": "I am super happy right now."}'
export USERS=240
export WORKERS=60
export RUN_TIME=1m
export LOCUST_UI=false # Use Locust UI .
.
. locust -f $SCRIPT -H $ENDPOINT_NAME --master --expect-workers $WORKERS -u $USERS -t $RUN_TIME --csv results &
.
.
. for (( c=1; c<=$WORKERS; c++ ))
do
locust -f $SCRIPT -H $ENDPOINT_NAME --worker --master-host=localhost &
done

./distributed.sh huggingface-pytorch-inference-2022-10-04-02-46-44-677 #to execute Distributed Locust test

Сначала мы запускаем распределенный тест на одном экземпляре, поддерживающем конечную точку. Идея здесь заключается в том, что мы хотим полностью максимизировать один экземпляр, чтобы понять количество экземпляров, необходимое для достижения нашего целевого TPS, оставаясь при этом в рамках наших требований к задержке. Обратите внимание, что если вы хотите получить доступ к пользовательскому интерфейсу, измените Locust_UI переменной среды в значение True и возьмите общедоступный IP-адрес вашего экземпляра EC2 и сопоставьте порт 8089 с URL-адресом.

На следующем снимке экрана показаны наши показатели CloudWatch.

Метрики CloudWatch

В конце концов мы замечаем, что, хотя изначально мы достигли TPS 200, мы начинаем замечать ошибки 5xx в наших журналах на стороне клиента EC2, как показано на следующем снимке экрана.

Мы также можем убедиться в этом, взглянув на наши метрики на уровне экземпляра, в частности CPUUtilization.

Метрики CloudWatchЗдесь мы замечаем CPUUtilization почти на 4,800%. Наш инстанс ml.m5.12x.large имеет 48 виртуальных ЦП (48 * 100 = 4800~). Это насыщает весь экземпляр, что также помогает объяснить наши ошибки 5xx. Мы также видим рост ModelLatency.

Кажется, что наш единственный экземпляр падает и не имеет вычислительных ресурсов, чтобы выдержать нагрузку выше 200 TPS, которые мы наблюдаем. Наша цель — 1000 TPS, поэтому давайте попробуем увеличить количество экземпляров до 5. Это может быть даже больше в производственных условиях, потому что мы наблюдали ошибки при 200 TPS после определенного момента.

Настройки конечной точки

Как в пользовательском интерфейсе Locust, так и в журналах CloudWatch мы видим, что у нас есть TPS почти 1000 с пятью экземплярами, поддерживающими конечную точку.

саранча

Метрики CloudWatchЕсли вы начинаете сталкиваться с ошибками даже при такой настройке оборудования, обязательно отслеживайте CPUUtilization чтобы понять полную картину хостинга вашей конечной точки. Крайне важно понимать использование вашего оборудования, чтобы увидеть, нужно ли вам увеличивать масштаб или даже уменьшать его. Иногда проблемы на уровне контейнера приводят к ошибкам 5xx, но если CPUUtilization низкий, это указывает на то, что это не ваше оборудование, а что-то на уровне контейнера или модели, что может привести к этим проблемам (например, не задана правильная переменная среды для числа рабочих). С другой стороны, если вы заметили, что ваш инстанс полностью загружен, это признак того, что вам нужно либо увеличить текущий парк инстансов, либо попробовать более крупный инстанс с меньшим парком.

Хотя мы увеличили количество экземпляров до 5, чтобы обрабатывать 100 TPS, мы видим, что ModelLatency показатель по-прежнему высок. Это связано с насыщением экземпляров. В целом, мы предлагаем стремиться использовать ресурсы подземелья на уровне 60–70%.

Убирать

После нагрузочного тестирования обязательно очистите все ресурсы, которые вы не будете использовать, через консоль SageMaker или через delete_endpoint Вызов API Boto3. Кроме того, обязательно остановите свой экземпляр EC2 или любую другую настройку клиента, чтобы не нести никаких дополнительных расходов.

Обзор

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


Об авторах

Марк Карп является архитектором машинного обучения в команде SageMaker Service. Он фокусируется на помощи клиентам в проектировании, развертывании и управлении рабочими нагрузками машинного обучения в масштабе. В свободное время он любит путешествовать и исследовать новые места.

Рам Вегираджу является архитектором машинного обучения в команде SageMaker Service. Он помогает клиентам создавать и оптимизировать свои решения AI/ML на Amazon SageMaker. В свободное время любит путешествовать и писать.

Отметка времени:

Больше от Машинное обучение AWS