С момента запуска Vertex AI я развертываю модели быстрее, чем когда-либо прежде. В самом простом сценарии Vertex AI предоставляет готовые образы управляемых контейнеров, что позволяет вам обслуживать свои модели из скрипта.

Но вот вопрос:

Что делать, если существующие предварительно созданные образы контейнеров Vertex AI не имеют нужных зависимостей или не используют вашу платформу?

Как вы можете продолжать развертывать свои модели в Vertex AI?

В этом посте я предложу возможное решение этих сценариев. Я буду обучать модель scikit-learn, чтобы предсказать, превысит ли годовой доход 50 000 долларов США в год, на основе данных переписи с версией библиотеки, которая не поддерживается готовыми обучающими контейнерами Vertex AI. И я покажу, как вы можете использовать ONNX на Vertex AI для его развертывания. К концу вы узнаете, чем ONNX и Vertex AI лучше вместе. Использование ONNX на Vertex AI не только упростит процесс развертывания модели, но также предоставит обслуживающие платформы, изначально поддерживаемые Vertex AI, что сделает платформу еще более открытой.

Важно отметить, что содержание статьи представляет собой первую попытку. Ни один из подходов или общего кода не готов к работе.

Резюме: что такое ONNX?

Если вы уже знаете, что такое ONNX и как он поддерживает жизненный цикл MLOps, можете пропустить этот раздел.

Представьте, что у вас есть модель A, обученная с помощью платформы X, и модель B, обученная с помощью платформы Y. Поскольку разные платформы машинного обучения требуют разной оптимизации обслуживания и могут требовать разных ресурсов инфраструктуры, команда разработчиков машинного обучения должна предоставлять разные стратегии развертывания, поддерживать производительность среды выполнения обслуживания. и его конвейеры CD для каждого фреймворка. Управление этим разнообразием стратегий, сред выполнения и конвейеров компакт-дисков с течением времени может увеличить операционные издержки, связанные с производством моделей, и это нередкая проблема, с которой инженеры машинного обучения сталкиваются при развертывании моделей в масштабе.

MLOps помогает справляться с различными операционными проблемами, используя лучшие практики DevOps. Например, вы можете создать общий образ с минимальными зависимостями и создать конвейеры компакт-дисков, которые постепенно создают обслуживающий контейнер в зависимости от обучающей среды. Но наличие такого процесса может потребовать времени в зависимости от нескольких факторов, включая возможности и навыки команды, которые могут быть ограниченными ресурсами, которые пользуются очень большим спросом.

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

Один из вариантов — ввести стандарт взаимодействия для сериализации моделей и сделать их обслуживающий код независимым от базовой среды выполнения. Имея модель A, обученную с помощью платформы X, и модель B, обученную с помощью платформы Y, вы преобразуете обе модели в представление, которое использует одну и ту же среду выполнения для их обслуживания с использованием одного и того же конвейера CD.

ONNX означает Open Neural Network Exchange, и это формат с открытым исходным кодом, который обеспечивает общее и эффективное представление моделей ИИ, как для глубокого обучения (ONNX), так и для традиционных моделей ML (ONNXML).

ONNX представляет модели в виде графов вычислений (protobuf) с использованием встроенных версионных операторов и определенных типов данных, чтобы гарантировать совместимость между реализациями. Также поддерживаются метаданные модели. Основными компонентами ONNX являются:

  • Конвертеры для преобразования моделей любого поддерживаемого фреймворка в формат ONNX.
  • Время выполнения, позволяющее выполнять модели ONNX на нескольких OSS, архитектурах микросхем и аппаратных ускорителях.
  • Оптимизаторы для выполнения произвольной оптимизации моделей ONNX для более быстрого вывода.

Большинство этих возможностей доступны через Python API.

Вернемся к нашему сценарию. Как только вы создадите свой конвейер scikit-learn, вы можете использовать преобразователь sklearn-onnx, чтобы превратить конвейер из scikit-learn в ONNX. Затем вы можете развернуть свою модель на конечной точке Vertex AI, поместив onnxruntime в простой сервис REST с помощью Fast API. Таким образом, вы получите эффективную службу обслуживания, независимую от зависимостей фреймворка благодаря преобразованию ONNX.

Теперь, когда вы знаете, что такое ONNX и как вы можете извлечь выгоду из его использования в рамках вашего процесса MLOps, позвольте мне описать вам, как обучить и развернуть простую модель обучения с использованием технологии scikit-learn на вершинном ИИ с использованием ONNX.

Обучение и развертывание простой модели на Vertex AI с использованием ONNX

После создания конвейера с помощью API scikit-learn вы можете преобразовать его в формат ONNX с помощью sklearn-onnx. См. псевдокод, который я использовал:

# Libraries
import numpy as np
import pandas as pd
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import Int64TensorType, StringTensorType

# Helpers
def read_data(data_path: str) -> pd.DataFrame:
   …
   return pipeline

def build_pipeline(cat_features: List[str], num_features: List[str]) -> Pipeline:
   …
   return pipeline

def train(pipe: Pipeline, x_train: pd.DataFrame, y_train: pd.DataFrame) -> object:
   …
   return trained_pipeline

def get_schema(dataframe: pd.DataFrame) -> List[Dict[str, str]]:
   """
   Get schema from a pandas dataframe.
   Args:
       dataframe: pandas dataframe
   Returns:
       schema
   """
   schema = []
   for col, col_type in zip(dataframe.columns, dataframe.dtypes):
       if col_type == "object":
           schema_type = StringTensorType([None, 1])
       else:
           schema_type = Int64TensorType([None, 1])
       schema.append((col, schema_type))
   return schema


def save_onnx(model: Pipeline, schema: List[Tuple], file_path: str) -> None:
   """
   Save a model to ONNX format.
   Args:
       model: trained model
       schema: schema
       file_path: path to save the model
   Returns:
       None
   """
   gs_prefix = 'gs://'
   gcsfuse_prefix = '/gcs/'
   if file_path.startswith(gs_prefix):
     file_path = file_path.replace(gs_prefix, gcsfuse_prefix)
   if not os.path.exists(os.path.dirname(file_path)):
       os.makedirs(os.path.dirname(file_path))

   onnx_model = convert_sklearn(model, initial_types=schema)
   serialized_model = onnx_model.SerializeToString()
   with open(file_path, "wb") as f:
       f.write(serialized_model)
   f.close()

if __name__ == "__main__":

   # Read data
    print("Reading data...")
    df = read_data(...)

   # Build pipeline
    print("Building pipeline...")
    pipeline = build_pipeline(...)

    # Train
    print("Training...")
    train_pipe = train(...)

   # Save model
   print("Saving model...")
   schema = get_schema(x_train)
   save_onnx(train_pipe, schema, model_path)
   print("Done!")

Обратите внимание, что skl2onnx имеет метод convert_sklearn, который создает эквивалентную модель ONNX данной модели scikit-learn. convert_sklearn требует, чтобы пользователь вручную определял имя и типы ввода. Также этот метод позволяет указать opset (набор операторов), обеспечивающий совместимость во время выполнения. Операторы имеют версии с точки зрения представлений (IR) и времени выполнения, и вы можете добавить метаданные модели, включая имя и документацию для созданной модели ONNX.

Создав представление ONNX ModelProto, вы можете использовать ONNX Runtime (ORT) для обслуживания своей модели. На момент написания статьи Vertex AI не поддерживал предварительно созданный обслуживающий контейнер ONNX. Итак, вам нужно создать собственный контейнер, совместимый с Vertex AI.

Во-первых, вы кодируете сервер. Ниже вы можете увидеть простой пример использования ONNX Runtime и Fast API.

# Libraries
import os
from typing import List
import numpy as np
from onnxruntime import InferenceSession
from fastapi import FastAPI
from pydantic import BaseModel

# Variables
MODEL_PATH = "/app/model.onnx"
AIP_HEALTH_ROUTE = os.environ['AIP_HEALTH_ROUTE']
AIP_PREDICT_ROUTE = os.environ['AIP_PREDICT_ROUTE']

# initiate serving server
app = FastAPI(title="Serving Model")


# represent data point
class Person(BaseModel):
   age: int
   workclass: str
   fnlwgt: int
   education: str
   education_num: int
   marital_status: str
   occupation: str
   relationship: str
   race: str
   sex: str
   capital_gain: int
   capital_loss: int
   hours_per_week: int
   native_country: str

# represent records
class Records(BaseModel):
   instances: List[Person]


# load model
@app.on_event("startup")
def load_inference_session():
   global sess
   sess = InferenceSession(MODEL_PATH)


# check health
@app.get(AIP_HEALTH_ROUTE, status_code=200)
def health():
   return dict(status="healthy")

# get prediction
@app.post(AIP_PREDICT_ROUTE)
async def predict(records: Records, status_code=200):
   predictions = []
   for person in records.instances:
       # convert data to numpy array
       data = dict(
           age=np.array([[person.age]]),
           workclass=np.array([[person.workclass]]),
           fnlwgt=np.array([[person.fnlwgt]]),
           education=np.array([[person.education]]),
           education_num=np.array([[person.education_num]]),
           marital_status=np.array([[person.marital_status]]),
           occupation=np.array([[person.occupation]]),
           relationship=np.array([[person.relationship]]),
           race=np.array([[person.race]]),
           sex=np.array([[person.sex]]),
           capital_gain=np.array([[person.capital_gain]]),
           capital_loss=np.array([[person.capital_loss]]),
           hours_per_week=np.array([[person.hours_per_week]]),
           native_country=np.array([[person.native_country]])
       )
       predictions.append(sess.run([], data)[0].tolist())
   return dict(predictions=predictions)

Важно подчеркнуть, что вашему серверу не требуется scikit-learn для создания прогнозов. Это связано с тем, что вы развернули ONNX-представление исходного конвейера с помощью onnxruntime (ORT). Для генерации прогнозов ORT требуется InferenceSession. В InferenceSession ORT организует оптимизированное выполнение ядер операторов через провайдеров, которые содержат набор ядер для конкретной цели выполнения (в данном случае ЦП). После создания экземпляра InferenceSession модель будет готова возвращать прогнозы.

