Введение

Специалисты по данным и инженеры данных часто выполняют такие задачи, как разработка и проверка моделей машинного обучения в изолированных средах, таких как ноутбуки Jupyter и Google Colab. Однако возникает проблема, когда им нужно поделиться этими моделями с коллегами из других команд удобным и доступным способом. Хотя существует множество решений для решения этой проблемы, они могут сбивать с толку специалистов по данным, которые могут не разбираться в развертывании своих решений в виде веб-приложений. К счастью, Python предлагает комплексную экосистему для моделирования и развертывания кода с использованием веб-технологий.

Учитывая многочисленные варианты развертывания API-интерфейсов машинного обучения, я решил описать подход, который позволяет мне быстро преобразовать простую модель в API и поделиться ею как веб-приложением. В качестве примера я продемонстрирую развертывание модели классификации изображений в виде Flask API. Это будет включать использование Gunicorn в качестве интерфейса шлюза веб-сервера, Nginx в качестве обратного прокси-сервера и Docker в качестве решения для упаковки всех этих ресурсов в развертываемое решение.

В этом первом руководстве рассматривается обертывание веб-приложения Python вокруг модели машинного обучения.

Требования

Основными компонентами этого проекта являются:

  • Flask: облегченный фреймворк для веб-разработки на Python, который позволяет настроить веб-приложение без особых заморочек. В Flask довольно просто погрузиться, так как он не требует обширного списка зависимостей или потребностей в настройке, и мы можем довольно быстро создать простой API.
  • Gunicorn: (сокращение от Green Unicorn) — это интерфейс шлюза веб-сервера — часть программного обеспечения, позволяющая масштабируемым и надежным образом обслуживать веб-приложение Python в производственной среде. Gunicorn — это сервер приложений, который находится между веб-сервером (обращенным к клиенту) и логикой приложения. Он контролирует такие вещи, как обработка нескольких входящих запросов и управление несколькими процессами одного и того же приложения.
  • Nginx:высокопроизводительный веб-сервер с открытым исходным кодом, который действует как прокси-сервер перед нашим сервером приложений Gunicorn, перенаправляя ему только релевантные запросы. В то время как мы будем разрабатывать относительно простое приложение, Nginx действительно сияет в случаях, когда мы можем ожидать большое количество одновременных запросов, и у нас есть сложное приложение, взаимодействующее с несколькими серверами. Nginx является основным продуктом в производственных развертываниях для веб-приложений, выступая в качестве первой точки контакта для клиентского запроса к приложению.
  • Docker: мощный инструмент для упаковки приложения со всеми его зависимостями в автономный модуль (называемый контейнером). Контейнеры служат независимыми единицами программного обеспечения, содержащими как наш код, так и его операционную среду, что позволяет нам последовательно и надежно запускать наше приложение в различных средах, не беспокоясь о таких вещах, как конфликты зависимостей и проблемы совместимости.

Установка и среда

Прежде чем конкретизировать детали приложения, первым шагом будет настройка среды для его создания. Я использую машину с Ubuntu, поэтому следующие команды сосредоточены вокруг терминала на базе Linux.

Создайте новый каталог для нашего проекта, а затем виртуальную среду, чтобы изолировать его. Я использую библиотеку Python virtualenv среди множества доступных вариантов. Виртуальная среда дает нам песочницу для разработки нашего проекта и размещения его зависимостей, не беспокоясь о возможных конфликтах с пакетами в других средах на нашей машине. Мы можем установить virtualenv с помощью pip с помощью команды pip install virtualenv.

mkdir image_classifier_flask && cd image_classifier_flask
virtualenv venv

Активировать виртуальную среду

source venv/bin/activate

В оболочке Windows среду можно активировать следующим образом.

venv/scripts/activate

Установите зависимости проекта с помощью pip. Список зависимостей доступен в файле requirements.txt в Git-репозитории этого проекта, но в основном нам нужны Flask, tensorflow и numpy.

В нашем основном каталоге проекта мы создаем новый каталог с именем app и в файле Python (который я удачно назвал app.py) настраиваем приложение Flask.

В приведенном выше коде показана минимальная настройка для запуска и запуска приложения Flask на нашем локальном компьютере. Мы создаем экземпляр Flask с именем server, используя server = Flask(__name__). Синтаксис Flask использует декораторы для добавления веб-функций к функциям для выполнения своих задач. route() decorator сообщает Flask, какой URL-адрес должен запускать нашу домашнюю функцию, которая в данном случае является маршрутом по умолчанию или базовым маршрутом для нашего приложения. Мы указываем, что приложение должно работать в режиме отладки, указав debug=True в методе run() для просмотра сообщений об ошибках и предупреждений — очень полезно на этапе разработки нашего проекта.

Чтобы убедиться, что все работает, запустите приложение.

python app.py

