簡體   English   中英

ValueError: Out of range float values are not JSON compliant error on Heroku and WSL but not on Windows

[英]ValueError: Out of range float values are not JSON compliant error on Heroku, and WSL but not on Windows

我正在嘗試使用 FastAPI 將使用 Tensorflow 創建的 CNN model 部署到 Heroku。 該應用程序在 Heroku 上運行,但在嘗試進行 model 預測時返回錯誤。 運行heroku logs --tail返回:

2022-02-17T03:32:12.426547+00:00 app[web.1]: [2022-02-17 03:32:12 +0000] [10] [ERROR] Exception in ASGI application
2022-02-17T03:32:12.426549+00:00 app[web.1]: Traceback (most recent call last):
2022-02-17T03:32:12.426549+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 373, in run_asgi
2022-02-17T03:32:12.426550+00:00 app[web.1]: result = await app(self.scope, self.receive, self.send)
2022-02-17T03:32:12.426550+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
2022-02-17T03:32:12.426551+00:00 app[web.1]: return await self.app(scope, receive, send)
2022-02-17T03:32:12.426551+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/fastapi/applications.py", line 212, in __call__
2022-02-17T03:32:12.426552+00:00 app[web.1]: await super().__call__(scope, receive, send)
2022-02-17T03:32:12.426552+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/applications.py", line 112, in __call__
2022-02-17T03:32:12.426552+00:00 app[web.1]: await self.middleware_stack(scope, receive, send)
2022-02-17T03:32:12.426553+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
2022-02-17T03:32:12.426553+00:00 app[web.1]: raise exc
2022-02-17T03:32:12.426554+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
2022-02-17T03:32:12.426554+00:00 app[web.1]: await self.app(scope, receive, _send)
2022-02-17T03:32:12.426554+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
2022-02-17T03:32:12.426554+00:00 app[web.1]: raise exc
2022-02-17T03:32:12.426555+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
2022-02-17T03:32:12.426555+00:00 app[web.1]: await self.app(scope, receive, sender)
2022-02-17T03:32:12.426555+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/routing.py", line 656, in __call__
2022-02-17T03:32:12.426555+00:00 app[web.1]: await route.handle(scope, receive, send)
2022-02-17T03:32:12.426556+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/routing.py", line 259, in handle
2022-02-17T03:32:12.426556+00:00 app[web.1]: await self.app(scope, receive, send)
2022-02-17T03:32:12.426556+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/routing.py", line 61, in app
2022-02-17T03:32:12.426556+00:00 app[web.1]: response = await func(request)
2022-02-17T03:32:12.426557+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/fastapi/routing.py", line 250, in app
2022-02-17T03:32:12.426557+00:00 app[web.1]: response = actual_response_class(response_data, **response_args)
2022-02-17T03:32:12.426557+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/responses.py", line 49, in __init__
2022-02-17T03:32:12.426558+00:00 app[web.1]: self.body = self.render(content)
2022-02-17T03:32:12.426558+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/starlette/responses.py", line 174, in render
2022-02-17T03:32:12.426558+00:00 app[web.1]: return json.dumps(
2022-02-17T03:32:12.426559+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/json/__init__.py", line 234, in dumps
2022-02-17T03:32:12.426559+00:00 app[web.1]: return cls(
2022-02-17T03:32:12.426559+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/json/encoder.py", line 199, in encode
2022-02-17T03:32:12.426560+00:00 app[web.1]: chunks = self.iterencode(o, _one_shot=True)
2022-02-17T03:32:12.426560+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/json/encoder.py", line 257, in iterencode
2022-02-17T03:32:12.426560+00:00 app[web.1]: return _iterencode(o, 0)
2022-02-17T03:32:12.426561+00:00 app[web.1]: ValueError: Out of range float values are not JSON compliant

最值得注意的是在最后一行,它說“ValueError:超出范圍的浮點值不符合 JSON”。我的 procfile 看起來像這樣:

web: gunicorn -w 2 -k uvicorn.workers.UvicornWorker main:app

當嘗試使用python -m uvicorn main:app在 WSL 上運行服務器時,出現此錯誤

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/eruaro/.local/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 375, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/fastapi/applications.py", line 212, in __call__
    await super().__call__(scope, receive, send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/routing.py", line 61, in app
    response = await func(request)
  File "/home/eruaro/.local/lib/python3.8/site-packages/fastapi/routing.py", line 250, in app
    response = actual_response_class(response_data, **response_args)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/responses.py", line 49, in __init__
    self.body = self.render(content)
  File "/home/eruaro/.local/lib/python3.8/site-packages/starlette/responses.py", line 174, in render
    return json.dumps(
  File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
ValueError: Out of range float values are not JSON compliant

它類似於我在 Heroku 上獲得的那個。但是,在 Windows 上,使用與我在 WSL 上使用的命令相同的命令,該應用程序可以運行。 沒有返回錯誤,我可以在服務器上進行預測。 如何刪除 JSON 兼容錯誤?

作為參考,我的代碼在一個單獨的main.py文件中:

from fastapi import FastAPI
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import get_file 
from tensorflow.keras.utils import load_img 
from tensorflow.keras.utils import img_to_array
from tensorflow import expand_dims
from tensorflow.nn import softmax
from numpy import argmax
from numpy import max
from numpy import array

app = FastAPI()
model_dir = "food-vision-model.h5"
model = load_model(model_dir)

class_predictions = array([
    'apple_pie',
    'baby_back_ribs',
    'baklava',
    'beef_carpaccio',
    'beef_tartare',
    'beet_salad',
    'beignets',
    'bibimbap',
    'bread_pudding',
    'breakfast_burrito',
    'bruschetta',
    'caesar_salad',
    'cannoli',
    'caprese_salad',
    'carrot_cake',
    'ceviche',
    'cheesecake',
    'cheese_plate',
    'chicken_curry',
    'chicken_quesadilla',
    'chicken_wings',
    'chocolate_cake',
    'chocolate_mousse',
    'churros',
    'clam_chowder',
    'club_sandwich',
    'crab_cakes',
    'creme_brulee',
    'croque_madame',
    'cup_cakes',
    'deviled_eggs',
    'donuts',
    'dumplings',
    'edamame',
    'eggs_benedict',
    'escargots',
    'falafel',
    'filet_mignon',
    'fish_and_chips',
    'foie_gras',
    'french_fries',
    'french_onion_soup',
    'french_toast',
    'fried_calamari',
    'fried_rice',
    'frozen_yogurt',
    'garlic_bread',
    'gnocchi',
    'greek_salad',
    'grilled_cheese_sandwich',
    'grilled_salmon',
    'guacamole',
    'gyoza',
    'hamburger',
    'hot_and_sour_soup',
    'hot_dog',
    'huevos_rancheros',
    'hummus',
    'ice_cream',
    'lasagna',
    'lobster_bisque',
    'lobster_roll_sandwich',
    'macaroni_and_cheese',
    'macarons',
    'miso_soup',
    'mussels',
    'nachos',
    'omelette',
    'onion_rings',
    'oysters',
    'pad_thai',
    'paella',
    'pancakes',
    'panna_cotta',
    'peking_duck',
    'pho',
    'pizza',
    'pork_chop',
    'poutine',
    'prime_rib',
    'pulled_pork_sandwich',
    'ramen',
    'ravioli',
    'red_velvet_cake',
    'risotto',
    'samosa',
    'sashimi',
    'scallops',
    'seaweed_salad',
    'shrimp_and_grits',
    'spaghetti_bolognese',
    'spaghetti_carbonara',
    'spring_rolls',
    'steak',
    'strawberry_shortcake',
    'sushi',
    'tacos',
    'takoyaki',
    'tiramisu',
    'tuna_tartare',
    'waffles'
])

@app.get("/")
async def root():
    return {"message": "Welcome to the Food Vision API!"}

@app.post("/net/image/prediction/")
async def get_net_image_prediction(image_link: str = ""):
    if image_link == "":
        return {"message": "No image link provided"}
    
    img_path = get_file(
        origin = image_link
    )
    img = load_img(
        img_path, 
        target_size = (224, 224)
    )

    img_array = img_to_array(img)
    img_array = expand_dims(img_array, 0)

    pred = model.predict(img_array)
    score = softmax(pred[0])

    class_prediction = class_predictions[argmax(score)]
    model_score = round(max(score) * 100, 2)

    return {
        "model_prediction_class": class_prediction,
        "model_prediction_score": model_score
    }

我已經解決了這個問題,解決方案是對整個應用程序進行 docker 化,然后將其部署到 Heroku。這樣它就可以在 WSL (Linux) 上運行,也可以在 Heroku 上運行(使用 Linux)。

因此,這需要稍微編輯main.py文件:

from fastapi import FastAPI
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import get_file 
from tensorflow.keras.utils import load_img 
from tensorflow.keras.utils import img_to_array
from tensorflow import expand_dims
from tensorflow.nn import softmax
from numpy import argmax
from numpy import max
from numpy import array
from json import dumps
from uvicorn import run
import os

app = FastAPI()
model_dir = "food-vision-model.h5"
model = load_model(model_dir)

class_predictions = array([
    'apple_pie',
    'baby_back_ribs',
    'baklava',
    'beef_carpaccio',
    'beef_tartare',
    'beet_salad',
    'beignets',
    'bibimbap',
    'bread_pudding',
    'breakfast_burrito',
    'bruschetta',
    'caesar_salad',
    'cannoli',
    'caprese_salad',
    'carrot_cake',
    'ceviche',
    'cheesecake',
    'cheese_plate',
    'chicken_curry',
    'chicken_quesadilla',
    'chicken_wings',
    'chocolate_cake',
    'chocolate_mousse',
    'churros',
    'clam_chowder',
    'club_sandwich',
    'crab_cakes',
    'creme_brulee',
    'croque_madame',
    'cup_cakes',
    'deviled_eggs',
    'donuts',
    'dumplings',
    'edamame',
    'eggs_benedict',
    'escargots',
    'falafel',
    'filet_mignon',
    'fish_and_chips',
    'foie_gras',
    'french_fries',
    'french_onion_soup',
    'french_toast',
    'fried_calamari',
    'fried_rice',
    'frozen_yogurt',
    'garlic_bread',
    'gnocchi',
    'greek_salad',
    'grilled_cheese_sandwich',
    'grilled_salmon',
    'guacamole',
    'gyoza',
    'hamburger',
    'hot_and_sour_soup',
    'hot_dog',
    'huevos_rancheros',
    'hummus',
    'ice_cream',
    'lasagna',
    'lobster_bisque',
    'lobster_roll_sandwich',
    'macaroni_and_cheese',
    'macarons',
    'miso_soup',
    'mussels',
    'nachos',
    'omelette',
    'onion_rings',
    'oysters',
    'pad_thai',
    'paella',
    'pancakes',
    'panna_cotta',
    'peking_duck',
    'pho',
    'pizza',
    'pork_chop',
    'poutine',
    'prime_rib',
    'pulled_pork_sandwich',
    'ramen',
    'ravioli',
    'red_velvet_cake',
    'risotto',
    'samosa',
    'sashimi',
    'scallops',
    'seaweed_salad',
    'shrimp_and_grits',
    'spaghetti_bolognese',
    'spaghetti_carbonara',
    'spring_rolls',
    'steak',
    'strawberry_shortcake',
    'sushi',
    'tacos',
    'takoyaki',
    'tiramisu',
    'tuna_tartare',
    'waffles'
])

@app.get("/")
async def root():
    return {"message": "Welcome to the Food Vision API!"}

@app.post("/net/image/prediction/")
async def get_net_image_prediction(image_link: str = ""):
    if image_link == "":
        return {"message": "No image link provided"}
    
    img_path = get_file(
        origin = image_link
    )
    img = load_img(
        img_path, 
        target_size = (224, 224)
    )

    img_array = img_to_array(img)
    img_array = expand_dims(img_array, 0)

    pred = model.predict(img_array)
    score = softmax(pred[0])

    class_prediction = class_predictions[argmax(score)]
    model_score = round(max(score) * 100, 2)
    model_score = dumps(model_score.tolist())

    return {
        "model_prediction_class": class_prediction,
        "model_prediction_score": model_score
    }

if __name__ == "__main__":
    port = int(os.environ.get('PORT', 5000))
    run(app, host="0.0.0.0", port=port)

這里的主要區別在於os.environ.get()的使用。 我發現只要手動定義一個端口,如port = 5000 ,就會在 Heroku 上返回R10 (boot timeout) 錯誤

從這里,我創建了一個 Dockerfile,內容如下:

FROM python:3.7.3-stretch

# Maintainer info
LABEL maintainer="erickson_ruaroii@dlsu.edu.ph"

# Make working directories
RUN  mkdir -p  /my-directory/project
WORKDIR  /my-directory/project

# Upgrade pip with no cache
RUN pip install --no-cache-dir -U pip

# Copy application requirements file to the created working directory
COPY requirements.txt .

# Install application dependencies from the requirements file
RUN pip install -r requirements.txt

# Copy every file in the source folder to the created working directory
COPY  . .

# Run the python application
CMD ["python", "main.py"]

隨着requirements.txt有這些:

fastapi==0.73.0
gunicorn==20.1.0
numpy==1.19.5
uvicorn==0.15.0
image==1.5.33
tensorflow-cpu==2.7.0

我使用tensorflow-cpu在一個免費帳戶上繞過了 Heroku 的 slug 大小和 memory 限制。

然后我可以從這里構建 docker 映像並將其部署到 heroku。

$ docker image build -t app-name .
$ heroku create app-name
$ heroku container:push web --app app-name
$ heroku container:release web --app food-vision-api

在本地運行時,我使用了以下命令:

$ docker run -p 5000:5000 -d app-name

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM