Узнайте, как развернуть модели машинного обучения в кластерах Kubernetes и реализовать автомасштабирование для вашего развертывания с помощью HPA и KEDA.
В большинстве приложений машинного обучения развертывание обученных моделей в рабочей среде является ключевым этапом. Именно здесь модели демонстрируют свою ценность, давая прогнозы для клиентов или других систем.
Развертывание модели может быть таким же простым, как реализация сервера Flask, а затем экспорт его конечных точек для вызова пользователями. Тем не менее, создать систему, способную надежно и надежно обслуживать большое количество запросов со строгими требованиями к времени отклика или пропускной способности, непросто.
Для среднего и крупного бизнеса системы должны иметь возможность масштабирования для обработки более тяжелых рабочих нагрузок без существенного изменения кодовой базы. Возможно, корпорация расширяется и нуждается в масштабируемой системе для обработки растущего числа запросов (эта характеристика — масштабируемость). Бизнесу необходимо, чтобы система могла адаптироваться к колебаниям трафика (эта характеристика — эластичность). Эти характеристики могут быть достигнуты, если системы способны автоматически масштабироваться в зависимости от объема трафика.
В этом руководстве мы узнаем, как развертывать модели машинного обучения в кластерах Kubernetes с помощью Seldon Core. Мы также научимся реализовывать автомасштабирование для нашего развертывания с помощью HPA и KEDA. Код для этого урока можно найти в этом репозитории.
Обучить модель PyTorch
Чтобы пройти процесс развертывания, нам понадобится модель. Мы используем модель из этого учебника с официального сайта PyTorch. Это простая модель классификации изображений, которая может легко работать с ЦП, поэтому мы можем протестировать весь процесс развертывания на локальных компьютерах, таких как ваш ноутбук.
Предположим, вы находитесь в папке toy-model
этого репозитория. Вы можете обучить модель на наборе данных CIFAR10 с помощью:
python train.py # Output: model.pth -> the trained weights of the model
Seldon Core использует Triton Inference Server для обслуживания моделей PyTorch, поэтому нам нужно подготовить модель в формате, в котором ее можно будет обслуживать с помощью Triton. Во-первых, нам нужно экспортировать модель в TorchScript (также можно обслуживать модели PyTorch с помощью python backend от Triton, но, как правило, это менее эффективно и сложнее в развертывании).
Трассировка и создание сценариев — это два метода экспорта модели в TorchScript. Выбор между ними до сих пор остается дискуссионным, в этой статье исследуются преимущества и недостатки обоих методов. Мы будем использовать метод трассировки для экспорта модели:
python export_to_ts.py -c model.pth -o model.ts # Output: model.ts # -> serialized model containing both trained weights and the model's architecture
Triton загружает модели из хранилища моделей. Он должен содержать информацию, необходимую серверу для обслуживания модели, такую как информация о входе/выходе модели, используемая серверная часть… Репозиторий модели должен иметь следующую структуру:
<model-repository-path>/ <model-name>/ [config.pbtxt] [<output-labels-file> ...] <version>/ <model-definition-file> <version>/ <model-definition-file> ... <model-name>/ [config.pbtxt] [<output-labels-file> ...] <version>/ <model-definition-file> <version>/ <model-definition-file> ... ...
В нашем случае у нас есть только одна модель. Назовем модель cifar10-pytorch
, наш репозиторий модели должен иметь следующую структуру:
cifar10-model └── cifar10-pytorch ├── 1 │ └── model.ts └── config.pbtxt
cifar10-model
— имя репозитория, cifar10-pytorch
— имя модели, а model.ts
— модель TorchScript, которую мы только что экспортировали. config.pdtxt
определяет, как модель должна обслуживаться с помощью Triton:
platform: "pytorch_libtorch" default_model_filename: "model.ts" max_batch_size: 0 input [ { name: "image__0" data_type: TYPE_UINT8 dims: [-1, 3, -1, -1] } ] output [ { name: "probs__0" data_type: TYPE_FP32 dims: [-1, 10] } ]
Вы можете найти финальный репозиторий здесь. Triton поддерживает несколько функций, которые можно использовать для настройки производительности модели. Вы также можете сгруппировать несколько шагов или несколько моделей в конвейер вывода для реализации своей бизнес-логики. Однако я намеренно делаю конфигурацию модели простой, чтобы проиллюстрировать весь процесс развертывания модели, вместо того чтобы сосредоточиться на производительности.
Если вы хотите увидеть более реалистичный пример того, как экспортировать и обслуживать модель PyTorch с помощью Triton, взгляните на этот пост. Он демонстрирует, как использовать Triton для обслуживания модели MaskRCNN от Detectron2, популярной модели для сегментации экземпляров и используемой во многих реальных системах компьютерного зрения.
Triton может получать доступ к моделям из локальной файловой системы или облачных служб хранения (например, S3, Google Storage или Azure Storage). Поскольку мы собираемся развернуть модель в Kubernetes, использование облачного хранилища более удобно, поскольку все узлы в кластере Kubernetes могут получить доступ к одним и тем же моделям. В этом руководстве мы будем использовать AWS S3 в качестве хранилища моделей. Предположим, что у вас уже есть учетная запись AWS, давайте создадим корзину S3 и загрузим подготовленную нами папку:
aws s3 cp --recursive cifar10-model s3://<YOUR_BUCKET>/cifar10-model
Замените <YOUR_BUCKET>
на имя вашего ведра. Теперь у нас есть репозиторий модели на AWS S3, и мы можем приступить к развертыванию модели.
Развертывание моделей с помощью Seldon Core
Мы развернем модель в кластере Kubernetes с помощью Seldon Core, фреймворка, специализирующегося на развертывании и мониторинге модели машинного обучения. Давайте создадим локальный кластер Kubernetes, чтобы протестировать процесс развертывания на нашей локальной машине.
Вид можно использовать для создания локальных кластеров. На момент написания у Seldon Core была проблема с k8s ≥ 1.25, поэтому мы должны использовать версию 1.24 или старше. Чтобы указать версию k8s с помощью Kind, просто выберите образ с соответствующей версией для запуска кластера. Следующая команда создает локальный кластер с именем kind-seldon
и k8s==1.24.7
:
kind create cluster --name seldon --image kindest/node:v1.24.7
Кроме того, убедитесь, что на вашем локальном компьютере установлены docker
, kubectl
, helm
. Переключение контекста kubectl
на kind-seldon
указывает kubectl
на подключение к только что созданному кластеру по умолчанию:
kubectl cluster-info --context kind-seldon
Установите ядро Селдон
Мы будем использовать Istio в качестве Ingress кластера и Seldon Core в качестве обслуживающей платформы. Инструкцию по установке вы можете найти здесь. После установки Istio и Seldon Core выполните следующие команды, чтобы проверить, правильно ли они установлены:
kubectl get svc -n istio-system # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE # istio-egressgateway ClusterIP 10.96.90.103 <none> 80/TCP,443/TCP 3m29s # istio-ingressgateway LoadBalancer 10.96.229.8 <pending> 15021:30181/TCP,80:32431/TCP,443:30839/TCP,31400:32513/TCP,15443:32218/TCP 3m28s # istiod ClusterIP 10.96.195.7 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 8m48s
Проверьте, работает ли шлюз Istio:
kubectl get gateway -n istio-system # NAME AGE # seldon-gateway 5m17s
Проверьте, работает ли контроллер Seldon:
kubectl get pods -n seldon-system # NAME READY STATUS RESTARTS AGE # seldon-controller-manager-b74d66684-qndf6 1/1 Running 0 4m18Create an Istio gateway to manage the cluster’s traffic:
Если вы этого не сделали, убедитесь, что метка istio-injection
включена:
kubectl label namespace default istio-injection=enabled
Шлюз Istio работает на порту 80 в кластере, нам нужно перенаправить порт с вашего локального компьютера на этот порт, чтобы мы могли получить к нему внешний доступ:
kubectl port-forward -n istio-system svc/istio-ingressgateway 8080:80
Работа с Seldon Core
Если репозиторий вашей модели хранится в частной корзине, вам необходимо предоставить разрешение на доступ к этой корзине из кластера. Это можно сделать, создав секрет, а затем ссылаясь на него при создании развертывания. Это шаблон для создания секретов для корзин S3:
apiVersion: v1 kind: Secret metadata: name: seldon-rclone-secret type: Opaque stringData: RCLONE_CONFIG_S3_TYPE: s3 RCLONE_CONFIG_S3_PROVIDER: aws RCLONE_CONFIG_S3_ENV_AUTH: "false" RCLONE_CONFIG_S3_ACCESS_KEY_ID: "<AWS_ACCESS_KEY_ID>" RCLONE_CONFIG_S3_SECRET_ACCESS_KEY: "<AWS_SECRET_ACCESS_KEY>"
Замените AWS_ACCESS_KEY_ID
и AWS_SECRET_ACCESS_KEY
вашим фактическим идентификатором ключа доступа AWS и секретным ключом доступа. Создайте секрет:
kubectl apply -f secret.yaml
Мы можем развернуть модель с этим манифестом, обратите внимание, что созданный секрет упоминается в манифесте с ключом envSecretRefName
. Убедитесь, что spec.predictors[].graph.name
соответствует имени модели, которое вы загрузили в репозиторий моделей. Примените манифест для создания развертывания:
kubectl apply -f cifar10-deploy.yaml
Если это ваше первое развертывание в этом кластере, загрузка необходимых образов Docker займет некоторое время. Проверьте, успешно ли развернута модель:
kubectl get deploy # NAME READY UP-TO-DATE AVAILABLE AGE # cifar10-default-0-cifar10-pytorch 1/1 1 1 41m
Я создал скрипт с помощью Locust для тестирования развернутых моделей. Вам нужно сначала установить требования, необходимые для запуска скрипта:
pip install -r requirements.txt
Учитывая, что порт localhost:8080
был переадресован на шлюз кластера, выполните следующую команду, чтобы отправить запросы на модели, развернутые с помощью Seldon:
locust -f test.py --headless -u 100 -r 10 --run-time 180 -H http://localhost:8080
Если ваше имя развертывания или имена модели отличаются, вы можете соответствующим образом изменить URL-адрес развертывания в сценарии. URL развернутой модели соответствует протоколу вывода Seldon Core:
/seldon/{namespace}/{model_repo}/v2/models/{model_name}/versions/{model_version}/infer
Мы развернули нашу пользовательскую модель с помощью Seldon Core и протестировали ее, отправив в модель запросы на вывод. В следующем разделе мы рассмотрим, как масштабировать развертывание для обработки большего количества пользователей или более высокого трафика.
Автомасштабирование Pod с помощью HPA
Что касается масштабируемости, Kubernetes предлагает HPA (Horizontal Pod Autoscaling). Когда определенные показатели достигают своих пороговых значений для ресурса (например, ЦП или памяти), HPA может добавить больше модулей для обработки более тяжелых рабочих нагрузок.
Установить сервер метрик
HPA необходимо получать метрики из агрегированного API, который обычно предоставляется через Сервер метрик. Вы можете установить сервер метрик для своего кластера с помощью:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Если ваш кластер локальный, вам также необходимо отключить проверку сертификата, передав аргумент -kubelet-insecure-tls
серверу:
kubectl patch -n kube-system deployment metrics-server --type=json \ -p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
Развертывание моделей с HPA
Мы можем включить HPA в манифесте развертывания, добавив hpaSpec
для соответствующего компонента:
hpaSpec: maxReplicas: 2 metrics: - resource: name: cpu # This can be either "cpu" or "memory" targetAverageUtilization: 50 type: Resource minReplicas: 1
Спецификация HPA сообщает развертыванию о необходимости масштабирования, когда текущее значение метрики (в данном случае использование ЦП) превышает 50 % от желаемого значения, а максимальное количество реплик, которые может иметь развертывание, равно 2.
Примените этот манифест для создания развертывания с HPA, убедитесь, что вы заменили <YOUR_BUCKET>
на имя вашей корзины и что секрет для доступа к корзине (как упоминалось в предыдущем разделе) создан:
kubectl apply -f cifar10-deploy-hpa.yaml
Вы можете увидеть текущее значение метрики с помощью:
kubectl get hpa # NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE # cifar10-default-0-cifar10-pytorch Deployment/cifar10-default-0-cifar10-pytorch 0%/50% 1 2 1 98m
Давайте проверим работающие стручки. Вы должны увидеть работающий модуль для развернутой модели:
kubectl get pods # NAME READY STATUS RESTARTS AGE # cifar10-default-0-cifar10-pytorch-7744fdc4dd-vzx4x 3/3 Running 0 101m
Теперь мы можем протестировать развернутую модель с помощью нашего тестового скрипта (о котором говорилось в предыдущем разделе):
locust -f test.py --headless -u 100 -r 10 --run-time 180 -H http://localhost:8080
Отслеживая текущее значение метрики с помощью kubectl get hpa -w
, вы увидите, что через некоторое время значение метрики превышает пороговое значение, и HPA инициирует создание нового модуля:
kubectl get pods # NAME READY STATUS RESTARTS AGE # cifar10-default-0-cifar10-pytorch-7744fdc4dd-pgpxm 3/3 Running 0 10s # cifar10-default-0-cifar10-pytorch-7744fdc4dd-vzx4x 3/3 Running 0 108m
Если текущее значение метрики ниже порогового значения для определенного периода (по умолчанию это 5 минут), HPA уменьшит масштаб развертывания. Период можно настроить с помощью флага аргумента --horizontal-pod-autoscaler-downscale-stabilization
на kube-controller-manager
:
kubectl get pods # NAME READY STATUS RESTARTS AGE # cifar10-default-0-cifar10-pytorch-7744fdc4dd-pgpxm 3/3 Terminating 0 7m3s # cifar10-default-0-cifar10-pytorch-7744fdc4dd-vzx4x 3/3 Running 0 114m
В этом разделе мы узнали, как увеличивать и уменьшать количество модулей в зависимости от загрузки ЦП. В следующем разделе мы будем использовать KEDA для более гибкого масштабирования нашего развертывания на основе пользовательских показателей.
Автомасштабирование Pod с помощью KEDA
KEDA умеет получать метрики из многих источников (они называются скейлерами), список поддерживаемых скейлеров смотрите здесь. Мы настроим KEDA для получения метрик с сервера Prometheus и будем отслеживать метрики для запуска масштабирования пода. Сервер Prometheus собирает метрики из развертываний Seldon в кластере.
Установите Seldon Monitoring и KEDA
Следуйте этой инструкции, чтобы установить стек Селдона для мониторинга, в который входит сервер Prometheus. Теперь в пространстве имен seldon-monitoring
должны присутствовать следующие модули:
kubectl get pods -n seldon-monitoring # NAME READY STATUS RESTARTS AGE # alertmanager-seldon-monitoring-alertmanager-0 2/2 Running 3 (8h ago) 26h # prometheus-seldon-monitoring-prometheus-0 2/2 Running 2 (8h ago) 26h # seldon-monitoring-blackbox-exporter-dbbcd845d-qszj8 1/1 Running 1 (8h ago) 26h # seldon-monitoring-kube-state-metrics-7588b77796-nrd9g 1/1 Running 1 (8h ago) 26h # seldon-monitoring-node-exporter-fmlh6 1/1 Running 1 (8h ago) 26h # seldon-monitoring-operator-6dc8898f89-fkwx8 1/1 Running 1 (8h ago) 26h
Проверьте, создан ли монитор модуля для Seldon Core:
kubectl get PodMonitor -n seldon-monitoring # NAME AGE # seldon-podmonitor 26h
Выполните следующую команду, чтобы включить KEDA в Seldon Core:
helm upgrade seldon-core seldon-core-operator \ --repo https://storage.googleapis.com/seldon-charts \ --set keda.enabled=true \ --set usageMetrics.enabled=true \ --set istio.enabled=true \ --namespace seldon-system
Установите KEDA в кластер и убедитесь, что ранее установленный KEDA (если он был) полностью удален:
kubectl delete -f https://github.com/kedacore/keda/releases/download/v2.9.1/keda-2.9.1.yaml kubectl apply -f https://github.com/kedacore/keda/releases/download/v2.9.1/keda-2.9.1.yaml
Развертывание моделей с помощью KEDA
У нас все настроено. Давайте создадим развертывание Seldon с помощью KEDA. Как и в случае с HPA, чтобы включить KEDA в развертывании, нам нужно всего лишь включить kedaSpec
в манифест развертывания. Рассмотрим следующую спецификацию:
kedaSpec: pollingInterval: 15 minReplicaCount: 1 maxReplicaCount: 2 triggers: - type: prometheus metadata: serverAddress: http://seldon-monitoring-prometheus.seldon-monitoring.svc.cluster.local:9090 metricName: access_frequency threshold: '20' query: avg(rate(seldon_api_executor_client_requests_seconds_count{deployment_name=~"cifar10"}[1m]))
serverAddress
— это адрес сервера Prometheus внутри кластера, это должен быть URL-адрес сервиса Prometheus, мы можем проверить сервис с помощью kubectl get svc -n seldon-monitoring
. Когда значение метрики превысит threshold
, будет запущено масштабирование. query
— это среднее количество запросов в секунду для запущенных реплик, это показатель, который мы хотим отслеживать.
Примените этот манифест для развертывания модели:
kubectl apply -f cifar10-deploy-keda.yaml
Запустим автомасштабирование, отправив запросы в деплоймент:
locust -f test.py --headless -u 100 -r 10 --run-time 180 -H http://localhost:8080
Через несколько секунд вы увидите созданный новый модуль:
kubectl get pods # NAME READY STATUS RESTARTS AGE # cifar10-default-0-cifar10-pytorch-5dc484599c-2zrv8 3/3 Running 3 (18m ago) 35h # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 0/3 Init:0/2 0 9s
Подобно HPA, уменьшение масштаба будет запущено после определенного периода (по умолчанию 5 минут) низкого трафика.
kubectl get pods -w # NAME READY STATUS RESTARTS AGE # cifar10-default-0-cifar10-pytorch-5dc484599c-2zrv8 3/3 Running 3 (22m ago) 35h # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 3/3 Running 0 3m55s # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 3/3 Terminating 0 5m49s # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 2/3 Terminating 0 6m # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 1/3 Terminating 0 6m1s # cifar10-default-0-cifar10-pytorch-5dc484599c-ljk74 0/3 Terminating 0 6m3s
Заключение
Мы узнали, как развертывать модели машинного обучения в кластерах Kubernetes с помощью Seldon Core. Хотя мы в основном сосредоточились на развертывании моделей PyTorch, процедуры, показанные в этом руководстве, можно использовать для развертывания моделей из других платформ.
Мы также сделали развертывания масштабируемыми с помощью HPA и KEDA. По сравнению с HPA, KEDA предоставляет более гибкие способы масштабирования системы на основе метрик Prometheus (или других поддерживаемых масштабаторов от KEDA). Технически мы можем реализовать любые правила масштабирования из метрик, которые можно получить с сервера Prometheus.
Первоначально опубликовано на https://tintn.github.io 9 января 2023 г.