Часто возникает необходимость абстрагироваться от деталей модели машинного обучения и просто развернуть или интегрировать ее с помощью простых в использовании конечных точек API. Например, мы можем предоставить конечную точку URL, с помощью которой любой может сделать запрос POST, и они получат ответ JSON о том, что модель предположила, не беспокоясь о ее технических деталях.

В этом руководстве мы создадим обслуживающий сервер TensorFlow для развертывания нашей InceptionV3 сверточной нейронной сети (CNN) классификации изображений, построенной на Keras. Затем мы создадим простой сервер Flask, который будет принимать запрос POST и выполнять некоторую предварительную обработку изображений, необходимую для обслуживающего сервера Tensorflow, и возвращать ответ JSON.

Что такое TensorFlow Serving?

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

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

Установка TensorFlow Serving

Предварительные требования: создайте виртуальную среду python и установите в ней Keras с серверной частью TensorFlow. Подробнее здесь.

Примечание. Все команды выполнялись в виртуальной среде python в Ubuntu 18.04.1 LTS.

Теперь в той же виртуальной среде выполните следующие команды (используйте sudo для прав root):

$ apt install curl
$ echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -
$ apt-get update
$ apt-get install tensorflow-model-server
$ tensorflow_model_server --version
TensorFlow ModelServer: 1.10.0-dev
TensorFlow Library: 1.11.0
$ python  --version
Python 3.6.6

Вы можете перейти на более новую версию tensorflow-model-server с помощью:

$ apt-get upgrade tensorflow-model-server

Обзор каталога того, что мы собираемся построить

Понимание структуры каталогов, прежде чем мы начнем, поможет нам получить четкое представление о том, где мы находимся на каждом этапе.

(tensorflow) ubuntu@Himanshu:~/Desktop/Medium/keras-and-tensorflow-serving$ tree -c
└── keras-and-tensorflow-serving
    ├── README.md
    ├── my_image_classifier
    │   └── 1
    │       ├── saved_model.pb
    │       └── variables
    │           ├── variables.data-00000-of-00001
    │           └── variables.index
    ├── test_images
    │   ├── car.jpg
    │   └── car.png
    ├── flask_server
    │   ├── app.py
    │   ├── flask_sample_request.py
    └── scripts
        ├── download_inceptionv3_model.py
        ├── inception.h5
        ├── auto_cmd.py
        ├── export_saved_model.py
        ├── imagenet_class_index.json
        └── serving_sample_request.py
6 directories, 15 files

Вы можете получить все эти файлы из моего репозитория GitHub:



Экспорт модели Keras для обслуживания Tensorflow

Для этого урока мы загрузим и сохраним InceptionV3 CNN с весами Imagenet в Keras, используя download_inceptionv3_model.py. Вы можете загрузить любую другую модель, доступную в keras.applications библиотеке (здесь), или, если вы создали свою собственную модель в Keras, вы можете пропустить этот шаг.

После выполнения вышеуказанного скрипта вы должны получить следующий результат:

$ python download_inceptionv3_model.py
Using TensorFlow backend.
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels.h5
96116736/96112376 [==============================] - 161s 2us/step

Теперь у нас есть InceptionV3 CNN (inception.h5), сохраненный в формате Keras. Мы хотим экспортировать нашу модель в формате, который может обрабатывать сервер TensorFlow. Мы делаем это, выполняя export_saved_model.py скрипт.

TensorFlow предоставляет формат SavedModel как универсальный формат для экспорта моделей. Под капотом наша модель Keras полностью определена с точки зрения объектов TensorFlow, поэтому мы можем легко экспортировать ее, используя методы Tensorflow. TensorFlow предоставляет удобную функцию tf.saved_model.simple_save(), которая абстрагирует некоторые из этих деталей и отлично работает для большинства случаев использования.

Выход:

$ python export_saved_model.py
WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.

Мы получили это предупреждение, потому что мы загрузили предварительно обученную модель. Мы можем использовать эту модель для вывода как есть, но если мы хотим обучить ее дальше, нам нужно запустить функцию compile() после ее загрузки. Это предупреждение пока можно проигнорировать. После выполнения этого сценария в каталоге my_image_classifier сохраняются следующие файлы:

