Развертывание моделей машинного обучения. Часть первая. Размещаем Web-приложение в облачной платформе Heroku

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

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

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

Классификация изображений с помощью TensorFlow

Для классификации изображений мы будем использовать библиотеку TensorFlow и модель EfficientNetB0, обученную на наборе данных ImageNet. Эта модель умеет распознавать 1000 классов изображений.

EfficientNetB0 – не самая качественная предварительно обученная модель, у нее доля правильных ответов (Top-1 Accuracy) составляет 77.1%. Но зато размер у модели очень маленький – всего 29 МБ. Небольшой размер модели важен для нас, т.к. в бесплатном аккаунте Heroku есть ограничения по объему памяти для запуска приложений: не более 512 МБ. Поэтому большие модели можно развертывать только на платном аккаунте. Кроме того, EfficientNetB0 работает достаточно быстро: время распознавания 46 с.

Классифицировать изображение с использованием модели EfficientNetB0 можно с помощью слегка модифицированного кода с сайта Keras:

from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.efficientnet import preprocess_input
from tensorflow.keras.applications.efficientnet import decode_predictions
import numpy as np

# Загружаем предварительно обученную модель EfficientNetB0
model = EfficientNetB0(weights='imagenet')

# Прописываем путь к файлу с изображением
img_path = 'plane.jpg'
# Загружаем изображение в память
# EfficientNetB0 рассчитана на изображения размером 224х224
img = image.load_img(img_path, target_size=(224, 224))
# Выполняем предварительную обработку изображения
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
# Запускаем распознавание
preds = model.predict(x)
# Печатаем ТОП-3 класса с самой большой вероятностью
classes = decode_predictions(preds, top=3)[0]
for cl in classes:
    print(cl[1], cl[2])

Давайте попробуем запустить этот код для распознавания вот такого изображения с самолетом (картинку нужно предварительно сохранить в файл 'plane.jpg').

Источник - https://unsplash.com/photos/gXs-mwiXrhA
Источник - https://unsplash.com/photos/gXs-mwiXrhA

После запуска получим следующий результат:

airliner 0.4786306
wing 0.0591435
warplane 0.03492508

Самая большая вероятность, что на картинке воздушный лайнер (airliner) – 47%. Это правильный ответ. На втором месте крыло (wing) – почти 6%. Крыло на изображении, действительно, есть, и даже не одно, а два. Однако основной объект – это самолет, а не отдельные крылья. Так что второй ответ будем считать неправильным, хотя и достаточно обоснованным. Третий вариант – военный самолет (warplane), вероятность всего 3,4%, что не очень много. Опять же, ответ частично правильный: на картинке самолет, но другого типа – гражданский, а не военный.

Итак, код для определения объектов на изображении работает. Но его нужно запускать из командной строки и каждый раз прописывать путь к изображению прямо в коде. Это делать очень неудобно. Давайте создадим Web-приложение, в которое пользователь может загрузить любую картинку, которую он хочет распознать.

Создание Web-приложения с помощью Streamlit

Быстро преобразовать наш скрипт на Python в Web-приложение можно с помощью бесплатной библиотеки Streamlit, созданной как раз для этих целей. Streamlit позволяет добавлять в скрипт элементы управления, например, загрузчик изображений, и запускать этот скрипт во встроенном Web-сервере.

Для начала нам нужно установить Streamlit с помощью pip:

pip install streamlit

Описание элементов управления в Streamlit выполняется в скрипте на Python. Давайте создадим простое Web-приложение, которое позволяет загрузить изображение.

import io
import streamlit as st
from PIL import Image


def load_image():
    """Создание формы для загрузки изображения"""
    # Форма для загрузки изображения средствами Streamlit
    uploaded_file = st.file_uploader(
        label='Выберите изображение для распознавания')
    if uploaded_file is not None:
        # Получение загруженного изображения
        image_data = uploaded_file.getvalue()
        # Показ загруженного изображения на Web-странице средствами Streamlit
        st.image(image_data)
        # Возврат изображения в формате PIL
        return Image.open(io.BytesIO(image_data))
    else:
        return None

# Выводим заголовок страницы средствами Streamlit     
st.title('Классификация изображений')
# Вызываем функцию создания формы загрузки изображения
img = load_image()

Запуск Web-приложения выполняется командой:

streamlit run app.py

При запуске нужно указать имя скрипта на Python с описанием Web-страницы, в нашем случае app.py. Streamlit запустит встроенный Web-сервер, а в нем – страницу на основе скрипта app.py.

Скриншот запуска streamlit
Скриншот запуска streamlit

Сервер Streamlit запущен по адресу http://localhost:8501. Наше приложение будет выглядеть следующим образом.

Web-приложение Streamlit
Web-приложение Streamlit

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

Загрузка изображения в приложение на Streamlit
Загрузка изображения в приложение на Streamlit

Web-приложение для распознавания изображений

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

def load_model():
    model = EfficientNetB0(weights='imagenet')
    return model

Вторая функция выполняет предварительную обработку изображения для подготовки к распознаванию.

def preprocess_image(img):
    img = img.resize((224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    return x

Третья функция печатает названия и вероятность для ТОП 3 классов, выданных моделью.

def print_predictions(preds):
    classes = decode_predictions(preds, top=3)[0]
    for cl in classes:
        st.write(cl[1], cl[2])

Теперь мы готовы написать код, создающий Web-страницу с помощью Streamlit.

# Загружаем предварительно обученную модель
model = load_model()
# Выводим заголовок страницы
st.title('Классификация изображений')
# Выводим форму загрузки изображения и получаем изображение
img = load_image()
# Показывам кнопку для запуска распознавания изображения
result = st.button('Распознать изображение')
# Если кнопка нажата, то запускаем распознавание изображения
if result:
    # Предварительная обработка изображения
    x = preprocess_image(img)
    # Распознавание изображения
    preds = model.predict(x)
    # Выводим заголовок результатов распознавания жирным шрифтом
    # используя форматирование Markdown
    st.write('**Результаты распознавания:**')
    # Выводим результаты распознавания
    print_predictions(preds)

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

Запущенное приложение будет выглядеть так.

Внешний вид Web-приложения классификации изображений
Внешний вид Web-приложения классификации изображений

Если нажать кнопку "Распознать изображение", то запуститься нейронная сеть и результаты ее работы будут показаны под изображением.

Результаты распознавания объекта на изображении
Результаты распознавания объекта на изображении

На первом месте по прежнему воздушный лайнер (airliner), так что распознавание происходит правильно.

Более подробно о создании Web-приложения распознавания изображений с использованием Streamlit и TensorFlow можно посмотреть в видео.

Итак, у нас получилось создать Web-приложение, в которое можно загрузить произвольную картинку для распознавания. Однако это приложение запускается только на локальном компьютере, его адрес – http://localhost:8501. Это означает, что другие пользователи не смогут подключиться к этому приложению по сети. Чтобы это стало возможным, нужно разместить приложение на каком-либо сервере в Интернет. Для этого хорошо подходят облачные платформы. Далее мы рассмотрим, как разместить наше приложение на облачной платформе Heroku.

Облачная платформа Heroku

Heroku – это облачная платформа PaaS (Platform as a Service), которая предоставляет удобные инструменты для развертывания приложения. Пользователю не нужно самому создавать виртуальную машину, устанавливать ОС, запускать и настраивать Web-сервер. Все это платформа Heroku делает автоматически.

Чтобы развернуть приложение на Heroku нужно просто сделать push в репозиторий Git Heroku. Это очень удобно.

На Heroku есть бесплатные аккаунты, в которых можно использовать 550 часов работы контейнеров (на Heroku контейнеры называются Dyno). У бесплатного аккаунта есть ограничения по ресурсам контейнера:

  • Максимальный объем оперативной памяти: 512 МБ.

  • Максимальный объем образа для контейнера (на Heroku он называется slug): 500 МБ.

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

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

Создание приложения на платформе Heroku

Если у вас еще нет аккаунта на Heroku, то нужно зарегистрироваться. После регистрации и входа вы попадаете в панель управления Heroku (dashboard).

Создание нового приложения на Heroku
Создание нового приложения на Heroku

Чтобы создать новое приложение, нужно в правой верхней части панели управления Heroku нажать на кнопку "New", а затем в появившемся меню выбрать пункт "Create new app". Откроется страница создания приложения, в котором нужны выполнить три действия:

  1. Ввести имя приложения. Имя должно быть уникально для всех приложений Heroku. Пользователи смогут обращаться к вашему приложению по ссылке виде https://app-name.herokuapp.com. Например, если имя приложения image-classification-demo, то ссылка на приложение будет https://image-classification-demo.herokuapp.com. Heroku подсвечивает введенное имя зеленым, если оно свободно, и красным в противном случае.

  2. Выбрать регион размещения приложения. Регионов доступно всего два, США и Европа. Лучше выбирать тот, который географически ближе к вам. Поэтому я выбрал Европу.

  3. Нажать на кнопку "Create app".

Окно создания приложения Heroku
Окно создания приложения Heroku

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

Создание Git репозитория для Web-приложения

Давайте создадим репозиторий Git в том каталоге, где находится наш Python скрипт с Web-приложением. Для этого выполняем команду:

git init -b main

Теперь нужно добавит скрипт с Web-приложением в репозиторий. Пусть скрипт называется image_classification.py, тогда команды будут следующие:

git add image_classification.py
git commit -m "Add image_classification.py"

Репозиторий Git создан и скрипт с Web-приложением зафиксирован в нем. Однако пока репозиторий не готов для развертывания на Heroku. Облачной платформе для успешного запуска нашего приложения требуются дополнительные сведения:

  • Какие библиотеки Python нужны для работы приложения? Heroku установит эти библиотеки в образ для запуска приложения. В Python список библиотек указывается в файле requirements.txt.

  • Как запускать наше приложение? Вручную мы запускали приложение из командной строки с помощью streamlit run. Heroku использует файл с названием Procfile чтобы узнать, как нужно запускать приложение. Именно в него мы и пропишем команду запуска. Также нужно будет добавить дополнительный скрипт на shell, который создает конфигурационные файлы Streamlit для работы в режиме сервера.

Мы начнем с файла requirements.txt. В него нужно записать всего две библиотеки:

streamlit
tensorflow-cpu

Обратите внимание, что мы будем использовать версию TensorFlow с поддержкой только CPU. Во-первых, в контейнерах Heroku нет GPU, поэтому пытаться его применять бессмысленно. Во-вторых, версия TensorFlow с поддержкой GPU занимает значительное место, превышающее размер образа для бесплатного аккаунта на Heroku в 500МБ.

Теперь можно создать bash скрипт, создающий конфигурационные файлы Streamlit. Файл будет называться setup.sh и содержать следующее:

mkdir -p ~/.streamlit/

echo "\
[general]\n\
email = \"ваш@email.com\"\n\
" > ~/.streamlit/credentials.toml

echo "\
[server]\n\
headless = true\n\
port = $PORT\n\
" > ~/.streamlit/config.toml

Первая команда в этом скрипте создает каталог .streamlit в домашнем каталоге пользователя, где и будут храниться настройки Streamlit.

Вторая команда записывает в файл credentials.toml адрес вашей почты. Не забудьте прописать этот адрес в скрипт.

Третья команда создает конфигурационный файл для сервера Streamlit config.toml, в котором две опции:

  • headless = true – при запуске Streamlit не будет открывать новое окно браузера (это поведение Streamlit по умолчанию подходит для персонального компьютера, но не для сервера)

  • port = $PORT – Streamlit будет работать не на порту 8501, как он обычно делает, а на порту, который ему укажет облачная платформа Heroku в переменной окружения $PORT.

Последний файл, Procfile, содержит команду, которую платформа Heroku должна выполнить для запуска нашего приложения:

web: sh setup.sh && streamlit run image_classification.py

web в начале строки говорит Heroku о типе контейнера, в котором должно быть запущено приложение – контейнер для Web приложений. Затем идет команда запуска приложения, которая в нашем случае состоит из двух частей:

  • sh setup.sh – запуск скрипта для создания конфигурационных файлов

  • streamlit run image_classification.py - запуск нашего Web-приложения в Streamlit. Эта команда выполняется только в случае успешного выполнения первой команды (символы &&).

Все три файла есть в репозитории с исходным кодом статьи.

Теперь нам нужно зафиксировать добавление новых файлов в репозитории Git:

git add requirements.txt setup.sh Procfile
git commit -m "Add configs for Heroku"

Сейчас наш репозиторий готов к развертыванию на Heroku!

Развертывание приложения из Git репозитория на Heroku

Инструкция по развертыванию есть на закладке "Deploy" приложения Heroku.

Инструкция по развертыванию приложения на Heroku
Инструкция по развертыванию приложения на Heroku
  1. Устанавливаем Heroku CLI. Подробная инструкция есть на сайте Heroku. Установка в Linux:

    curl https://cli-assets.heroku.com/install.sh | sh

    Установка на macOS:

    brew tap heroku/brew && brew install heroku

    Для Windows нужно скачать и запустить установочный файл.

  2. Выполняем логин в Heroku CLI. В консоли запускаем команду:

    heroku login

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

    Успешная аутентификация в Heroku CLI
    Успешная аутентификация в Heroku CLI
  3. Подключаем удаленный Git репозиторий Heroku.

    heroku git:remote -a image-classification-demo

    Не забудьте заменить image-classification-demo на название вашего приложения на Heroku.

После подключения удаленного репозитория Git на платформе Heroku, развертывание можно выполнять с помощью push в этот репозиторий:

git push heroku main

В результате Heroku запустит сборку образа контейнера для вашего приложения и развернет его по ссылке вида https://application-name.herokuapp.com. В облачной платформе наше приложение выглядит следующим образом:

Приложение классификации изображений, развернутое на платформе Heroku
Приложение классификации изображений, развернутое на платформе Heroku

Пользователям можно давать ссылку на наше приложение – https://image-classification-demo.herokuapp.com. При необходимости Heroku позволяет подключить собственный домен для приложения.

Итоги

Итак, мы рассмотрели, как преобразовать Python скрипт классификации изображений в Web-приложение и развернуть его на облачной платформе Heroku. Основные действия, которые необходимо выполнить:

  1. Написать скрипт классификации изображений. Мы использовали библиотеку TensorFlow, но подойдет PyToch или любая аналогичная библиотека.

  2. Преобразовать скрипт в Web-приложение с помощью библиотеки Streamlit.

  3. Создать приложение на облачной платформе Heroku в бесплатном аккаунте.

  4. Создать репозиторий Git для развертывания приложения, добавить в него конфигурационные файлы, необходимые Heroku.

  5. Подключить репозиторий Git к приложению на Heroku и выполнить развертывание командой git push.

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

В следующей части мы рассмотрим, как развертывать созданное нами Web-приложение классификации изображений через Docker.

Магистратура Инженерия искусственного интеллекта

Если вам интересно создавать приложения, использующие модели машинного обучения, и развертывать их для продуктивного применения пользователями, приглашаем в новую магистратуру Уральского федерального университета "Инженерия искусственного интеллекта".

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

  • Машинное обучение: математические основы, классические алгоритмы, глубокие нейронные сети, компьютерное зрение, обработка естественного языка, анализ временных рядов.

  • Промышленная разработка программного обеспечения: Python, Linux, программная инженерия, DevOps, MLOps.

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

Социальные сети магистратуры цифровых профессий УрФУ:

  • Телеграм канал.

  • Сообщество VK.

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

Полезные ссылки

  1. Предварительно обученная нейронная сеть EfficientNetB0.

  2. Использование предварительно обученных нейронных сетей в TensorFLow и Keras.

  3. Библиотека Streamlit.

  4. Репозиторий с исходными кодами статьи.

  5. Облачная платформа Heroku.

  6. Приложение классификации изображений, развернутое на платформе Heroku.

  7. Магистратура УрФУ "Инженерия искусственного интеллекта".

  8. Телеграм канал "Магистратура ИРИТ-РТФ УрФУ".

  9. Сообщество "Магистратура ИРИТ-РТФ УрФУ" в VK.

Источник: https://habr.com/ru/post/664076/


Интересные статьи

Интересные статьи

В предыдущей статье мы познакомились с общей идеологией симуляции при согласовании импедансов на примере бесплатного ПО. Посмотрим теперь, каких результатов можно ожидать от пакетов, которые использу...
Поведение генераторов, описанное в предыдущей статье, нельзя назвать сложным, но оно точно удивляет и поначалу может выглядеть непонятным. Поэтому вместо изучения новых концепций мы сей...
Данная статья — четвертая в серии. Ссылки на предыдущие статьи: первая, вторая, третья 4.1 Структуры данных Структура данных — это представление того, как организованы отдельные данны...
Здравствуйте. Я уже давно не пишу на php, но то и дело натыкаюсь на интернет-магазины на системе управления сайтами Битрикс. И я вспоминаю о своих исследованиях. Битрикс не любят примерно так,...
Добрый день, друзья. Сегодня мы подготовили для вас перевод первой части статьи «Лямбды: от C++11 до C++20». Публикация данного материала приурочена к запуску курса «Разработчик C++», который ста...