и как это сделать с умом с модельными серверами

Хотя большинство статей о глубоком обучении сосредоточено на моделировании, очень мало статей о том, как развернуть такие модели в производственной среде. Некоторые из них говорят «производственная», но часто просто используют неоптимизированную модель и встраивают ее в веб-сервер Flask. В этом посте я объясню, почему такой подход плохо масштабируется и расходует ресурсы.

«Производственный» подход

Если вы ищете, как развернуть модели TensorFlow, Keras или Pytorch в производственной среде, есть много хороших руководств, но иногда вы сталкиваетесь с очень простыми простыми примерами, заявляющими о готовности к работе. В этих примерах часто используется модель raw keras, веб-сервер Flask и помещается в контейнер докеров. В этих примерах для составления прогнозов используется Python. Код для этих «производственных» веб-серверов Flask выглядит так:

from flask import Flask, jsonify, request
from tensorflow import keras
app = Flask(__name__)
model = keras.models.load_model("model.h5")
@app.route("/", methods=["POST"])
def index():
    data = request.json
    prediction = model.predict(preprocess(data))   
    return jsonify({"prediction": str(prediction)})

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

Теперь давайте резюмируем, что здесь происходит и почему это не «производственная» марка.

Не оптимизирующие модели

Сначала обычно используется модель как есть, что означает, что модель Кераса из примера была просто экспортирована с помощью model.save (). Модель включает в себя все параметры и градиенты, которые необходимы для обучения модели, но не требуются для вывода. Кроме того, модель не сокращается и не квантуется. В результате использование неоптимизированных моделей имеет большую задержку, требует больше вычислений и больше по размеру файла.

Пример с B5 Efficientnet:

  • h5 keras модель: 454 МБ
  • Оптимизированная модель тензорного потока (без квантования): 222 МБ

Использование Flask и Python API

Следующая проблема заключается в том, что простой Python и Flask используются для загрузки модели и предоставления прогнозов. Здесь много проблем.

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

При этом давайте посмотрим на Flask. Flask включает мощный и простой в использовании веб-сервер для разработки. На официальном сайте вы можете прочитать следующее:

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

Тем не менее, вы можете использовать Flask как приложение WSGI, например, Google App Engine. Однако во многих руководствах не используется Google App Engine или NGIX, они просто используют их как есть и помещают в контейнер докеров. Но даже когда они используют NGIX или любые другие веб-серверы, они обычно полностью отключают многопоточность.

Давайте рассмотрим проблему подробнее. Если вы используете TensorFlow, он обрабатывает вычислительные ресурсы (CPU, GPU) за вас. Если вы загружаете модель и вызываете прогноз, TensorFlow использует вычислительные ресурсы для выполнения этих прогнозов. Пока это происходит, ресурс используется или заблокирован. Если ваш веб-сервер одновременно обслуживает только один запрос, все в порядке, поскольку модель была загружена в этом потоке и прогноз вызывается из этого потока. Но как только вы разрешаете более одного запроса одновременно, ваш веб-сервер перестает работать, потому что вы просто не можете получить доступ к модели TensorFlow из разных потоков. При этом в этой настройке вы не можете обрабатывать более одного запроса одновременно. Не похоже на масштабируемость, правда?

Пример:

  • Веб-сервер разработки Flask: 1 одновременный запрос
  • Сервер TensorFlowX Model: настраиваемый параллелизм

Масштабирование «малонагруженных» экземпляров с помощью docker

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

Пример задержки:

  • Обслуживание Flask, как показано выше: ~ 2 с на изображение
  • Сервер модели Tensorflow (без пакетной обработки, без графического процессора): ~ 250 мс на изображение
  • Сервер модели Tensorflow (без пакетной обработки, графический процессор): ~ 100 мс на изображение

Без использования графических процессоров / TPU

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

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

Пример затрат:

  • 2 экземпляра ЦП (16 ядер, 32 ГБ, a1.4xlarge): 0,816 $ / ч
  • 1 экземпляр графического процессора (32 ГБ ОЗУ, 4 ядра, Tesla M60, g3s.xlarge): 0,75 $ / ч

Это уже решено

Как видите, загрузка обученной модели и помещение ее в контейнеры докеров Flask - не изящное решение. Если вы хотите глубокое обучение в производственной среде, начните с модели, затем подумайте о серверах и, наконец, о масштабировании экземпляров.

Оптимизировать модель

К сожалению, оптимизация модели для вывода не так проста, как должна быть. Тем не менее, это может легко сократить время вывода в несколько раз, так что это, без сомнения, того стоит. Первый шаг - заморозить веса и убрать лишние тренировки. Этого можно достичь с помощью TensorFlow напрямую, но для этого потребуется преобразовать вашу модель либо в оценщик, либо в граф Tensorflow (формат SavedModel), если вы пришли из модели Keras. В самом TensorFlow есть учебник для этого. Следующим шагом для дальнейшей оптимизации является применение отсечения и квантования модели, при котором незначительные веса удаляются, а размер модели уменьшается.

Использовать модельные серверы

Когда у вас есть оптимизированная модель, вы можете посмотреть на разные серверы моделей, предназначенные для моделей глубокого обучения в производстве. Для TensorFlow и Keras TensorFlowX предлагает сервер модели тензорного потока. Есть и другие, такие как TensorRT, Clipper, MLFlow, DeepDetect.

Сервер моделей TensorFlow предлагает несколько функций. Одновременное обслуживание нескольких моделей с минимальным сокращением накладных расходов. Это позволяет вам обновлять ваши модели без простоев при развертывании новой версии, сохраняя при этом возможность использовать старую версию. Он также имеет необязательную конечную точку REST API в дополнение к API gRPC. Пропускная способность намного выше, чем при использовании Flask API, поскольку он написан на C ++ и использует многопоточность. Кроме того, вы даже можете включить пакетную обработку, при которой сервер объединяет несколько отдельных прогнозов в пакет для очень высоких настроек нагрузки. И, наконец, вы можете поместить его в контейнер для докеров и еще больше масштабировать.

Подсказка: tensorflow_model_server доступен на каждом образе AMI AWS-EC2 Deep Learning, в TensorFlow 2 он называется tensorflow2_model_server.

Используйте экземпляры GPU

И, наконец, я бы рекомендовал использовать графические процессоры или TPU для сред логического вывода. Задержка и пропускная способность таких ускорителей намного выше, при этом экономится энергия и деньги. Обратите внимание, что он используется только в том случае, если ваш программный стек может использовать мощность графических процессоров (оптимизированная модель + модель сервера). В AWS вы можете заглянуть в Elastic Inference или просто использовать экземпляр GPU с Tesla M60 (g3s.xlarge).

Изначально размещено на digital-thnking.de