├── my_image_classifier
   └── 1
       ├── saved_model.pb
       └── variables
           ├── variables.data-00000-of-00001
           └── variables.index
2 directories, 3 files

Предположим, мы хотим обновить нашу модель в будущем (возможно, потому, что мы собрали больше обучающих данных и обучили модель на обновленном наборе данных), мы можем сделать это следующим образом:

  1. Запуск того же скрипта на новой модели keras
  2. Обновление export_path = ‘../my_image_classifier/1’ до export_path = ‘../my_image_classifier/2’ в export_saved_model.py

TensorFlow Serving автоматически обнаружит новую версию модели в каталоге my_image_classifier и обновит ее на сервере.

Запуск сервера обслуживания TensorFlow

Чтобы запустить обслуживающий сервер TensorFlow на локальном компьютере, выполните следующую команду:

$ tensorflow_model_server --model_base_path=/home/ubuntu/Desktop/Medium/keras-and-tensorflow-serving/my_image_classifier --rest_api_port=9000 --model_name=ImageClassifier
  • --model_base_path: Это должен быть абсолютный путь, иначе вы получите сообщение об ошибке:
Failed to start server. Error: Invalid argument: Expected model ImageClassifier to have an absolute path or URI; got base_path()=./my_image_classifier
  • --rest_api_port: Tensorflow Serving запустит gRPC ModelServer на порту 8500, а REST API будет доступен на порту 9000.
  • --model_name: это будет имя вашего обслуживающего сервера, с помощью которого вы будете отправлять POST-запрос. Вы можете ввести здесь любое имя.

Тестирование нашего сервера обслуживания TensorFlow

Сценарий serving_sample_request.py отправляет POST-запрос серверу обслуживания TensorFlow. Входное изображение передается через аргумент командной строки.

Выход:

$ python serving_sample_request.py -i ../test_images/car.png
Using TensorFlow backend.
[["n04285008", "sports_car", 0.998414], ["n04037443", "racer", 0.00140099], ["n03459775", "grille", 0.000160794], ["n02974003", "car_wheel", 9.57862e-06], ["n03100240", "convertible", 6.01581e-06]]

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

Зачем нам нужен Flask-сервер?

Как мы видим, мы выполнили некоторые шаги предварительной обработки изображений в serving_sample_request.py (вызывающий интерфейс). Ниже приведены причины для создания сервера Flask поверх обслуживающего сервера TensorFlow:

  • Когда мы предоставляем конечную точку API команде внешнего интерфейса, мы должны убедиться, что не перегружаем ее техническими деталями предварительной обработки.
  • У нас не всегда может быть внутренний сервер Python (например, сервер Node.js), поэтому использование библиотек numpy и keras для предварительной обработки может быть проблемой.
  • Если мы планируем обслуживать несколько моделей, нам придется создать несколько серверов обслуживания TensorFlow и добавить новые URL-адреса в наш код внешнего интерфейса. Но наш сервер Flask сохранит URL-адрес домена таким же, и нам нужно только добавить новый маршрут (функцию).
  • Предоставление доступа на основе подписки, обработка исключений и другие задачи могут быть выполнены в приложении Flask.

Что мы пытаемся сделать, так это устранить тесную связь между серверами TensorFlow Serving и нашим Frontend.

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

Создание сервера Flask

Предварительное условие: установите Flask в виртуальной среде Python отсюда.

Нам просто нужен один app.py файл, чтобы создать наш Flask-сервер.

Перейдите в каталог, в котором вы сохранили файл app.py, и запустите сервер Flask с помощью следующей команды:

$ export FLASK_ENV=development && flask run --host=0.0.0.0
  • FLASK_ENV=development: Это включает режим отладки, который в основном дает вам полные журналы ошибок. Не используйте это в производственной среде.
  • Команда flask run автоматически выполняет app.py файл в текущем каталоге.
  • --host=0.0.0.0: Это позволяет вам делать запросы к серверу Flask с любого другого компьютера. Чтобы сделать запрос с другого компьютера, вам нужно будет указать IP-адрес компьютера, на котором работает сервер Flask, вместо localhost.

Выход:

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 1xx-xxx-xx4
Using TensorFlow backend.

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

$ tensorflow_model_server --model_base_path=/home/ubuntu/Desktop/Medium/keras-and-tensorflow-serving/my_image_classifier --rest_api_port=9000 --model_name=ImageClassifier

Вот сценарий (auto_cmd.py) для автоматизации запуска и остановки двух серверов (TensorFlow Serving и Flask). Вы также можете изменить этот сценарий для более чем двух серверов.

Не забудьте изменить путь в строке 10 в auto_cmd.py, чтобы он указывал на ваш app.py каталог. Вам также может потребоваться изменить строку 6, чтобы она указывала на корзину вашей виртуальной среды. Затем вы можете выполнить приведенный выше сценарий из любого каталога, выполнив в своем терминале следующее:

$ python auto_cmd.py

Тестирование нашего сервера Flask и сервера обслуживания TensorFlow

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

  1. Мы берем входное изображение, кодируем его в формат base64 и отправляем на наш сервер Flask с помощью POST-запроса.
  2. Сервер Flask декодирует этот образ base64 и предварительно обрабатывает его для нашего сервера обслуживания TensorFlow.
  3. Затем сервер Flask отправляет запрос POST на наш обслуживающий сервер TensorFlow и декодирует ответ.
  4. Декодированный ответ форматируется и отправляется обратно во внешний интерфейс.

Выход:

$ python flask_sample_request.py -i ../test_images/car.png
[
  [
    "n04285008", 
    "sports_car", 
    0.998414
  ], 
  [
    "n04037443", 
    "racer", 
    0.00140099
  ], 
  [
    "n03459775", 
    "grille", 
    0.000160794
  ], 
  [
    "n02974003", 
    "car_wheel", 
    9.57862e-06
  ], 
  [
    "n03100240", 
    "convertible", 
    6.01581e-06
  ]
]

У нашего фляжного сервера в настоящее время есть только один маршрут для нашего единственного обслуживающего сервера Tensorflow. Мы можем обслуживать несколько моделей, создав несколько обслуживающих серверов Tensorflow на разных или тех же машинах. Для этого нам просто нужно добавить больше маршрутов (функций) в наш app.py файл и выполнить в нем необходимую предварительную обработку для конкретной модели. Мы можем передать эти маршруты нашей команде внешнего интерфейса для вызова моделей по мере необходимости.

Обработка HTTP-запроса между источниками

Рассмотрим сценарий, в котором мы делаем запрос POST с использованием Angular, наш сервер Flask получает заголовок OPTIONS, а не POST, потому что,

  • Веб-приложение выполняет HTTP-запрос с перекрестным источником, когда оно запрашивает ресурс, который имеет другое происхождение (домен, протокол и порт), чем его собственное происхождение.
  • CORS (Cross Origin Resource Sharing) - это механизм, который использует дополнительные заголовки HTTP, чтобы сообщить браузеру, что веб-приложение, работающее в одном источнике (домене), имеет разрешение на доступ к выбранным ресурсам с сервера в другом источнике. Подробнее о CORS читайте здесь.

Следовательно, Angular не получает ответа от сервера Flask. Чтобы решить эту проблему, мы должны включить Flask-CORS в нашем app.py. Узнайте больше об этом здесь.

Заключение

И это все, что нам нужно для работы нашей модели машинного обучения. TensorFlow Serving упрощает интеграцию машинного обучения в веб-сайты и другие приложения. Имея множество готовых моделей, доступных в keras (здесь), можно разрабатывать суперполезные приложения с минимальными знаниями в области машинного обучения и алгоритмов глубокого обучения.

Если вы нашли этот урок полезным, поделитесь им с друзьями и оставьте аплодисменты :-). Если у вас есть какие-либо вопросы, отзывы или предложения, дайте мне знать в комментариях. Также вы можете связаться со мной в Twitter и LinkedIn. Мне есть чем поделиться со всеми вами, и я только начинаю. Следите за новостями!