こんにちは
小さなFlaskAPIが前にあるTensorFlow2.0プロジェクトがあるので、APIですでに行われているデータ前処理を使用してHTTP呼び出しを介してモデルにリクエストを送信できます。 DockerコンテナでFlask / TensorFlowアプリケーションを実行するためにGunicornを選択しました。 悲しいことに、Gunicornが作成するワーカープロセスは、Gunicornによって殺されるまでコンテナにハングアップします。 サーバーが起動せず、サーバーにリクエストを送信できません。 さらに、同じGunicornのセットアップは、私のホストマシンのDockerの外でも問題なく機能します。
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のせいではないと思います。 コンテナ内のbashシェルからpython3 api.py
を実行すると、同じエラーが発生します。
@tlaanemaaあなた@mackdelanyの言うこと
おい。 そのように消えてすみません。
私のセットアップではDockerのRAMが少し制限されていますが、制限を解除しても同じことが起こりました。
gunicornを使用せずにAPIファイルを実行して、レポートを返してみます。
ありがとう!
@tlaanemaaそれについて何かニュースはありますか?
@benoitc Heya
申し訳ありませんが、私は他のものに夢中になり、これをさらに進める時間がありませんでした。
今日はこれを突いてあなたに返事をしようと思います
そこで、コンテナにgunicornを入れずにアプリを実行してみましたが、うまくいきました。
以下は私のDockerfileのCMDビットです
作品:
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がコンテナ内のローカルホストをリッスンしているため、外部からアクセスできないことでしょうか?
フラスコアプリが同じことをしていて、それが機能していたので、私はそうは思いません。
また、gunicornバージョンはテンソルフローバージョンをログに記録しません。これは、コードのログ行の前に問題が発生したことを示唆しています。 gunicornを使用せずに実行する場合は、フラスコを使用するだけで、ログに記録されます。
TensorFlow version is 2.0.0
デバッグレベルでは何と言っていますか?
@tlaanemaa Dockerデーモンネットワークはどのように構成されていますか? @CaselITからのコメントに
引数-b 0.0.0.0:8000
Gunicornを起動してみてください。
少なくともログからは、テンソルフローのインポート後に来るログ行にサーバーがヒットしないため、サーバーがまったく起動していないように見えるため、ネットワークに問題があるとは思いません。
それにもかかわらず、私はあなたの提案を試みましたが、それは私にエラーを与えます
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" ]
Dockerの完全なログは何ですか?最終的に使用しているコマンドラインを貼り付けることができますか?
この問題のデバッグ中に見過ごせないことをしているのでない限り、今のところ、Portainerなしで実行できますか?
これは私にとってはうまくいきます、Mac2.1.0.5用のDockerデスクトップ:
docker build -t tlaanemaa/image-classifier .
docker run -it --rm -p 8000:8000 tlaanemaa/image-classifier
POST
リクエストを受け入れます。
実行して、完全な出力と結果を投稿してください。
私はそれを試しました、そしてそれは今働きます。
それを修正したのは-b
フラグ
どうもありがとう!
今興味深いのは、POSTリクエストを実行すると、thposeは高速ですが、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ログに記録されないように見えます。 それも誤解を招く可能性があります。 何が原因なのかわからない
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