Gunicorn: Gunicorn + Flask + Tensorflow dalam wadah Docker tidak berfungsi

Dibuat pada 3 Okt 2019  ·  23Komentar  ·  Sumber: benoitc/gunicorn

Halo

Saya memiliki proyek TensorFlow 2.0 yang memiliki Flask API kecil di depannya sehingga saya dapat membuat permintaan ke model melalui panggilan HTTP dengan pra-pemrosesan data yang sudah dilakukan di API. Saya memilih Gunicorn untuk menjalankan aplikasi Flask/TensorFlow saya dalam wadah buruh pelabuhan. Sayangnya, proses pekerja yang dibuat Gunicorn hang di dalam wadah hingga dibunuh oleh Gunicorn. Server tidak pernah muncul dan saya tidak dapat membuat permintaan untuk itu. Selain itu, pengaturan Gunicorn yang sama berfungsi dengan sempurna di luar buruh pelabuhan, di mesin Host saya.

Log Docker (Itu hanya hang di sana dan mencetak kesalahan batas waktu setelah waktu yang lama)

[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

file buruh pelabuhan:

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!')

inferensi.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

Saya telah mencari solusi untuk ini selama berabad-abad dan belum berhasil menemukan apa pun, bantuan apa pun akan sangat dihargai.

Terima kasih!

Feedback Requested FeaturWorker FeaturIPC PlatforDocker

Komentar yang paling membantu

Punya masalah yang sama. Sejauh yang saya bisa tebak dari log saya sendiri, sepertinya tensorflow menggunakan gevent , dan Anda tidak dapat menggunakan gevent bersamaan di gunicorn . Bendera --workers dan --threads tidak membuat perbedaan bagi saya, tetapi mengubah dari --worker-class=gevent menjadi --worker-class=gthread memperbaiki masalah bagi saya. Terima kasih @javabrett

Semua 23 komentar

Apakah pengaturan Docker Anda membatasi memori maksimum yang tersedia untuk wadah?

Mengalami hal yang sama. Saya tidak berpikir Gunicorn yang harus disalahkan. Saya mendapatkan kesalahan yang sama saat menjalankan python3 api.py dari bash Shell di dalam wadah.

@tlaanemaa dapatkah Anda mengkonfirmasi apa yang dikatakan @mackdelany ?

Hai. Maaf menghilang seperti itu.

Pengaturan saya membatasi RAM Docker sedikit tetapi hal yang sama terjadi bahkan ketika saya menghapus batasannya.

Saya akan mencoba menjalankan file api tanpa gunicorn dan melaporkan kembali.

Terima kasih!

@tlaanemaa ada berita tentang itu?

@benoitc Heya
Maaf, saya sudah terbawa dengan hal-hal lain dan tidak punya waktu untuk melangkah lebih jauh dengan ini.
Saya akan mencoba menyodok ini hari ini dan menghubungi Anda kembali

Jadi saya mencoba menjalankan aplikasi tanpa gunicorn di dalam wadah dan itu berhasil.
Di bawah ini adalah bit CMD dari Dockerfile saya

Bekerja:

CMD [ "python", "src/api.py" ]

Log:

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)

Tidak berfungsi:

CMD [ "gunicorn", "--chdir", "src", "api:app" ]

Log:

