Узнайте, как развернуть оболочку API вокруг модели машинного обучения.

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

В этой статье будут рассмотрены основы развертывания вашей модели с помощью FastAPI и Azure. Некоторые более мелкие детали намеренно не рассматриваются (см. раздел «Предостережения» в конце), но к концу вы сможете быстро развернуть «грязную» оболочку для модели в Azure, используя базовую CI/CD.

Структура проекта

Структура проекта следующая. Различные файлы будут объяснены на протяжении всей статьи, но также доступен полный репозиторий github (ссылка в конце).

Моделирование

Обнимание лица Токенизатор и загрузка модели

Сначала нам нужна модель для развертывания. Библиотека Hugging Face Transformers позволяет быстро и легко загрузить предварительно обученную модель. Модель представляет собой модель классификации тональности, которая должна возвращать положительное, отрицательное или нейтральное значение в зависимости от классифицированной тональности текстовой строки. Для получения более подробной информации см. документы twitter roberta base на Hugging Face.

Код для загрузки модели вынесен в отдельный файл setup_model.py следующим образом:

Сначала мы импортируем токенизатор и модель классификатора последовательности из библиотеки преобразователей. Эта конкретная модель имеет несколько разных моделей/вариантов использования: настроение указывается для построения строки модели, а затем загружает предварительно обученный токенизатор и модель, чтобы вернуть ее в виде кортежа. Каталог кеша переопределен, чтобы файлы всегда были под рукой в ​​каталоге нашего проекта.

Затем создание экземпляра модели так же просто, как вызов этой функции. Мы сохраняем метки в списке для последующего использования:

Предварительная обработка текста

Как определено в документации по модели, перед выполнением вывода модели требуется простая предварительная обработка. Эта функция была предоставлена ​​в документации, слегка изменена для наших целей и сохранена в preprocess_helpers.py:

Вывод модели

Чтобы выполнить вывод модели на основе предоставленного пользователем списка строк, мы сначала предварительно обрабатываем каждую текстовую строку и используем токенизатор для кодирования ввода текста (заполнение примечаний включено, а 'pt' используется для возврата PyTorch тензоры). Затем закодированные входные данные обрабатываются моделью PyTorch, функцией softmax для нормализации вероятностей и преобразуются в объект списка Python. Наконец, создается выходной словарь, который объединяет входной список текстовых строк с оценками, а также добавляет удобные текстовые метки.

Этот код сформирует существенную основу API основного поста, созданного на следующем шаге.

FastAPI

FastAPI — это фреймворк API Python, который позволяет создавать API в первую очередь с помощью подсказок типов и декораторов функций. Эти концепции, вероятно, уже знакомы специалистам по обработке и анализу данных, поэтому освоить их может и любитель, и практик.

Схемы запросов и ответов

Чтобы формализовать, как данные должны быть получены и возвращены API, FastAPI использует pydantic. Это позволяет указать типы данных для каждого свойства, а также автоматически генерирует полезные документы API.

TextClassificationInput определяет, как API ожидает получать данные. Список строк соответствует нашему конвейеру логического вывода, определенному на этапе моделирования.

ResponseDict определяет, как API будет возвращать данные вызывающей стороне. В данном случае вложенный словарь — внешний слой output для обеспечения большей гибкости в последующих улучшениях, который имеет входные строки как вложенные ключи и метки: оценки как различные свойства внутри. Наконец, использование вложенного класса конфигурации с определенной схемой позволяет отображать пример в документации.

Оба они хранятся в файле api_schemas.py:

Базовая безопасность ключа API

Возможны различные схемы безопасности, но в этом примере для аутентификации будет использоваться простой ключ API, отправленный в заголовке запроса. FastAPI предоставляет функцию APIKeyHeader в модуле безопасности, а x-api-key передается в имени. Функция проверяет значение, переданное пользователем, чтобы убедиться, что оно находится в предварительно одобренном списке, и возвращает неавторизованную ошибку, если нет. Затем эту вспомогательную функцию можно использовать в нашем основном определении API — везде, где конечная точка зависит от этой функции, потребуется пройти аутентификацию с использованием x-api-key в заголовке с допустимым ключом.

Примечание. Скорее всего, этого недостаточно. См. раздел с предостережениями в конце. Динамические токены, наряду с ограничениями трафика, обеспечивают лучшую безопасность. Для этого примера подойдет простая авторизация через API.

Код security.py выглядит следующим образом:

Основной файл API

Теперь пришло время связать все это вместе. Импорт библиотеки, наряду с вышеуказанными модулями, определяется следующим образом:

Инициализируется объект приложения и загружается токенизатор + модель:

Определить конечную точку в FastAPI так же просто, как использовать декоратор. Например, если мы хотим вернуть простой ответ hello world по корневому пути, мы можем сделать что-то вроде этого:

В нашем примере мы хотим выполнить вывод модели, если используется правильный ключ API:

Этот код такой же, как мы создали на предыдущих шагах, со следующими ключевыми моментами:

  1. app.post: этот декоратор определяет функцию, которую можно вызвать с помощью запроса API POST. Примечание в декораторе. Мы определяем путь, /score/,, а также ответ, определенный с помощью pydantic.
  2. input_data: этот параметр передается пользователем, выполняющим вызов API. Схема также определяется pydantic из предыдущего шага. api_key использует зависимость от функции безопасности, которая проверяет действительные токены.
  3. метод возврата: просто возвращая наш dict (который соответствует указанной модели ответа), FastAPI преобразует его в действительный ответ с включенным кодом состояния.

Докер

Когда наше приложение определено, как мы можем поместить его в среду для тестирования? Docker позволяет контейнеризовать приложение, упрощая и добавляя гибкости при развертывании. Dockerfile создается на высоком уровне путем выполнения следующих шагов:

  1. Начните с базового образа Python.
  2. Установите зависимости, определенные в файле requirements.txt.
  3. Скопируйте все наши модули (на данный момент это комбинация всего кода Python).
  4. Начните загрузку нашей модели, так как это может занять много времени.
  5. Запустите наше приложение, используя сервер uvicorn.

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

Лазурный

Изображение контейнера

Отлично — контейнер работает локально, но как нам все это развернуть в Azure? С простой точки зрения используется комбинация контейнеров Azure и службы приложений. Что касается контейнерной части, Реестр контейнеров Azure позволяет определять и создавать контейнеры. Для ускорения темпов разработки можно использовать автоматизированный подход CI/CD, основанный на веб-перехватчиках GitHub. В вашем репозитории со всем кодом, включенным на данный момент, в Azure может быть предоставлен персональный токен доступа, чтобы разрешить это автоматическое обновление — всякий раз, когда в репозиторий делается фиксация, в Azure запускается новый контейнер.

Процесс выглядит следующим образом:

  1. Реестр контейнеров Azure: настройте реестр контейнеров Azure через портал Azure. Вам будет предложено выполнить несколько шагов, например, какую группу ресурсов использовать, но настройка проста.
  2. Получить токен личного доступа: в GitHub вы можете создать токен личного доступа. Добавление разрешений для кода, состояния фиксации, метаданных и веб-перехватчиков предоставило достаточные разрешения для Azure. Этот код будет использоваться на следующем этапе настройки процесса CI/CD для автоматического создания контейнера в Azure при создании новой фиксации в Git Hub.

После настройки реестра контейнеров и получения личного токена доступа создание задачи можно выполнить через оболочку Azure следующим образом (создание задачи и последующий однократный ее запуск перед автоматическими обновлениями):

Служба приложений

После определения контейнера приложение можно развернуть непосредственно с использованием этого контейнера. При переходе к Службе приложений Azure во время создания можно выбрать контейнер в качестве метода сборки.

Служба приложений позволяет быстро создавать веб-приложения, используя для этого контейнер. Предоставляется URL-адрес, который можно использовать для тестирования вызовов API.

Полезные документы Azure

Я не буду приводить скриншоты для каждого шага настройки реестра контейнеров и службы приложений, так как многие из вариантов интуитивно понятны (и пользовательский интерфейс может быть изменен), но если вы застряли на каком-либо из вышеперечисленных шагов — следующие пошаговые руководства по Azure очень полезны:

  1. Настройка репозитория связанных контейнеров.
  2. Разверните контейнер как веб-приложение.

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

Если все работает так, как ожидалось, вы должны получить ответ, который классифицирует входные тексты с соответствующими вероятностями:

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

От начала до конца мы загрузили предварительно обученную модель Hugging Face, обернули ее в контейнерный API и развернули в Azure, используя базовую CI/CD для итерации. Это далеко не единственный подход! Предостережения ниже…

Предостережения

  1. Не единственный способ. Существуют такие службы, как Azure ML, Databricks и другие, которые справляются со многими техническими задачами (и лучше). Помимо FastAPI существует множество других фреймворков API, которые можно использовать в качестве оболочки API. Наконец, есть сервисы, ориентированные на развертывание глубокого обучения, которые могут лучше подходить для больших моделей и производительности.
  2. Безопасность. Мы использовали простой метод APIKey. Существуют дополнительные проблемы, которые необходимо учитывать, такие как источник трафика, проверка подлинности на основе пользователей, такие службы, как передняя дверца Azure и т. д., чтобы обеспечить лучшую безопасность.
  3. Производительность. Лучшего масштабирования можно достичь с помощью кластеров (с использованием распределенного контейнерного развертывания, такого как служба Azure Kubernetes) или управляемых служб. Балансировщики нагрузки и кэширование также не рассматриваются здесь. Кроме того, в этой настройке используется один экземпляр uvicorn, в то время как установка с несколькими рабочими может увеличить параллелизм.
  4. Вам действительно нужны выводы в реальном времени? Многие проблемы можно решать в пакетном режиме, а не открывать API. В этих случаях этот тип настройки, вероятно, не нужен.
  5. Опыт SWE/Ops. Я определенно не являюсь экспертом в области разработки программного обеспечения или эксплуатации. Я уверен, что есть элементы, которые я пропустил — при необходимости включите опыт SWE/MLE/ML Ops, особенно если это производственное развертывание.

Все примеры и файлы доступны на Github.

Первоначально опубликовано на https://datastud.dev.