Мы должны увидеть аналогичный вывод на нашем терминале, как показано на следующем рисунке. Приложение Flask работает на локальном хосте через порт 5000 (по умолчанию). Мы можем перейти по URL-адресу, указанному в терминале (например, http://localhost:5000/), и проверить, запущено ли приложение.

Закончив проверку, можно переходить к разработке модели.

Разработка модели машинного обучения

Для этого проекта я создам API для классификации изображений и опишу шаги по его развертыванию в виде простого интерактивного веб-приложения, через которое пользователь может загрузить изображение, чтобы получить его категориальную классификацию и точность предсказания. Вместо создания собственной модели с нуля я буду использовать предварительно обученную модель классификации изображений под названием VGG16; сверточная нейронная сеть, состоящая из 16 слоев свертки и максимального объединения. Он способен классифицировать изображения из 1000 различных категорий с точностью около 92,7 %. Модель поставляется с API глубокого обучения Keras, что упрощает процесс ее настройки.

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

Создайте новый каталог с именем models в каталоге вашего приложения — он будет использоваться для хранения созданной вами модели. Создайте файл save_model.py, в котором вы сохраните особенности вашей модели. Несмотря на то, что существует несколько способов структурировать ваш проект для разделения сценариев и моделей, я буду хранить эти ресурсы в одном каталоге для простоты.

В save_model.py мы просто загружаем модель VGG16 с предварительно обученными весами 'imagenet' и сохраняем модель в каталоге models под псевдонимом my_model. . Запустите save_model.py из каталога приложения, и после запуска кода вы должны увидеть каталог my_model. Ваш каталог должен выглядеть примерно так:

Каталог модели состоит из ее более мелких деталей, таких как ее архитектура, веса и информация о компиляции.

Следующим шагом является определение функциональности для загрузки модели классификатора и создания прогнозов. Создайте файл classifier.py в каталоге вашего приложения.

Функция get_model просто загружает модель из артефакта, сохраненного с помощью save_model.py, и возвращает экземпляр модели Keras.

Функция make_prediction определяет шаги предварительной обработки, необходимые для подачи входных данных в модель, и вызывает модель для возврата меток прогноза и оценок. Шаги следующие.

  • Входные данные file_obj представляют собой объект bytes, представляющий данные файла. Мы преобразуем объект bytes в объект io.BytesIO, представляющий буфер в памяти, поэтому первый аргумент функции load_img ведет себя как файл, из которого можно читать.
  • Входной размер по умолчанию для изображения для модели классификации составляет 224 x 224 (ширина x высота), поэтому мы устанавливаем его в качестве целевого размера.
  • Функция load_img считывает данные файла как изображение PIL (Python Imaging Library), поэтому мы используем img_to_array для преобразования изображения в пустой массив формы (ширина, высота, канал).
  • Мы используем expand_dims, чтобы добавить дополнительное измерение к оси 0, чтобы соответствовать входным требованиям модели (1,244,244,3).
  • tf.keras.applications.vgg16.preprocess_input реализует дополнительные шаги предварительной обработки, чтобы подогнать данные под модель VGG16.
  • tf.keras.applications.vgg16.decode_predictions декодирует прогноз модели VGG16, преобразуя вероятности прогноза, возвращенные model.predict(), в возвращаемые удобочитаемые метки классов и оценки прогнозов.
  • Наконец, мы возвращаем имя класса и оценку класса в виде кортежа.

Когда код модели классификации завершен, мы можем перейти к работе над веб-приложением.

Фляжное приложение

Внешний интерфейс

Внешний интерфейс, использующий Bootstrap, используется для взаимодействия пользователя с Flask API. Он состоит из HTML-формы, содержащей параметр ввода файла, с помощью которого пользователь может загрузить файл изображения (png, jpg, jpeg). Код JavaScript с использованием Fetch API используется для отправки данных формы и возврата метки класса и оценки прогноза из модели.

Сначала мы создаем папку templates в каталоге нашего приложения, в которой будут храниться наши HTML-документы. По умолчанию Flask проверяет этот каталог, когда мы вызываем render_template, чтобы вернуть указанный шаблон. Создайте файл с именем index.html в каталоге шаблонов и скопируйте код из index.html в репозиторий Git. Этот файл предоставит основной внешний интерфейс для логики нашего приложения.

Классы Bootstrap используются для стилизации внешнего интерфейса, поскольку они обеспечивают относительно простой способ сделать наш внешний вид несколько приличным и структурированным, не переборщив с CSS.

Суть внешнего кода содержится в части ‹script› файла index.html.

Прослушиватель событий прикреплен к элементу формы, который запускает функцию, как только форма отправляется. Данные загруженного файла берутся, и делается запрос к конечной точке «/upload», обработчик которой будет присутствовать в нашем бэкэнд-коде. Запрос выполняется с использованием JavaScript Fetch API, который отправляет данные файла в указанную конечную точку и ожидает ответа, содержащего прогноз класса и оценку. Соответствующие данные впоследствии извлекаются из ответа JSON и добавляются к элементам отображения на веб-странице, чтобы показать пользователю метку прогноза и оценку.

Бэкэнд

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

  • Мы устанавливаем переменную ALLOWED_EXTENSIONS, состоящую из допустимых форматов файлов изображений. Функция allowed_file использует эту переменную для проверки правильности загружаемого типа файла.
  • Для домашней функции мы используем метод render_template Flask для возврата HTML-файла, определенного в нашем каталоге шаблонов (index.html), выступающего в качестве пользовательской части веб-приложения, которую можно использовать для взаимодействия с ML API.
  • Мы добавляем функцию для обработки другого маршрута, называемого upload, который занимается извлечением данных из загруженного файла и использованием модели классификации для прогнозирования его содержимого. После некоторых проверок на наличие отсутствующих и пустых файлов мы погружаемся в основную часть обработчика загрузки.
if file and allowed_file(file.filename):
       file_obj = file.read()
       model = get_model()
       (class_name, class_score) = make_prediction(model, file_obj)
       msg = {
           "class_name": class_name,
           "class_score": class_score
       }
   return {"message": msg}
  • Переменная file содержит данные нашего загруженного файла, обернув их как объект werkzeug.FileStorage. Это класс-оболочка, предоставляемый Flask для обработки входящих данных файла. Мы можем получить доступ к байтовым данным из этой переменной, используя метод read(). Затем мы просто извлекаем модель с помощью get_model и передаем модель и байтовые данные файла методу make_prediction в модуле классификатора. Результирующие прогнозы (имя и оценка) возвращаются в виде объектов JSON для вызова интерфейсного API.

Теперь, когда все готово, мы можем запустить наше приложение в нашей локальной среде (запустив python app.py ) и протестировать его.

Заключение

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

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