[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

Juga, saya telah membuat repositori terbuka sehingga Anda dapat melihat-lihat jika Anda mau.
Semoga bermanfaat

https://gitlab.com/tlaanemaa/image-classifier

Listening at: http://127.0.0.1:8000 (1)

Mungkinkah masalahnya adalah gunicorn mendengarkan localhost di dalam wadah sehingga tidak dapat dijangkau dari luar?

Saya rasa tidak karena aplikasi flask melakukan hal yang sama dan itu berhasil.
Juga, versi gunicorn tidak mencatat versi tensorflow yang menunjukkan bahwa masalah terjadi sebelum baris log dalam kode. Saat berjalan tanpa gunicorn, cukup labu, lalu log itu.
TensorFlow version is 2.0.0

apa yang tertulis di level debug?

@tlaanemaa bagaimana jaringan daemon Docker Anda dikonfigurasi? Per komentar dari @CaselIT , sepertinya klien Anda tidak dapat mencapai port Gunicorn melalui jaringan Docker.

Bisakah Anda mencoba memulai Gunicorn dengan arg -b 0.0.0.0:8000 ?

Saya tidak berpikir masalahnya terletak pada jaringan karena tampaknya, setidaknya dari log, bahwa server tidak memulai sama sekali karena tidak pernah mengenai baris log yang datang setelah impor tensorflow

Namun demikian saya mencoba saran Anda tetapi itu memberi saya kesalahan

CMD [ "gunicorn", "-b", "0.0.0.0:8000", "--chdir", "src", "api:app" ]

_Catatan_

usage: gunicorn [OPTIONS] [APP_MODULE]
gunicorn: error: unrecognized arguments: -d

Jika Anda ingin mencoba sendiri maka gambar comtainer tersedia di registry.gitlab.com/tlaanemaa/image-classifier

@tlaanemaa dapatkah Anda memposting ulang Dockerfile Anda yang diperbarui, perintah pembuatan gambar, dan perintah menjalankan wadah?

@javabrett Tentu

_Dockerfile pada saat posting:_

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" ]

apa log lengkap buruh pelabuhan, dapatkah Anda menempelkan baris perintah yang akhirnya digunakan?

Kecuali jika ia melakukan sesuatu yang tidak dapat diabaikan selama debug masalah ini, dapatkah Anda menjalankannya tanpa Portainer untuk saat ini?

Ini berfungsi untuk saya, Docker Desktop untuk Mac 2.1.0.5:

docker build -t tlaanemaa/image-classifier .
docker run -it --rm -p 8000:8000 tlaanemaa/image-classifier

Menerima permintaan POST .

Silakan jalankan dan posting output dan hasil lengkap.

Saya mencobanya dan berhasil sekarang.
Mungkinkah flag -b yang memperbaikinya?

Terima kasih banyak!

Yang menarik sekarang adalah ketika saya melakukan permintaan POST maka itu cepat tetapi permintaan GET sangat lambat. Setelah beberapa saat melakukan permintaan GET, ini menjadi cepat tetapi kemudian POST menjadi sangat lambat dan pekerja kehabisan waktu. Setelah merespons POST itu, POST menjadi cepat lagi dan GET menjadi lambat. Sepertinya bisa cepat dan butuh waktu untuk beralih :D

ini adalah log ketika GET cepat dan POST lambat karena waktu pekerja habis:

[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!

Juga, dalam beberapa situasi, log * Server ready! tampaknya tidak muncul di log buruh pelabuhan. Itu juga bisa menyesatkan. Tidak yakin apa yang menyebabkan itu

Server saat ini di Docker Anda akan dikonfigurasi single/sync threaded, yang akan sepele untuk membuat sibuk/memblokir, jadi kemungkinan Anda melihatnya. Coba tambahkan beberapa argumen seperti --workers=2 --threads=4 --worker-class=gthread .

Terima kasih @javabrett
Itu memperbaikinya!

Punya masalah yang sama. Sejauh yang saya bisa tebak dari log saya sendiri, sepertinya tensorflow menggunakan gevent , dan Anda tidak dapat menggunakan gevent bersamaan di gunicorn . Bendera --workers dan --threads tidak membuat perbedaan bagi saya, tetapi mengubah dari --worker-class=gevent menjadi --worker-class=gthread memperbaiki masalah bagi saya. Terima kasih @javabrett

Hai! Sebagai pengelola gevent dan kontributor untuk proyek ini, saya dapat dengan pasti menyatakan bahwa gevent dan gunicorn bekerja sama dengan baik. Berbagai perpustakaan dapat mengganggu, tetapi itu bukan kesalahan gunicorn atau gevent. Silakan buka masalah baru jika itu bukan kasus Anda. Terima kasih!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat