Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру 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
').
После запуска получим следующий результат:
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 запущен по адресу http://localhost:8501
. Наше приложение будет выглядеть следующим образом.
В область выбора файла можно перетащить картинку, тогда она загрузиться на сервер и будет показана на странице.
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)
Полный код приложения можно посмотреть в репозитории с исходным кодом для статьи.
Запущенное приложение будет выглядеть так.
Если нажать кнопку "Распознать изображение", то запуститься нейронная сеть и результаты ее работы будут показаны под изображением.
На первом месте по прежнему воздушный лайнер (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 нажать на кнопку "New", а затем в появившемся меню выбрать пункт "Create new app". Откроется страница создания приложения, в котором нужны выполнить три действия:
Ввести имя приложения. Имя должно быть уникально для всех приложений Heroku. Пользователи смогут обращаться к вашему приложению по ссылке виде https://app-name.herokuapp.com. Например, если имя приложения image-classification-demo, то ссылка на приложение будет https://image-classification-demo.herokuapp.com. Heroku подсвечивает введенное имя зеленым, если оно свободно, и красным в противном случае.
Выбрать регион размещения приложения. Регионов доступно всего два, США и Европа. Лучше выбирать тот, который географически ближе к вам. Поэтому я выбрал Европу.
Нажать на кнопку "Create app".
Приложение на платформе 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 CLI. Подробная инструкция есть на сайте Heroku. Установка в Linux:
curl https://cli-assets.heroku.com/install.sh | sh
Установка на macOS:
brew tap heroku/brew && brew install heroku
Для Windows нужно скачать и запустить установочный файл.
Выполняем логин в Heroku CLI. В консоли запускаем команду:
heroku login
После этого откроется окно браузера, в котором нужно будет войти на платформу Heroku. В случае успешного логина появится сообщение о том, что окно браузера можно закрыть и вернуться в командную строку. В консоли также будет написано об успешном выполнении логина.
Подключаем удаленный 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. В облачной платформе наше приложение выглядит следующим образом:
Пользователям можно давать ссылку на наше приложение – https://image-classification-demo.herokuapp.com. При необходимости Heroku позволяет подключить собственный домен для приложения.
Итоги
Итак, мы рассмотрели, как преобразовать Python скрипт классификации изображений в Web-приложение и развернуть его на облачной платформе Heroku. Основные действия, которые необходимо выполнить:
Написать скрипт классификации изображений. Мы использовали библиотеку TensorFlow, но подойдет PyToch или любая аналогичная библиотека.
Преобразовать скрипт в Web-приложение с помощью библиотеки Streamlit.
Создать приложение на облачной платформе Heroku в бесплатном аккаунте.
Создать репозиторий Git для развертывания приложения, добавить в него конфигурационные файлы, необходимые Heroku.
Подключить репозиторий Git к приложению на Heroku и выполнить развертывание командой
git push.
Передать ссылку на развернутое приложение пользователям.
В следующей части мы рассмотрим, как развертывать созданное нами Web-приложение классификации изображений через Docker.
Магистратура Инженерия искусственного интеллекта
Если вам интересно создавать приложения, использующие модели машинного обучения, и развертывать их для продуктивного применения пользователями, приглашаем в новую магистратуру Уральского федерального университета "Инженерия искусственного интеллекта".
В этой магистратуре мы учим создавать крупные программные системы, использующие машинное обучение. Основные курсы магистратуры в двух областях:
Машинное обучение: математические основы, классические алгоритмы, глубокие нейронные сети, компьютерное зрение, обработка естественного языка, анализ временных рядов.
Промышленная разработка программного обеспечения: Python, Linux, программная инженерия, DevOps, MLOps.
В магистратуре вы будете работать над проектами от компаний-партнеров. В случае успешного выполнения проекта есть шанс устроиться на работу прямо во время обучения в магистратуре.
Социальные сети магистратуры цифровых профессий УрФУ:
Телеграм канал.
Сообщество VK.
Пишем о программах магистратуры в области ИТ, кибербезопасности и радиоэлектроники: как поступить, как подготовиться к экзаменам, как перейти в ИТ с помощью магистратуры.
Полезные ссылки
Предварительно обученная нейронная сеть EfficientNetB0.
Использование предварительно обученных нейронных сетей в TensorFLow и Keras.
Библиотека Streamlit.
Репозиторий с исходными кодами статьи.
Облачная платформа Heroku.
Приложение классификации изображений, развернутое на платформе Heroku.
Магистратура УрФУ "Инженерия искусственного интеллекта".
Телеграм канал "Магистратура ИРИТ-РТФ УрФУ".
Сообщество "Магистратура ИРИТ-РТФ УрФУ" в VK.