Привет
У меня есть проект TensorFlow 2.0, перед которым стоит крошечный Flask API, поэтому я могу делать запросы к модели через HTTP-вызовы с предварительной обработкой данных, уже выполненной в API. Я выбрал Gunicorn для запуска моего приложения Flask / TensorFlow в докер-контейнере. К сожалению, рабочий процесс, созданный Gunicorn, зависает в контейнере, пока его не убьет Gunicorn. Сервер никогда не запускается, и я не могу отправлять к нему запросы. Более того, та же самая установка Gunicorn безупречно работает вне докера, на моем хост-компьютере.
Журналы Docker (он просто зависает и через долгое время выдает ошибку тайм-аута)
[2019-10-03 18:03:05 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-10-03 18:03:05 +0000] [1] [INFO] Listening at: http://127.0.0.1:8000 (1)
[2019-10-03 18:03:05 +0000] [1] [INFO] Using worker: sync
[2019-10-03 18:03:05 +0000] [8] [INFO] Booting worker with pid: 8
2019-10-03 18:03:08.126584: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-10-03 18:03:08.130017: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3392000000 Hz
2019-10-03 18:03:08.130306: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x55fbb23fb2d0 executing computations on platform Host. Devices:
2019-10-03 18:03:08.130365: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): Host, Default Version
dockerfile:
FROM python
RUN pip install gunicorn
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD [ "gunicorn", "--chdir", "src", "api:app" ]
api.py:
from flask import Flask, request
import inference
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def predict():
if request.method == 'GET':
return 'POST a json payload of {"imageBase64": "base64base64base64"} to this address to predict.'
try:
result = inference.run(request.json['imageBase64'])
return result
except Exception as e:
return {'error': str(e)}, 500
if __name__ == "__main__":
app.run()
else:
print('\n * Server ready!')
inference.py
# Import packages
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import tensorflow as tf
from tensorflow import keras
import PIL
import numpy as np
from io import BytesIO
import base64
import json
print("TensorFlow version is ", tf.__version__)
# Set variables
##########################################################################################
##########################################################################################
model_name = 'catsdogs'
base_dir = os.path.join(os.path.dirname(__file__), '..')
model_dir = os.path.join(base_dir, 'models')
##########################################################################################
##########################################################################################
# Load model
model = keras.models.load_model(os.path.join(model_dir, model_name + '.h5'))
# Load metadata
with open(os.path.join(model_dir, model_name + '_metadata.json')) as metadataFile:
metadata = json.load(metadataFile)
# Split metadata
labels = metadata['training_labels']
image_size = metadata['image_size']
# Exported function for inference
def run(imgBase64):
# Decode the base64 string
image = PIL.Image.open(BytesIO(base64.b64decode(imgBase64)))
# Pepare image
image = image.resize((image_size, image_size), resample=PIL.Image.BILINEAR)
image = image.convert("RGB")
# Run prediction
tensor = tf.cast(np.array(image), tf.float32) / 255.
tensor = tf.expand_dims(tensor, 0, name=None)
result = model.predict(tensor, steps=1)
# Combine result with labels
labeledResult = {}
for i, label in enumerate(labels):
labeledResult[label] = float(result[0][labels[label]])
return labeledResult
Я искал решение этой проблемы целую вечность и не смог ничего придумать, любая помощь была бы очень признательна.
Спасибо!
Ваша установка Docker ограничивает максимальный объем памяти, доступной для контейнера?
Испытывает то же самое. Я не думаю, что виноват Gunicorn. Я получаю ту же ошибку при запуске python3 api.py
из оболочки bash в контейнере.
@tlaanemaa, ты можешь подтвердить, что говорит @mackdelany ?
Привет. Извини, что так исчез.
Моя установка немного ограничивает оперативную память Docker, но то же самое произошло, даже когда я снял ограничение.
Я попробую запустить api-файл без пулемета и отправлю отчет.
Спасибо!
@tlaanemaa есть новости об этом?
@benoitc Heya
Извините, я увлекся другими вещами, и у меня не было времени углубляться в это.
Я попробую сегодня ткнуть в это и вернуться к тебе
Поэтому я попытался запустить приложение без пулемета в контейнере, и это сработало.
Ниже приведен бит CMD моего файла Dockerfile.
Работает:
CMD [ "python", "src/api.py" ]
Журналы:
2019-12-02 11:40:45.649503: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-12-02 11:40:45.653496: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2019-12-02 11:40:45.653999: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x55f969cf6a40 executing computations on platform Host. Devices:
2019-12-02 11:40:45.654045: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): Host, Default Version
TensorFlow version is 2.0.0
* Serving Flask app "api" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Не работает:
CMD [ "gunicorn", "--chdir", "src", "api:app" ]
Журналы:
[2019-12-02 11:39:22 +0000] [1] [INFO] Starting gunicorn 20.0.4
[2019-12-02 11:39:22 +0000] [1] [INFO] Listening at: http://127.0.0.1:8000 (1)
[2019-12-02 11:39:22 +0000] [1] [INFO] Using worker: sync
[2019-12-02 11:39:22 +0000] [9] [INFO] Booting worker with pid: 9
2019-12-02 11:39:24.041188: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-12-02 11:39:24.046495: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2019-12-02 11:39:24.047129: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5623e18b5200 executing computations on platform Host. Devices:
2019-12-02 11:39:24.047183: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): Host, Default Version
Кроме того, я сделал репозиторий открытым, так что вы можете покопаться, если хотите.
Может быть полезно
Listening at: http://127.0.0.1:8000 (1)
Может быть проблема в том, что Gunicorn слушает localhost внутри контейнера, поэтому к нему нельзя добраться извне?
Я так не думаю, потому что приложение flask делало то же самое, и оно работало.
Кроме того, версия gunicorn не регистрирует версию тензорного потока, что как бы предполагает, что проблема возникает в этой строке журнала в коде. Если вы работаете без пулеметчика, просто наберите флакон, и он это зарегистрирует.
TensorFlow version is 2.0.0
что он говорит на уровне отладки?
@tlaanemaa, как @CaselIT, похоже, что ваш клиент не может достичь порта Gunicorn через сеть Docker.
Можете ли вы попробовать запустить Gunicorn с аргументом -b 0.0.0.0:8000
?
Я не думаю, что проблема кроется в сети, потому что, по крайней мере, из журналов кажется, что сервер вообще не запускается, поскольку он никогда не попадает в строки журнала, которые появляются после импорта тензорного потока.
Тем не менее я попробовал ваше предложение, но это дает мне ошибку
CMD [ "gunicorn", "-b", "0.0.0.0:8000", "--chdir", "src", "api:app" ]
_Бревно_
usage: gunicorn [OPTIONS] [APP_MODULE]
gunicorn: error: unrecognized arguments: -d
Если вы хотите попробовать себя, образ comtainer доступен по адресу registry.gitlab.com/tlaanemaa/image-classifier.
@tlaanemaa, можете ли вы повторно Dockerfile
, команду построения образа и команду запуска контейнера?
@javabrett Конечно
docker build -t tlaanemaa/image-classifier .
_Dockerfile на момент публикации: _
FROM python:3.7
RUN pip install gunicorn
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD [ "gunicorn", "-b", "0.0.0.0:8000", "--chdir", "src", "api:app" ]
какой полный журнал докера, можете ли вы вставить командную строку, которую он наконец использует?
Если он не делает что-то, от чего нельзя отказаться во время отладки этой проблемы, можете ли вы сейчас запустить его без Portainer?
Это работает для меня, Docker Desktop для Mac 2.1.0.5:
docker build -t tlaanemaa/image-classifier .
docker run -it --rm -p 8000:8000 tlaanemaa/image-classifier
Принимает запросы POST
.
Пожалуйста, запустите и опубликуйте полный вывод и результат.
Я попробовал, и теперь он работает.
Может быть, это был исправлен флаг -b
?
Большое спасибо!
Что интересно, когда я делаю запросы POST, запросы выполняются быстро, а запросы GET очень медленные. После некоторого времени выполнения запросов GET они становятся быстрыми, но затем POST становится очень медленным, и рабочий процесс истекает. Как только он отвечает на этот POST, POST снова выполняется быстро, а GET - медленно. Кажется, что он может сделать один быстро, и ему нужно время, чтобы переключиться: D
это журналы, когда GET выполняется быстро, а POST - медленно из-за времени ожидания рабочего:
[2020-01-10 09:34:46 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:72)
[2020-01-10 09:34:46 +0000] [72] [INFO] Worker exiting (pid: 72)
[2020-01-10 09:34:47 +0000] [131] [INFO] Booting worker with pid: 131
TensorFlow version is 2.0.0
2020-01-10 09:34:48.946351: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-01-10 09:34:48.951124: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2020-01-10 09:34:48.951612: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x56481dbabd80 executing computations on platform Host. Devices:
2020-01-10 09:34:48.951665: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): Host, Default Version
* Server ready!
Кроме того, в некоторых ситуациях журнал * Server ready!
не отображается в журналах докеров. Это тоже могло ввести в заблуждение. Не уверен, что вызывает это
Текущий сервер в вашем Docker будет настроен однопоточным / синхронизирующим, что будет тривиально сделать занятым / блокирующим, поэтому, вероятно, вы это видите. Попробуйте добавить несколько аргументов, например --workers=2 --threads=4 --worker-class=gthread
.
Спасибо @javabrett
Это исправило!
Была такая же проблема. Насколько я могу догадаться из моих собственных журналов, похоже, что tensorflow
использует gevent
, и вы не можете одновременно использовать gevent
в gunicorn
. Флаги --workers
и --threads
не имеют для меня никакого значения, но изменение с --worker-class=gevent
на --worker-class=gthread
устранило проблему для меня. Спасибо @javabrett
Привет! Как сопровождающий gevent и участник этого проекта, я могу категорически заявить, что gevent и gunicorn хорошо работают вместе. Различные библиотеки могут мешать, но это не вина Gunicorn или gevent. Пожалуйста, откройте новый выпуск, если это не ваш случай. Спасибо!
Самый полезный комментарий
Была такая же проблема. Насколько я могу догадаться из моих собственных журналов, похоже, что
tensorflow
используетgevent
, и вы не можете одновременно использоватьgevent
вgunicorn
. Флаги--workers
и--threads
не имеют для меня никакого значения, но изменение с--worker-class=gevent
на--worker-class=gthread
устранило проблему для меня. Спасибо @javabrett