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

Указатель
0. Введение
1. Создание модели
2. Настройка сервера Flask
3. Создание index.html
4. Создание main.js
5. Обновление сервера Flask.

0. Введение
Представим, что вы создали какую-то глубокую и замечательную модель, которая делает отличные вещи и помогает людям. Например, модель предсказывает любимые смайлики человека по фотографии их чашки. Вы размещаете эту модель в Интернете, и ежедневное использование составляет около 1000 запросов, а не много. Простой сервер может справиться с этим, но однажды эта модель была обнаружена широкой публикой, и вы начали получать 100 тыс. Запросов ежедневно, и тот же сервер вероятно, умрет. Итак, теперь вы можете либо масштабировать сервер и добавлять все больше и больше памяти, либо попробовать переписать прогноз на стороне клиента. Если вы выберете второй вариант, это учебное пособие для вас.

Для достижения цели у нас будут следующие компоненты.
Backend: Flask, любая библиотека, которую вы хотите для предварительной обработки изображения в python
Frontend: tensorflowjs
Недавно TensorflowJS добавил поддержку node.js, однако мы будем использовать Flask, который является библиотекой python. . Часто для правильного выполнения некоторых из обученных моделей требуется предварительная обработка данных. Пока предварительная обработка может быть более удобной в python, чем в javascript. (Я надеюсь, что когда-нибудь появится возможность делать предварительную обработку и на стороне клиента)

1. Создание модели
Вы можете обучить модель для MNIST, запустив train_model.py, или вы можете создать и обучить любую модель, какую захотите. Здесь важно сохранить топологию и вес моделей. Если ваша модель написана на keras, просто добавьте это.

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

Где group \ * - shard \ * of \ * - - это набор файлов двоичных весов, а
model.json - - топология и конфигурация модели.

2. Настройка сервера Flask
Потому что мы хотим, чтобы пользователи имели доступ к нашей модели.

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

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

Наша первая версия будет выглядеть так. Единственное, что здесь важно, это строка 6, в которой добавляется tensorflowjs из cdn.
Следующим шагом является добавление некоторого тела HTML, чтобы пользователь мог загружать изображения и нажимать кнопки. :) Вот.

Следующим и последним шагом для нашей части HTML является добавление стиля к нашей странице и, следовательно, перенос классов в элементы HTML, а также создание файла main.js, который будет содержать наша часть волшебного предсказания. Теперь посмотрим на последнюю версию index.html.

Ваш index.html может отличаться от моего, вы также можете добавлять или удалять некоторые части из него, однако здесь важны следующие моменты:
- строка 6 (добавляет скрипт из CDN в голове - плохая практика для производственных версий кода, однако я не хочу никого беспокоить объяснениями, что такое npm и node_modules)
- строка 13 (ввод, если вы хотите, чтобы пользователь загрузил изображение, вы также можете использовать различные типы ввода)
- строка 20 (наш скрипт, который выполняет прогнозирование на стороне клиента)

4. Создание main.js
Пришло время проявить волшебство. Прежде всего нам нужно инициализировать кнопки, ввод, модель и функцию для прогнозирования.

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

Мы отправляем изображения в / api / prepare /, этот маршрут добавим позже. А также мы помещаем ответ сервера из поля изображение в tf.tensor2d.
Теперь пришло время добавить прогноз для нашего тензора, затем визуализировать прогноз и изображение для просмотра пользователями. Последнее, что нужно сделать, это добавить подпрограмму кнопок и вызов функций.

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

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

5. Обновление сервера Flask
Теперь нам нужно обновить наш сервер, чтобы он мог выполнять предварительную обработку изображения для / api / prepare, а также для служить моделью для / model во внешнем интерфейсе. Окончательная версия сервера будет выглядеть примерно так.

Для предварительной обработки у нас есть две функции:
- prepare (вызывается для / api / prepare)
- предварительная обработка (принимает изображение, возвращает изображение с измененным размером в массив numpy, эта функция может выполнять любую предварительную обработку, которая вам нравится, и все будет работать правильно, если она возвращает массив numpy)
Модель:
- модель (называется / model)
- load_shards (вызывается для любого файла, который вызывается для /, эта функция используется для загрузки файлов двоичного веса)

Почему нам нужно иметь 2 функции и 2 отдельных API для обслуживания модели вместо одного?

В следующей версии tensorflowjs, когда мы загружаем модель для некоторого API model = await tf.loadModel(modelURL);
, он сначала загружает модель, которая является файлом JSON, из modelURL, а затем автоматически отправляет еще несколько POST в корень домена, чтобы загрузить осколки (проверьте эти POST-запросы в демонстрации, в журналах сервера). Поскольку я не хочу сохранять свою модель в корневом каталоге рядом с сервером, поэтому мне нужно иметь 2 функции: одну для model.json, а другую для сегментов.

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

Спасибо за чтение! Не стесняйтесь добавлять / переписывать любую понравившуюся деталь! Наслаждайтесь!
Github