С момента запуска 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.
Спасибо Ли за отзывы и предложения.
Рекомендации
- https://en.wikipedia.org/wiki/Open_Neural_Network_Exchange
- https://onnx.ai/index.html
- https://onnx.ai/onnx/intro/index.html
- https://onnxruntime.ai/
- https://onnxruntime.ai/docs/reference/compatibility.html
- https://odsc.medium.com/interoperable-ai-high-performance-inferencing-of-ml-and-dnn-models-using-open-source-tools-6218f5709071
- https://medium.com/geekculture/onnx-in-a-nutshell-4b584cbae7f5
- https://medium.com/moonvision/onnx-the-long-and-collaborative-road-to-machine-learning-portability-a6416a96e870
- https://towardsdatascience.com/creating-onnx-from-scratch-4063eab80fcd
- https://onnx.ai/sklearn-onnx/index.html
- https://github.com/onnx/onnx
- https://github.com/onnx/optimizer