Упаковка системы рекомендаций изображений на основе PostgreSQL / PyTorch с Flask, импорт данных и запуск их на платформе облачных приложений Heroku.

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

Разработанное решение и шаги по развертыванию на Heroku представлены в этой статье, а код доступен на GitHub.

Я установил и выполнил следующие требования для этого проекта

1. Веб-приложение доступно в Интернете.

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

3. Данные для галереи и рекомендации берутся из базы данных.

4. Рекомендации - это наиболее похожие изображения из возможно большого набора изображений. Они должны появиться мгновенно; это означает, что вычисление сходства происходит в автономном режиме.

5. Галерея адаптивна.

6. Приложение Flask правильно упаковано для будущих расширений / повторного использования.

В моем последнем посте уже части требований были реализованы как прототип, в частности 2 и 4. Блокнот Jupyter доступен на GitHub для рекомендателя Resnet18 PyTorch, который принимает изображение в качестве входных данных и выдает наиболее похожие изображения из тот же набор изображений. Чтобы использовать приложение Flask, эту записную книжку следует использовать для создания фреймов данных Pandas, которые хранятся в виде файлов pickle. Они используются в приложении как статический контент.

В этом посте мы покажем, как реализовать все другие требования, как использовать базу данных SQLite локально и PostgreSQL на Heroku, как использовать ее для разбивки на страницы, как очистить работу и развернуть ее в Heroku, чтобы сделать ее доступной. в Интернете через браузер на ПК или смартфонах.

Вы можете получить доступ и протестировать демонстрационное приложение с несколькими изображениями на Heroku по следующей ссылке:

Этот пост состоит из следующих разделов:

1. Описание возможностей приложения

2. Повторен расчет сходства между изображениями

3. Описана структура упаковки приложения.

4. Представлена ​​модель SQL

5. Представлена ​​логика серверного приложения.

6. Представлены шаблоны.

7. Объясняются все шаги по развертыванию Heroku.

8. Сделан вывод

Обратите внимание, что в этой статье я использовал компьютер с Windows 10 и Python 3.5.4. Я не учел обработку исключений.

1. Особенности приложения

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

Галерея изображений:

Можно просмотреть набор изображений в самописной галерее, показывая все изображения из исходного входного набора (небольшой тестовый набор, созданный из моего личного репозитория изображений), как показано ниже:

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

Разбивка на страницы:

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

Рекомендации по изображениям:

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

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

Отзывчивость:

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

Команды базы данных:

Я подготовил некоторые тестовые данные и использовал словарь, чтобы использовать их в более раннем прототипе. Это повторно используется для команды импорта. Можно использовать консоль для создания или очистки базы данных, а также для импорта данных, описанных в таком словаре. Это работает локально для SQLite, но также и для базы данных PostgreSQL на Heroku. Команды включены как модуль Blueprint.

2. Расчет рекомендаций в автономном режиме

В предыдущей статье я подробно объяснил, как легко создать матрицу сходства и топ-k списков (для каждого изображения k наиболее похожих других изображений). Реализация была представлена ​​отдельным постом. Поэтому ознакомьтесь с этими сообщениями для получения подробной информации.

Что мы делаем вкратце:

  • Предварительная обработка изображений из папки ввода изображений
  • Для каждого изображения создайте векторы признаков с помощью Resnet18 от PyTorch
  • Сравните векторы признаков и сохраните списки топ-k

Это сделано в одной записной книжке Jupyter, где я теперь добавил две строки для хранения фреймов данных с похожими именами изображений и значениями сходства, как в файлах pickle. Они используются в качестве статического содержимого для представленного здесь рекомендательного приложения. Вы можете проверить репозиторий с тестовыми изображениями, и он должен работать без усилий.

Что нам нужно добавить, так это импорт этих результатов - фактических рекомендаций - в базу данных SQL.

Для онлайн-обработки серверный процесс запрашивает только наиболее похожие изображения для рендеринга правильного HTML.

3. Упаковка приложения

Была использована следующая структура приложения:

~/imageRecommender             
     |-- requirements.txt         # All packages to run the app
     |-- Procfile                 # file needed to use gunicorn
     |-- run.py                   # starts the application   
     |-- .flaskenv                # sets environment variables   
     |__ env                      # virtual environment – not in vc
     |__ /imageRecommender        # The application package
          |-- __init__.py         # Application factory method
          |-- config.py           # Configuration file for dev/prod     
          |-- models.py           # Database models 
          |__ /commands           # For import to database
              |-- __init__.py     # Application factory
              |-- commands.py     # Commands for DB creation/import
          |__ /main               # For routes
              |-- __init__.py     # Application factory
              |-- routes.py       # Business logic, fctns for routes   
          |__ /static             # All static data
              |__ /css            # Stlyesheets
              |__ /javascript     # Java Script code for modal
              |__ /pickles        # The top-k lists in pickle format
              |__ /site_imgs      # The images for the app
              |-- favicon.ico     # The favicon
          |__ /templates          # All templates
              |-- home.html       # Home route
              |-- layout.html     # General layout
              |-- recommend.html  # Recommend route

Файлы __init__.py превращают содержащиеся в них папки в модули. Эти модули можно зарегистрировать как Blueprints. Только файл __init__.py на уровне imageRecommender не является пустым в этом приложении.

4. Модель данных

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

3.1. Начало работы с SQL для Flask

Пакет, поддерживающий базы данных SQL, - flask-sqlalchemy, версия 2.4.4 находится в файле requiremets.txt. Таким образом, мы можем импортировать его в приложение на фабрике для фабрики приложений imageRecommender __init__.py.

Мы настраиваем базу данных SQLite для приложения Flask локально и базу данных Postgres (тогда все хранится в одном файле) для Heroku в файле config.py

В зависимости от варианта использования (разработка или производство на Heroku) выбирается правильная конфигурация. Секретный ключ в производственной среде должен быть уникальным в целях безопасности, и необходимо указать URL-адрес базы данных.

3.2. Модель данных

Мы создаем класс для изображений для галереи и связанный класс для рекомендуемых изображений.

Несколько замечаний к этой модели:

  • Идентификаторы id для обеих таблиц устанавливаются автоматически и однозначно по умолчанию.
  • imageName и imageDescription - это строки для метаданных изображений.
  • imageRecs - отношение к рекомендациям, они необходимы для рекомендуемого маршрута.
  • Класс Imagerecommendations содержит связанный идентификатор запрошенного изображения, имя рекомендованного изображения и его значение сходства. Он денормализует нормальную форму по отношению к имени изображения.

Теперь мы можем создать базу данных и импортировать данные.

3.3 Команды базы данных

Есть три простых команды:

  1. сбросить базу данных
  2. создать это
  3. импортировать данные

Приложение упаковано, как описано выше, так что сценарий commands.py имеет доступ к приложению - мы увидим это позже, когда будем говорить о Blueprints.

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

5. Логика серверного приложения

Что такое Flask и как его настроить, уже рассказывалось в прошлой статье.

Решение упаковано в пакет imageRecommender, и мы вызываем его с помощью скрипта run.py.

Метод createApp находится в фабрике приложения __init__.py, и становится полезным работать с ним при расширении приложения, например тестами, для которых требуется несколько экземпляров приложения.

  • Для импорта загружаются конфигурации, которые были описаны ранее. Приложение необходимо создать в этом файле __init__.py через app = Flask (__ name__).
  • После создания объекта переменная среды проверяется для правильного варианта использования и загружается подходящая конфигурация.
  • Создается объект базы данных, и два Blueprints регистрируются для основного приложения и команд базы данных. cli_group = None объединяет команды на уровне приложения, так что их можно просто вызвать с помощью flask ‹имя команды› в консоли Heroku.

main Blueprint содержит основную логику серверного приложения в файле routes.py. Давайте рассмотрим этот файл по шагам:

from flask import render_template, request, Blueprint
from imageRecommender.models import Galleryimages
  • Мы работаем с шаблонами, которые используются для генерации HTML-страниц с помощью пакета render_template.
  • По запросу мы получаем имя выбранного изображения и страницу, на которой мы находимся в галерее.
  • Поскольку мы используем Blueprints для создания модулей приложения, Blueprint импортируется.
  • К запрошенному изображению мы получаем похожие изображения через связанный класс Imagerecommendations, и поэтому мы работаем с нашим классом Galleryimages.
main = Blueprint('Fmain', __name__)
  • Чертеж Fmain зарегистрирован.
@main.route("/")
@main.route("/home")
def home():
    page = request.args.get('page', 1, type=int)
    gImages = Galleryimages.query.paginate(page=page, per_page=8)
    return render_template('home.html', images = gImages)
  • Основной и домашний маршруты дают доступ к галерее.
  • С помощью шаблона home.html мы визуализируем изображения, указанные в вызове render_template.
  • В качестве входных данных он принимает изображения из gImages. Здесь используется функция нумерации страниц. С помощью per_page можно указать, сколько изображений должно отображаться на одной странице галереи, и page - это открываемая страница по умолчанию, в данном случае первая страница галереи с первыми восемью изображений.
@main.route("/recommend")
def recommend():
    selectedImage = request.args.get('selectedImage')
    imageEntry = Galleryimages.query.filter_by(imageName=selectedImage)
    images = []
    values = []
    for image in imageEntry:
         for recommendation in image.imageRecs:
             images.append(recommendation.recommendedName)
             values.append(recommendation.similarityValue)
    return render_template('recommend.html', title='Recommendations', customstyle='recommend.css', inputImage=selectedImage, similarImages=images, similarityValues = values)
if __name__ == '__main__':
    app.run(debug=True)
  • Рекомендуемый маршрут вызывается с соответствующей функцией рекомендации, которая запрашивает selectedImage пользователя.
  • Он запрашивается из нашей базы данных, и мы повторяем все рекомендации из соответствующего класса.
  • Массивы изображений и значений заполняются соответствующей информацией.
  • Вся необходимая информация передается для отображения страницы Recommended.html.

6. Шаблоны

Мы видели два вызова для рендеринга html-страниц из шаблонов:

render_template('home.html', images = gImages)
render_template('recommend.html', title='Recommendations', customstyle='recommend.css', inputImage=selectedImage, similarImages=images, similarityValues = values)

Давайте посмотрим на соответствующие разделы файлов home.html и Recommended.html.

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

<body>
…
{% block content %} {% endblock %}
</body>

Файл home.html используется для галереи.

Он состоит в основном из двух частей:

1. Изображения в галерее, которые повторяются с помощью {% для изображения в images.items%} и

2. Элементы разбивки на страницы в разделе div разбивки на страницы. Здесь самая интересная часть - это метод iter_pages, который позволяет установить, сколько чисел отображается слева и справа, а также в середине блока чисел.

{% для page_num в images.iter_pages (left_edge = 2, right_edge = 2, left_current = 1, right_current = 2)%}

Шаблон рекомендует.html используется для отображения запроса и наиболее похожих изображений:

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

Отзывчивость:

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

@media only screen and (max-device-width : 640px) {

а для содержимого галереи мы установили, например, счетчик столбцов равным единице в этом разделе.

.gallery .galleryContent .item{
    float: left;
    width: 100%;
    height: 100%;
    position: relative;
    cursor: pointer;
    column-count: 1;
}

7. Развертывание Heroku

Файл .flaskenv содержит две записи и работает, когда установлен python-dotenv.

FLASK_APP=run.py
FLASK_ENV=development

так что запуск flask позволяет вам протестировать приложение локально на http: // localhost: 5000 /

Пришло время развернуть пакет и сделать его доступным через Интернет.

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

Следующие шаги протестированы и работают в августе 2020 года на Heroku.com.

Для простого развертывания на Heroku отправьте свой код на GitHub. Создайте репозиторий. Используйте полученный URL-адрес, чтобы отправить репозиторий на GitHub.

Поэтому вам необходимо посетить https://www.heroku.com/ и создать учетную запись с основным языком разработки Python.

Чтобы установить Heroku CLI, следуйте инструкциям на https://devcenter.heroku.com/articles/heroku-cli.

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

В Heroku нажмите «Создать новое приложение». Он просит вас дать ему имя, давайте установим здесь image-Recommender-demo и регион Европа.

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

Когда мы отправили код на GitHub, мы выбираем опцию GitHub, после чего нам нужно «Подключиться к GitHub» и авторизовать Heroku для доступа к вашему репозиторию GitHub.

Далее мы вводим имя соответствующего репозитория image-Recommender-demo, ищем его и подключаемся к нему.

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

Для начала мы развертываем его один раз вручную (для этого нужно нажать еще одну кнопку). Теперь вы можете видеть, как создается ваше решение, и насколько успешно

Вверху сайта вы можете найти кнопку

В данном случае это приводит нас к нашей системе рекомендаций по

Https://image-recommender-demo.herokuapp.com/

До сих пор журналы показывали, что веб-процессы не запущены, поэтому необходимо создать Procfile, который используется Heroku, чтобы понять, как запускать приложение. Он содержит только строку

web: gunicorn run:app

web указывает, что используется веб-работник. Необходим сервер приложений, поэтому используется gunicorn, и его необходимо установить - версия 20.0.4 указана в файле requirements.txt. gunicorn - это команда, необходимая для запуска веб-процесса, чтобы код Python мог взаимодействовать с веб-сервером. run относится к файлу run.py, содержащему объект приложения, app относится к имени объекта приложения.

После фиксации необходимо установить FLASK_ENV. Как уже упоминалось, я использую файл .flaskenv локально. В производстве конфигурация устанавливается вручную через Heroku CLI.

heroku config:set FLASK_ENV=production --app image-recommender-demo

Если вы еще не вошли в систему, Heroku сначала запросит логин.

Теперь при запуске приложения по-прежнему возникает внутренняя ошибка сервера, поскольку база данных еще не настроена.

Мы хотим работать с PostgreSQL. Нажмите «Обзор» в пользовательском интерфейсе Heroku, выберите «Настроить надстройки», найдите «Postgres»; выберите «Heroku Postgres». Я использую бесплатную версию для этой демонстрации.

Теперь эта база данных уже прикреплена к приложению image-Recommender-demo! Теперь вы можете увидеть его в разделе «Настройки», «Переменные конфигурации» с его URL-адресом.

Если psycopg2 еще не был установлен, Heroku снова сообщит нам об ошибке, а журналы покажут, что модуль «psycopg2» не был найден. Следовательно, psycopg2 == 2.8.5 в файле requirements.txt получает правильный пакет.

Таблицы все еще не существуют, поэтому мы все равно увидим ошибку после этой настройки на Heroku.

Чтобы создать недостающие таблицы и импортировать некоторые данные, мы используем команды из файла command.py, описанные ранее.

Мы установим переменную FLASK_APP так, чтобы команды распознавались в Heroku con

heroku config:set FLASK_APP=run.py --app image-recommender-demo

Теперь мы можем вызвать консоль в Heroku и использовать команды, представленные ранее.

flask createDB
flask importDB

Вот и все, приложение развернуто, онлайн, и база данных содержит соответствующие данные!

8. Выводы

С этим и Рекомендательным постом PyTorch у вас будет все под рукой, чтобы

  • Запускать код машинного обучения в автономном режиме и сохранять результаты
  • Создайте веб-приложение на основе Flask
  • Используйте результаты машинного обучения в веб-приложении
  • Используйте базу данных PostgreSQL с Flask
  • Разверните свое приложение в Heroku

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

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

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

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

Спасибо за прочтение! Понравилась тема?

Если вы нашли чтение интересным, возможно, вы захотите ознакомиться с моими предыдущими статьями по теме, на которую распространяется эта статья: