FastAPI versus BentoML: что лучше для MLOps и почему

FastAPI versus BentoML: что лучше для MLOps и почему

    Что общего у FastAPI с BentoML, чем они отличаются и почему только один из них является полноценным MLOps-инструментом. Смотрим на примере операций разработки и развертывания API сервисов машинного обучения.

    Что общего у FastAPI с BentoML и при чем здесь MLOps

    С точки зрения промышленной эксплуатации, в проектах машинного обучения следует фокусироваться не только и не столько на точности самих алгоритмов Machine Learning. Огромного внимания требует автоматизация рутинных процессов развертывания и сопровождения ML-моделей, что превратилось в целую концепцию под названием MLOps. Поскольку это направление инженерной науки о данных еще довольно молодое, в нем постоянно появляются новые идеи и инструменты. В частности, одним из самых популярных MLOps-средств считается FastAPI – высокопроизводительный веб-фреймворк для создания API с помощью стандартной аннотации типов Python 3.6+. ML-инженеры часто используют его для развертывания своих моделей в качестве сервисов API.

    Впрочем, FastAPI используется не только в ML-проектах. Этот фреймворк отлично подходит для быстрого создания любых REST-приложений на Python. Его дополнительным преимуществом является автогенерация документации API в формате Swagger (открытый стандарт OpenAPI 3) и JSON Schema. Пример создания такого REST API с тестированием методов в Swagger UI мы описывали в этой статье на блоге нашей Школы прикладного бизнес-анализа.

    Возвращаясь к тему MLOps, отметим, что способность FastAPI генерировать документацию поддерживает идеи MLOps, а потому этот фреймворк можно отнести к набору инструментальных средств MLOps-Инженера. Однако, это далеко не единственный инструмент этой категории. Сюда же относится BentoML – открытая библиотека для быстрого создания MVP систем машинного обучения. Она упрощает создание API методов для доступа к обученной ML-модели и совместима со всеми крупными фреймворками: Tensorflow, Keras, PyTorch, XGBoost, scikit-learn и fastai.

    BentoML поддерживает адаптивную микропакетную обработку данных, а также предоставляет функции управления моделью и ее развертывания. BentoML отлично реализует идеи MLOps, позволяя разработчикам ML-моделей использовать лучшие практики DevOps. Специалисты по Data Science и инженеры Machine Learning используют BentoML для ускорения и стандартизации процесса запуска моделей в производство, создавая масштабируемые и высокопроизводительные сервисы машинного обучения. Библиотека поддерживает непрерывное развертывание, мониторинг и сопровождение сервисов в производственной среде. Пример практического использования BentoML мы рассматривали в этом материале.

    Отметим общие функции FastAPI и BentoML с точки зрения MLOps:

    • они оба основаны на Starlette – легковесной ASGI-платформе для создания асинхронных веб-сервисов на Python;
    • автоматическая документация в Swagger UI согласно открытому стандарту OpenAPI 3;
    • асинхронные запросы, что позволяет обрабатывать несколько запросов одновременно, а не выполнять их линейно.

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

    Применение в разработке и развертывании ML-систем

    Создание API в машинном обучении обычно начинается в Jupyter-блокноте или Google Colab. Формат сохраненной модели напрямую влияет на то, как она передается на сервер API. В FastAPI используется сериализованный Python-объект pickle, в котором хранится код ML-модели. Но этот формат очень ограничивает возможности разработчика манипулировать им. Помимо вопросов безопасности и производительности, самой большой MLOps-проблемой Pickle-формата является полное отсутствие контроля версий модели и управления зависимостями. Почему лучше не использовать Pickle-формат для сохранения ML-моделей, мы подробно писали в этой статье.

    На практике даже в небольшом проекте машинного обучения ML-разработчик может создавать десятки или даже сотни моделей и хранить их в реестре с версионированием. Однако, организовать удобный для использования реестр моделей, сохраненных в Pickle-формате, почти невозможно.

    В BentoML есть стандартная процедура сохранения и загрузки моделей на основе среды, в которой они были обучены. А если модели не являются отдельными файлами и имеют зависимости, которые также следует сохранить, в BentoML можно использовать параметры custom_objects и метаданные для сохранения дополнительных объектов и информации о модели:

    import bentoml
    bentoml.keras.save_model(
        "cnn16",
        model_cnn,
        metadata={"desc": "CNN architecture with 16 starting filters", "owner": "Bex"},
        custom_objects={"model_history": history_object["history"]},
    )

    После вызова функции save_model(), BentoML сохраняет их в локальном реестре моделей, который находится по адресу ~/bentoml/models. Команда list выведет содержимое этого каталога:

    $ bentoml models list
    Tag                     Module         Size        Creation Time        Path
    cnn16:2uo5fkgxj27exuqj  bentoml.keras  5.81 KiB    2022-12-19 08:36:52  ~/bentoml/models/cnn16/2uo5fkgxj27exuqj
    cnn16:nb5vrfgwfgtjruqj  bentoml.keras  5.80 KiB    2022-12-19 21:36:27  ~/bentoml/models/cnn16/nb5vrfgwfgtjruqj

    Даже если модели сохраняются под одним и тем же именем, им присваиваются уникальные идентификаторы. Выбрав лучшую модель из реестра, ею можно поделиться, экспортировав в единый формат архива .bentomodel, независимо от структуры модели:

    $ bentoml models export cnn:version_tag .

    Аналогично можно импортировать любую ML-модель в архив .bentomodel со всеми ее пользовательскими объектами и метаданными, добавив ее в свой собственный реестр моделей. Впрочем, BentoML не только упрощает и автоматизирует управление реестром моделей, но и облегчает работу с входными и выходными данными API.

    REST API обычно работают с данными в формате JSON, который не очень подходит для упаковки векторов машинного обучения. Предположим, ML-модель обучена на датасете с четырьмя фичами. Ее форматы ввода/вывода в FastAPI будут выглядеть так:

    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel
    import numpy as np
    import pickle
    
    app = FastAPI()
    
    class Input(BaseModel):
       feature_1: float
       feature_2: float
       feature_3: float
       feature_4: float
    
    class Output(BaseModel):
       prediction: float

    FastAPI использует Pydantic для проверки данных. Это означает, что фреймворк выдаст ошибку, если форма ввода и типы данных не соответствуют входному классу. Но когда ML-модель имеет сотню фичей для обучения, определить структуру таких больших массивов NumPy или DataFrames в классах Python почти невозможно.

    В BentoML проверка входных данных массива NumPy выполняется следующим образом:

    import bentoml
    from bentoml.io import NumpyNdarray
    
    
    runner = bentoml.sklearn.get("model_name:latest").to_runner()
    
    svc = bentoml.Service("classifier", runners=[runner])
    
    # The important part 
    @svc.api(input=NumpyNdarray(), output=NumpyNdarray())
    def classify(input_series: np.ndarray) -> np.ndarray:
    
       result = runner.predict.run(input_series)
       return result

    Класс NumpyNdarray проверяет входные данные на соответствие массивам NumPy любой формы в одной строке кода. Чтобы применить к входным данным определенную форму, достаточно указать всего один параметр:

    @svc.api(input=NumpyNdarray(shape=(-1,15), enforce_shape=True), output=NumpyNdarray())

    Предоставление (-1, 15) параметру формы подтвердит, что входные данные имеют как можно больше строк, но всегда 15 фичей. В FastAPI и Pydantic это выглядит сложнее:

    class Input(BaseModel):
       data: List[conlist(item_type=float, min_items=15, max_items=15)]

    В реальности ML-модели работают не только с массивами NumPy: данные, отправляемые в API, могут быть любыми, от датафреймов Pandas до двоичных файлов, таких как изображения или аудио. FastAPI и Pydantic проверяют только стандартные типы данных. А BentoML содержит классы проверки для типов данных, характерных для машинного обучения. Есть даже специальный валидатор MultiPart, который позволяет передавать в модель несколько типов данных. Этот класс особенно полезен в задачах компьютерного зрения, когда для модели Machine Learning надо предоставить изображения и табличные метаданные во время логического вывода.

    Когда скрипт сервиса готов, его необходимо упаковать для развертывания. Проще всего сделать это с помощью Docker, упаковав API в образ, чтобы разместить его в различных операционных системах и облачных средах. Чтобы сделать это в FastAPI, необходимо знать, как создать Dockerfile:

    # Get the Fast API image with Python version 3.7
    FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
    
    # Create the directory for the container
    WORKDIR /app
    COPY requirements.txt ./requirements.txt
    
    # Install the dependencies
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY ./app.py ./
    
    # Copy the serialized model
    COPY ./models/cnn_model.pkl ./models/cnn_model.pkl
    
    # Run by specifying the host and port
    CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80"]

    В BentoML все гораздо проще – в корневом каталоге создается YAML-файл bentofile.yaml со следующим шаблоном:

    service: "service.py:service_name"
    include:
    - "*.py"
    python:
     packages:
      - scikit_learn
      - numpy
      - tensorflow

    В поле include следует указать все файлы, необходимые скрипту сервиса для запуска. В разделе пакеты перечисляются зависимости проекта. Далее следует вызвать bentoml build на терминале:

    $ bentoml build

    И команда сборки упакует весь проект в автономный архив внутри локального хранилища Bento. Чтобы преобразовать архив в Docker-образ, достаточно выполнить всего 1 команду:

    $ bentoml containerize model_name:latest

    Теперь можно развернуть полученный Docker-образ в любой среде. Работа FastAPI на этом заканчивается – фреймворк помогает создать API, но не развернуть его. В BentoML есть специальная вспомогательная библиотека под названием bentoctl, которая позволяет развертывать контейнерные API на любой облачной платформе (AWS, GCP, Azure, Heroku). Например, для развертывания ML-модели из реестра в AWS SageMaker потребуется всего несколько команд:

    $ pip install bentoctl terraform
    $ bentoctl operator install aws-sagemaker
    $ export AWS_ACCESS_KEY_ID=REPLACE_WITH_YOUR_ACCESS_KEY
    $ export AWS_SECRET_ACCESS_KEY=REPLACE_WITH_YOUR_SECRET_KEY
    $ bentoctl init
    $ bentoctl build -b model_name:latest -f deployment_config.yaml
    $ terraform init
    $ terraform apply -var-file=bentoctl.tfvars -auto-approve

    Как мы недавно отмечали, большинство современных ML-моделей использует графические процессоры для рабочих нагрузок. Особенно это характерно для проектов глубокого обучения. Поэтому рекомендуется создавать Docker-образ, поддерживающий ускорение GPU. Но, чтобы запустить логический вывод на графическом процессоре, необходима библиотека CUDA от NVIDIA, установить которую не так-то просто из-за наличия множества версий под разные ML-фреймворки (TensorFlow, PyTorch или XGBoost).

    В FastAPI для установки CUDA на Docker-образ нужен большой Dockerfile:

    FROM nvidia/cuda:11.2.0-runtime-ubuntu20.04
    
    # install utilities
    RUN apt-get update && \
       apt-get install --no-install-recommends -y curl
    
    ENV CONDA_AUTO_UPDATE_CONDA=false \
       PATH=/opt/miniconda/bin:$PATH
    RUN curl -sLo ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-py38_4.9.2-Linux-x86_64.sh \
       && chmod +x ~/miniconda.sh \
       && ~/miniconda.sh -b -p /opt/miniconda \
       && rm ~/miniconda.sh \
       && sed -i "$ a PATH=/opt/miniconda/bin:\$PATH" /etc/environment
    
    # Installing python dependencies
    RUN python3 -m pip --no-cache-dir install --upgrade pip && \
       python3 --version && \
       pip3 --version
    
    RUN pip3 --timeout=300 --no-cache-dir install torch==1.10.0+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable/
    
    COPY ./requirements.txt .
    RUN pip3 --timeout=300 --no-cache-dir install -r requirements.txt
    
    # Copy model files
    COPY ./model /model
    
    # Copy app files
    COPY ./app /app
    WORKDIR /app/
    ENV PYTHONPATH=/app
    RUN ls -lah /app/*
    
    COPY ./start.sh /start.sh
    RUN chmod +x /start.sh
    
    EXPOSE 80
    CMD ["/start.sh"]

    В BentoML установить CUDA так же просто, как добавить одно поле в bentofile.yaml:

    service: "service.py:service_name"
    include:
    - "*.py"
    python:
    packages:
    - torch
    - torchvision
    - torchaudio
    docker:
    distro: ubuntu
    python_version: "3.8.12"
    cuda_version: "11.6.2"

    Затем следует снова запустить команду containerize:

    $ bentoml containerize model_name:latest

    Фреймворки PyTorch и TensorFlow позволяют группировать входные данные, используя векторизацию для одновременного выполнения операций с несколькими входами благодаря специальной аппаратной структуре современных графических процессоров. Чтобы наилучшим образом использовать GPU после успешной установки CUDA, инфраструктура API должна разрешать автоматическую группировку входных данных, чего не делает FastAPI. А в BentoML эту функцию можно включить с помощью одного параметра при сохранении моделей, поддерживающих пакетную обработку:

    bentoml.pytorch.save_model(
       name="my-model",
       model=model,
       signatures={
           "__call__": {
               "batchable": True,
               "batch_dim": (0, 0),
           },
       },
    )

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

    Как применять эти и другие средства MLOps в проектах аналитики больших данных и машинного обучения, вы узнаете на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

    Источники

    1. https://pub.towardsai.net/bentoml-vs-fastapi-the-best-ml-model-deployment-framework-and-why-its-bentoml-f0ed26cae88d
    2. https://www.bentoml.com/
    3. https://fastapi.tiangolo.com/