Наилучшее сочетание фреймворков с открытым исходным кодом для управления моделями в Kubernetes?
В простейшей форме управление моделью можно рассматривать как обучение одной модели машинного обучения, а затем повторение этого десятков, сотен или тысяч раз с разными данными, параметрами, функциями и алгоритмами, чтобы наконец развернуть «лучший» один. Более полное определение будет заключаться в том, что управление моделями включает в себя разработку инструментов и конвейеров для специалистов по данным для разработки, развертывания, измерения, улучшения и повторения, чтобы они могли продолжать создавать лучшие модели не только для одной конкретной проблемы, но и для более широкого диапазона наборов данных и алгоритмов.
В то же время управление моделями включает все требования более традиционных приложений, таких как разработка API и управление версиями, управление пакетами, контейнеризация, воспроизводимость, масштабирование, мониторинг, ведение журналов и многое другое.
Цель этой статьи - предложить повторяемый конвейер, чтобы упростить вашу жизнь и ускорить итерации. Думаю, эта цитата очень хорошо передает дух.
Мы не применяем одну модель, мы внедряем процесс, чтобы многократно производить больше. Когда вы внедряете модель машинного обучения в производство, вы не говорите: «Это лучшая модель, и мы должны использовать ее вечно». На самом деле это означает развертывание конвейера для построения модели и повышение ее повторяемости.
Как мы сюда попали
В этом году мы стали свидетелями роста многих платформ машинного обучения, только на Strata мы увидели прилив от решений для хранения данных к механизмам SQL для данных в этих решениях хранения, к Spark, платформам для обработки данных и популярные сейчас платформы машинного обучения.
Точно так же, как Google выпустил MapReduce и другие документы для остального мира, чтобы последовали годы спустя с экосистемой Hadoop, для решения проблемы машинного обучения появились инструменты от Google и нескольких других крупных технологических компаний. Я даже связываю это каким-то образом с Kubernetes, который был так молод 2 года назад и сейчас стал ключевой частью предложения каждого облачного провайдера. На этом этапе было бы глупо не делать ставки на стек CNCF. Projects также включает TensorFlow и, совсем недавно, KubeFlow, который предоставляет больше рекомендаций по сочетанию инструментов.
Модель ML имеет множество различных требований, для разработки / обучения вам нужны графические процессоры, упаковка более сложна, чем просто файл JAR, поскольку нет одного языка, который вы могли бы использовать для всего, вам нужен Python, R с другими частями, написанными на C и C ++. Приложение увеличилось с 10 до +100 Мб, поскольку в моделях содержится много данных. Они перешли от конечных точек, которые в основном выполняли операции с базой данных, которые занимали пару миллисекунд, к более интеллектуальным операциям, которые делают прогнозы, но требуют больше времени для выполнения, требуют больше ЦП и больше ОЗУ.
В то же время традиционные требования журналов, мониторинга, безопасности, масштабируемости и другие вещи, которые имеют более традиционные приложения, также необходимы для этих новых типов приложений. Если вы выполняли A / B-тестирование для тестирования разделов на веб-сайте, теперь вы выполните A / B-тестирование для всех своих моделей машинного обучения, чтобы увидеть, какая из них работает лучше. Если вы масштабировали веб-сервер Node, теперь вам нужно масштабировать сервер обслуживания TensorFlow и так далее. В то же время разработка моделей машинного обучения также намного сложнее и требует больше времени, поскольку требует тестирования комбинаций алгоритмов, функций и прочего.
Вы можете получить большую пользу от машинного обучения по сравнению с традиционными приложениями, но вложения, которые вам необходимо сделать, огромны во многих областях.
Этот эксперимент
В этой статье исследуется сочетание нескольких новых технологий для управления моделями, чтобы обеспечить конвейер, который решает три основные группы проблем:
- Распределенное гиперпараметрическое обучение, которое также может быть использовано для реального распределенного обучения: Полиаксон
- Конвейер построения образа контейнера, использующий s2i: Argo
- Развертывание модели, которая может обрабатывать одно или несколько сложных развертываний: Селдон
Конечным результатом является конвейер машинного обучения, который обучает несколько моделей, исследует метрики, чтобы (вручную) выбирать лучшую, упаковывать модель как образ докера и развертывать ее как REST API.
Весь код, необходимый для выполнения, можно найти здесь: danielfrg / polyaxon-argo-seldon-example. Локально вам не понадобится больше, чем пара клиентских интерфейсов командной строки и клонирование пары репозиториев.
$ brew install kubectx $ brew install kubernetes-helm $ pip install polyaxon-cli $ brew install argoproj/tap/argo
$ git clone https://github.com/danielfrg/polyaxon-argo-seldon-example.git $ git clone https://github.com/SeldonIO/seldon-core.git
Инфраструктура и установка
Этот раздел представляет собой небольшую ссылку из документации по каждому проекту, поэтому обязательно прочтите ее, если что-то здесь не работает или устареет.
В следующих нескольких разделах мы рассмотрим установку и настройку пяти компонентов, которые мы будем использовать для построения конвейера развертывания модели:
- Кластер Kubernetes,
- NFS для постоянного хранения,
- Polyaxon для обучения распределенной модели,
- Арго для построения модели рабочего процесса контейнеризации и
- Селдону за развертывание модели.
После того, как мы установили и настроили каждый из этих компонентов, мы обучим, построим и развернем модель, начиная с раздела «Polyaxon: обучающие модели». Так что просто идите туда, если хотите пропустить все этапы установки.
Кластер Kubernetes
Я использовал GKE, но это мог быть любой кластер Kubernetes, используя консоль GCP или такую команду:
$ gcloud beta container --project "<project-name>" clusters create "model-mgmt" --zone "us-central1-a" --cluster-version "1.10.7-gke.2" --machine-type "n1-standard-2" --image-type "COS" --disk-size "10" --num-nodes "3" --network "default"
Настройте свой локальный kubectl
:
$ gcloud container clusters get-credentials model-mgmt --zone us-central1-a
NFS: одноузловая файловая система
Здесь сохраняется весь код, модели и данные. Его очень легко создать, используя этот GCP Шаблон файлового сервера с одним узлом.
Нам нужно создать пару каталогов на сервере NFS, чтобы подключиться к узлу по SSH, скопировав команду, доступную на экране после установки, или просто нажав кнопку «SSH to…».
Попав в экземпляр, создайте некоторую структуру каталогов для Polyaxon, Jupyter Lab и Argo позже.
$ cd /data $ mkdir -m 777 data $ mkdir -m 777 outputs $ mkdir -m 777 logs $ mkdir -m 777 repos $ mkdir -m 777 upload
$ cd repos $ mkdir deployments/ $ chmod 777 deployments/
Получите (частный) IP-адрес сервера NFS либо с помощью приведенной ниже команды, либо просто найдите его в консоли Google Cloud на виртуальных машинах. В моем случае это10.240.0.8
$ gcloud compute instances describe polyaxon-nfs-vm --zone=us-central1-f --format='value(networkInterfaces[0].networkIP)'
10.240.0.8
Наконец, создайте несколько PVC для использования с Polyaxon и другими инструментами. Обратите внимание: вам необходимо отредактировать *-pvc.yml
файлы и добавить правильный IP-адрес:
$ cd <polyaxon-argo-seldon-example repo> $ cd gke/
# And replace with the right ip address in all the files $ vi data-pvc.yml $ vi outputs-pvc.yml $ vi logs-pvc.yml $ vi repos-pvc.yml $ vi upload-pvc.yml
# Create the k8s resources $ kubectl create namespace polyaxon $ kubens polyaxon $ kubectl apply -f data-pvc.yml $ kubectl apply -f outputs-pvc.yml $ kubectl apply -f logs-pvc.yml $ kubectl apply -f repos-pvc.yml $ kubectl apply -f upload-pvc.yml
Установка Polyaxon
Поскольку PVC уже созданы, его относительно легко установить на основе документации. Сначала некоторые разрешения для учетной записи службы tiller (helm server).
# Configure tiller to have the access it needs $ kubectl --namespace kube-system create sa tiller $ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller $ helm init --service-account tiller
# Add polyaxon charts $ helm repo add polyaxon https://charts.polyaxon.com $ helm repo update
Теперь мы можем запустить Polyaxon с помощью Helm, единственное, что нам нужно, это polyaxon-config.yml
файл конфигурации и запустить Helm:
rbac: enabled: true
ingress: enabled: true
serviceType: ClusterIP
persistence: logs: existingClaim: polyaxon-pvc-logs repos: existingClaim: polyaxon-pvc-repos upload: existingClaim: polyaxon-pvc-upload data: data1: existingClaim: polyaxon-pvc-data mountPath: /data outputs: outputs1: existingClaim: polyaxon-pvc-outputs mountPath: /outputs
$ cd <polyaxon-argo-seldon-example repo> $ cd polyaxon
$ helm install polyaxon/polyaxon --name=polyaxon --namespace=polyaxon -f polyaxon/polyaxon-config.yml
Когда команда завершится, вы получите что-то вроде этого:
Polyaxon is currently running: 1. Get the application URL by running these commands: export POLYAXON_IP=$(kubectl get svc --namespace polyaxon polyaxon-polyaxon-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}') export POLYAXON_HTTP_PORT=80 export POLYAXON_WS_PORT=80 echo http://$POLYAXON_IP:$POLYAXON_HTTP_PORT 2. Setup your cli by running theses commands: polyaxon config set --host=$POLYAXON_IP --http_port=$POLYAXON_HTTP_PORT --ws_port=$POLYAXON_WS_PORT 3. Log in with superuser USER: root PASSWORD: Get login password with kubectl get secret --namespace polyaxon polyaxon-polyaxon-secret -o jsonpath="{.data.POLYAXON_ADMIN_PASSWORD}" | base64 --decode
Так что выполните эти инструкции и войдите в систему, используя polyaxon-cli
. Пара username:password
по умолчанию: root:rootpassword
:
$ polyaxon login --username=root --password=rootpassword
Вы также можете посетить напечатанный URL-адрес, чтобы посетить пользовательский интерфейс Polyaxon.
Установка Арго
Полная документация здесь (важен раздел разрешений), в основном:
$ kubectl create ns argo
$ kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/v2.2.1/manifests/install.yaml
$ kubectl create rolebinding default-admin --clusterrole=admin --serviceaccount=default:default
$ kubectl patch svc argo-ui -n argo -p '{"spec": {"type": "LoadBalancer"}}'
Теперь мы могли бы посетить пользовательский интерфейс Argo, который выглядит следующим образом, с помощью пары рабочих процессов:
Установка Селдона
Есть несколько способов установить Seldon, я решил использовать Helm, потому что, честно говоря, не совсем понимаю Ksonnet.
$ cd <seldon-core repo>
$ kubectl create namespace seldon $ kubens seldon $ kubectl create clusterrolebinding kube-system-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
$ helm install ./helm-charts/seldon-core-crd --name seldon-core-crd --set usage_metrics.enabled=true $ helm install ./helm-charts/seldon-core --name seldon-core --namespace seldon --set ambassador.enabled=true
Запустите это в другом терминале, чтобы проксировать службу Ambassador:
$ kubectl port-forward $(kubectl get pods -n seldon -l service=ambassador -o jsonpath='{.items[0].metadata.name}') -n seldon 8003:8080
Наконец-то мы установили все необходимое, давайте обучим и развернем несколько моделей!
Polyaxon: обучающие модели
Полиаксон - инструмент воспроизводимого машинного обучения. Это позволяет вам отправить параметризованный код, например, в TensorFlow или PyTorch для Polyaxon, чтобы запустить то, что они называют экспериментом. Эксперименты могут быть частью экспериментальной группы для поиска гиперпараметров.
Polyaxon заботится о выполнении заданий на основе императивных определений, аналогично тому, как это делает Kubernetes, он также заботится о сохранении метрик и выходных данных заданий для анализа и выбора. В нем есть некоторые функции, которые мы не будем использовать здесь для распределенного обучения или использования Tensorboard.
Следуя документации Polyaxon, мы можем создать новый проект на основе примеров.
$ polyaxon project create --name=mnist --description='Train and evaluate a model for the MNIST dataset'
$ polyaxon init mnist
Я хотел протестировать поиск гиперпараметров, чтобы файл полиаксона выглядел так:
--- version: 1
kind: group
hptuning: concurrency: 5 random_search: n_experiments: 10
matrix: lr: linspace: 0.001:0.1:5 momentum: uniform: 0.5:0.6
declarations: batch_size_train: 128 batch_size_test: 1000 epochs: 5 train_steps: 400
build: image: pytorch/pytorch:latest build_steps: - pip install --no-cache-dir -U polyaxon-helper
run: cmd: python run.py --batch-size={{ batch_size_train }} \ --test-batch-size={{ batch_size_test }} \ --epochs={{ epochs }} \ --lr={{ lr }} \ --momentum={{ momentum }} \ --epochs={{ epochs }}
Теперь мы можем запустить эксперимент:
$ cd <polyaxon-argo-seldon-example repo>
$ polyaxon run -u -f polyaxonfile_hyperparams.yml
На основе пространства параметров эта команда создаст одну экспериментальную группу с 10 экспериментами в этой группе. Вы можете видеть прогресс, журналы, параметры, среду и многое другое в пользовательском интерфейсе Polyaxon.
Когда эксперименты будут завершены, у вас будет 10 обученных моделей, и вы сможете использовать Polyaxon для просмотра показателей этих моделей и выбора наиболее эффективных для развертывания. Другой вариант внутри Polyaxon - развернуть сервер Tensorboard для просмотра там метрик, если вы сохранили вывод в этом формате, здесь я просто использовал собственные метрики Polyaxon.
Вы можете посмотреть и загрузить обученные модели, просто взглянув на запущенный нами ранее NFS-сервер и перейдя в каталог групп и экспериментов, например:
От Полиаксона к Арго
Теперь, когда мы обучили и сериализовали модели, нам нужно упаковать их и развернуть с помощью Seldon. Это требует некоторой ручной работы, так как вам нужно создать класс Python для использования Селдоном, создать requirements.txt
и переместить сериализованную модель в нужное место. Наконец, нам нужно использовать s2i для создания образа с использованием базового образа Селдона.
Весь этот процесс можно выполнить локально вручную, загрузив сериализованную модель и используя s2i, но в духе автоматизации я решил использовать Argo для этой задачи.
Я также хотел сохранить большинство вещей в кластере Kubernetes, где модели / данные и другие объекты расположены близко друг к другу, поэтому я использовал сервер Jupyter Lab, который вы можете запустить и запустить с этой спецификацией Kubernetes yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: jupyter
labels:
app: jupyter
spec:
replicas: 1
selector:
matchLabels:
app: jupyter
template:
metadata:
labels:
app: jupyter
spec:
containers:
- name: jupyter
image: jupyter/datascience-notebook
command: ["start-notebook.sh"]
args: ["--NotebookApp.token="]
env:
- name: JUPYTER_ENABLE_LAB
value: "1"
ports:
- containerPort: 8888
volumeMounts:
- mountPath: /home/jovyan
name: work-volume
- mountPath: /output
name: outputs-volume
volumes:
- name: work-volume
persistentVolumeClaim:
claimName: polyaxon-pvc-repos
- name: outputs-volume
persistentVolumeClaim:
claimName: polyaxon-pvc-outputs
---
kind: Service
apiVersion: v1
metadata:
name: jupyter
spec:
selector:
app: jupyter
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 8888
Эта установка Jupyter Lab будет иметь правильные крепления для перемещения сериализованной модели:
$ cp /output/root/mnist/groups/12/120/model.dat /home/jovyan/deployments/mnist/
После этого создайте файлы, необходимые для Seldon: класс Python для Seldon, каталог .s2i
с файлом environment
внутри и requirements.txt
. Все это доступно в репо. В конце должно получиться примерно так:
Фактический класс Python, который использует Селдон, таков:
import torch from network import Network from torchvision import datasets, transforms
class MnistModel(object): def __init__(self): self.model = Network() self.model.load_state_dict(torch.load("./model.dat"))
def predict(self, X, feature_names): tensor = torch.from_numpy(X).view(-1, 28, 28) t = transforms.Normalize((0.1307,), (0.3081,)) tensor_norm = t(tensor) tensor_norm = tensor_norm.unsqueeze(0) out = self.model(tensor_norm.float()) predictions = torch.nn.functional.softmax(out) print(predictions) return predictions.detach().numpy()
Это в основном загружает серализованную модель в функцию __init__
для последующего пользователя, так как в функции predict
у нас есть простой код PyTorch для предварительной обработки входных данных в соответствии с ожиданиями модели.
Теперь у нас есть все, что нужно для упаковки модели в виде образа докера с помощью Argo, который может использовать Селдон.
Арго: Создание образа докера для модели
Арго - менеджер рабочего процесса Kubernetes. Мы будем использовать Argo для создания многоразового нативного рабочего процесса контейнера для переноса сериализованной модели в контейнер, который впоследствии можно будет развернуть с помощью Seldon.
Для поддержки этого я создал простой образ докера, который выполняет s2i и отправляет образ, Dockerfile is here, а образ докера доступен как danielfrg / s2i.
Поскольку мы собираемся сначала отправить образ в концентратор Docker, нам нужно создать секрет с учетными данными для входа в реестр.
$ kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
С помощью образа мы можем использовать Argo для управления выполнением, конвейер Argo монтирует 3 объекта к контейнеру:
- Том Polyaxon для доступа к коду, который мы написали в предыдущем разделе.
- Сокет Docker для создания образа и отправки
- Учетные данные Docker для отправки в репозиторий
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: model-pkg- spec: entrypoint: model-pkg volumes: - name: work-volume persistentVolumeClaim: claimName: argo-pvc-repos - name: docker-sock-volume hostPath: path: /var/run/docker.sock - name: docker-config secret: secretName: regcred items: - key: .dockerconfigjson path: config.json
templates: - name: model-pkg steps: - - name: s2i-push template: s2i
- name: s2i container: image: danielfrg/s2i:0.1 command: ["sh", "-c"] args: ["s2i build /src/mnist seldonio/seldon-core-s2i-python3 danielfrg/seldon-mnist:0.2 && docker push danielfrg/seldon-mnist:0.2"] volumeMounts: - name: work-volume mountPath: /src - name: docker-sock-volume mountPath: /var/run/docker.sock - name: docker-config mountPath: /root/.docker readOnly: true
Затем просто выполните конвейер argo
$ argo submit argo/pipeline.yaml
Конвейер использует s2i с базовым образом Seldon seldonio/seldon-core-s2i-python3
, создает образ с тегом danielfrg/seldon-mnist:0.2
и отправляет этот новый образ в Docker hub. Argo будет обрабатывать все выполнение, и вы можете видеть журналы и многое другое в их пользовательском интерфейсе:
Теперь, когда у нас есть образ в Docker Hub, мы можем использовать Seldon для его развертывания.
Селдон: развертывание модели
Seldon - отличный фреймворк для управления моделями в Kubernetes. Модели становятся доступными как REST API или как конечные точки gRPC, и вы можете выполнять причудливую маршрутизацию между моделями, включая A / B-тестирование и многорукие бандиты. Селдон заботится о масштабировании модели и о том, чтобы она работала со всеми вашими моделями со стандартным API.
Seldon использует свой собственный Kubernetes CRD, и он будет просто использовать образ Docker, который выдвинул конвейер Argo, спецификация развертывания CRD Seldon выглядит так:
apiVersion: machinelearning.seldon.io/v1alpha2
kind: SeldonDeployment
metadata:
name: mnist
labels:
app: seldon
namespace: seldon
spec:
name: mnist
predictors:
- componentSpecs:
- spec:
containers:
- image: danielfrg/seldon-mnist:0.2
imagePullPolicy: Always
name: classifier
graph:
endpoint:
type: REST
name: classifier
type: MODEL
labels:
version: v1
name: mnist
replicas: 1
Это создаст пару модулей Kubernetes, которые включают работающую модель и обрабатывают другие элементы маршрутизации.
После всей этой работы мы наконец можем запросить модель!
Поскольку мы развернули REST API, мы можем запросить эту развернутую модель, используя немного Python для чтения, изображения и выполнения HTTP-запроса:
import requests import numpy as np from PIL import Image
API_AMBASSADOR = "localhost:8003"
def load_image(filename): img = Image.open(filename) img.load() data = np.asarray(img, dtype="int32") return data
def rest_request_ambassador(deploymentName, imgpath, endpoint=API_AMBASSADOR): arr = load_image(imgpath).flatten() shape = arr.shape payload = {"data":{"names":[], "tensor":{"shape":shape, "values":arr.tolist()}}} response = requests.post( "http://"+endpoint+"/seldon/"+deploymentName+"/api/v0.1/predictions", json=payload) print(response.status_code) print(response.text)
rest_request_ambassador("mnist", "images/87.png")
Результатом этого будет прогноз для изображения, 87-е изображение - это 9, и прогноз действительно таков.
{
"meta": {
"puid": "6rtbtvkvlftfeusuej5ni4197q",
"tags": {
},
"routing": {
},
"requestPath": {
"classifier": "danielfrg/seldon-mnist:0.2"
}
},
"data": {
"names": ["t:0", "t:1", "t:2", "t:3", "t:4", "t:5", "t:6", "t:7", "t:8", "t:9"],
"tensor": {
"shape": [1, 10],
"values": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
}
}
}
У Селдона есть много других функций, которые здесь не рассматриваются, проверьте их сайт.
Мысли
Это выглядит очень сложно, должен быть способ получше! Вероятно, есть гораздо лучшие способы. Большинство компаний с командами по большим данным создают аналогичную инфраструктуру, и некоторые из них доступны для использования, например:
- TFX от Google / TensorFlow, бумага здесь
- KubeFlow, набор инструментов также от Google, он использует Seldon
- Фолилла от StictFix. Также ознакомьтесь с отличным докладом Джульетты Хогланд о том, как Stitch Fix выполняет развертывание производственной модели
- IBM / FfDL
- Убер Микеланджело
- Клипер, инструмент более низкого уровня для обслуживания моделей.
- Instacart Lore
Есть также, конечно, компании, у которых есть продукты, которые вы можете купить в этом направлении:
- Anaconda Enterprise (отказ от ответственности там, где я работаю)
- Лаборатория данных Domino
- DataBricks
- Все облачные провайдеры
- и многое другое.
Варианты бесконечны в зависимости от вашего варианта использования, и вы должны выбирать и строить поверх всего. Kubernetes - настоящая платформа в том смысле, что вы можете расширять ее по мере необходимости, это пример этого. Не хватает многого, что вы можете добавить, чтобы создать идеальную платформу для управления моделями. Например, мониторинг, несколько пользователей, аутентификация и безопасность, аудит, каталог для моделей в виде образов докеров, центральное хранилище должно быть NFS или хранилищем объектов или что-то еще?
Каждая из этих функций значительно увеличит стоимость.
Jupyter Hub и Binder. Этот процесс относительно хорошо интегрируется с некоторыми предыдущими работами, которые я разместил здесь в Jupyter Hub в Kubernetes для многопользовательской среды разработки. Отличное многопользовательское сотрудничество - ключевая часть процесса. Также не забывайте, что конечным результатом обычно является не API, а какое-то приложение, информационная панель или отчет, и развертывание этих приложений также важно.
Почему бы просто не использовать Argo для обучения моделей? Я думаю, что сейчас Polyaxon лучше подходит для обучения моделей, поскольку он делает именно это, Argo - более общий характер, и это замечательно, но специализированные инструменты иногда лучше. Архитектура Арго более сложна и расширяема, поэтому на ее основе можно построить другие инструменты, я полагаю, что в конце концов это произойдет.
Что с этим делать? Воспринимайте это как простой эксперимент, чтобы показать, что сегодня возможно с помощью фреймворков с открытым исходным кодом для управления моделями в Kubernetes. Возьмите это и адаптируйте к своим потребностям. Цель состоит в том, чтобы упростить вашу жизнь, ускорить итерации и улучшить модели.
Этот конвейер очень полезен. Однако это далеко не все. Это сэкономит вам время прямо сейчас, но некоторые ручные части необходимо автоматизировать. Вам нужно будет поработать над интеграцией этого (или чего-то еще) в существующий рабочий процесс вокруг Git и CI / CD (Jenkins).
Другие ссылки и вещи, которые я использовал
- Документы Polyaxon
- Примеры полиаксона
- FfDL-Seldon / pytorch-модель
- Селдон-ядро
- https://github.com/SeldonIO/seldon-core.gitcreate_docker_image_build_workflow.html">Арго ДинД