Затем вы можете использовать Artifact Registry и Cloud Build в Google Cloud для создания пользовательского образа контейнера с использованием Dockerfile. Ниже приведен Dockerfile, который я использовал.

FROM python:3.7

COPY requirements.txt .

RUN pip3 install --upgrade pip && \
   pip3 install -r requirements.txt

COPY ./app /app

EXPOSE 8080

CMD ["uvicorn", "app.api:app", "--host", "0.0.0.0", "--port", "8080"]

где в файле требований указаны следующие библиотеки:

numpy==1.21.6
protobuf==3.20.3
onnxruntime==1.13.1
fastapi==0.89.1
uvicorn==0.20.0
pydantic==1.10.4

Затем вы можете использовать эту команду gcloud для создания пользовательского образа контейнера.

gcloud builds submit . --tag=your-region-docker.pkg.dev/your-project/your-repository/scikit-learn-onnx-cpu --machine-type='n1-highcpu-32' --timeout=900s --verbosity=info

После того, как вы создали обслуживающий образ ONNX, вам необходимо создать ресурс модели, загрузив модель в Реестр моделей Vertex AI Model Registry с помощью пользовательского образа контейнера с помощью Vertex AI Python SDK.

model = vertex_ai.Model.upload(
   display_name='sklearn-onnx-model',
   description='A simple Sklearn classifier with ONNX runtime',
   serving_container_image_uri='your-onnx-serving-image',
   serving_container_predict_route='/predict',
   serving_container_health_route='/health',
   serving_container_ports=['8080'],
)

По умолчанию новая версия модели будет создана в Реестре модели Vertex AI.

Наконец, вам нужно создать Конечную точку Vertex AI, чтобы развернуть зарегистрированную модель Vertex AI для онлайн-прогнозирования. Вы можете создать ресурс конечной точки, а затем развернуть модель, или вы можете напрямую использовать метод развернуть ресурса модели, как показано ниже.

endpoint = model.deploy(
   deployed_model_display_name='onnx-classifier',
   traffic_split={"0": 100},
   machine_type='n1-standard-4',
   min_replica_count=1,
   max_replica_count=1,
)

Развертывание модели займет несколько минут. После успешного развертывания модели вы можете вызвать ее для создания прогнозов с помощью метода прогнозирования.

prediction = endpoint.predict(instances)

Ниже вы можете увидеть пример результата предсказания.

Prediction(predictions=[[' <=50K'], [' <=50K']], deployed_model_id='1234567890', model_version_id='1', model_resource_name='projects/my-project-id/locations/my-region/models/1234567890', explanations=None)

Краткое содержание

В этой статье мы рассмотрели, как вы можете использовать ONNX вместе с Vertex AI для развертывания моделей машинного обучения. Использование ONNX на Vertex AI не только упростит процесс развертывания модели, но и позволит обслуживать платформы, изначально поддерживаемые Vertex AI, что сделает платформу еще более открытой и гибкой.

Конечно, при работе с ONNX я столкнулся с некоторыми ограничениями и проблемами. Например, ONNX не поддерживает экосистему библиотеки scikit-learn, такую ​​как Category Encoders, и доступны не все методы scikit-learn. См. документацию для поддерживаемых операций. Вот почему содержание статьи представляет собой первую попытку. Ни один из подходов или общего кода не готов к работе.

Помимо некоторых ограничений на момент написания статьи, идея сделать Vertex AI еще более открытой очень интересна. И многое еще предстоит изучить. Например, вы можете измерить, как ONNX и его оптимизатор повлияют на конечные точки Vertex AI.

А пока, надеюсь, статья была вам интересна. Если это так, хлопайте или оставляйте комментарии. И не стесняйтесь обращаться ко мне в LinkedIn или Twitter для дальнейшего обсуждения или, если у вас есть вопрос о Vertex AI, ознакомьтесь с Инициативой вопросов и ответов Vertex AI.

Спасибо Ли за отзывы и предложения.

Рекомендации

  1. https://en.wikipedia.org/wiki/Open_Neural_Network_Exchange
  2. https://onnx.ai/index.html
  3. https://onnx.ai/onnx/intro/index.html
  4. https://onnxruntime.ai/
  5. https://onnxruntime.ai/docs/reference/compatibility.html
  6. https://odsc.medium.com/interoperable-ai-high-performance-inferencing-of-ml-and-dnn-models-using-open-source-tools-6218f5709071
  7. https://medium.com/geekculture/onnx-in-a-nutshell-4b584cbae7f5
  8. https://medium.com/moonvision/onnx-the-long-and-collaborative-road-to-machine-learning-portability-a6416a96e870
  9. https://towardsdatascience.com/creating-onnx-from-scratch-4063eab80fcd
  10. https://onnx.ai/sklearn-onnx/index.html
  11. https://github.com/onnx/onnx
  12. https://github.com/onnx/optimizer