【问题标题】:Build API using FastAPI for Classification Model produced using pycaret使用 FastAPI 为使用 pycaret 生成的分类模型构建 API
【发布时间】:2020-12-19 17:10:45
【问题描述】:

我使用 pycaret 作为我的 ML 工作流,我尝试使用 FastAPI 创建一个 API。这是我第一次进入生产级别,所以我对API有点困惑

我有 10 个功能;年龄:float,live_province:str,live_city:str,live_area_big:str,live_area_small:str,sex:float,marital:float,bank:str,salary:float,amount:float和一个标签,其中包含二进制值(0和 1)。

这是我构建 API 的脚本

from pydantic import BaseModel
import numpy as np
from pycaret.classification import *

import uvicorn
from fastapi import FastAPI

app = FastAPI()

model = load_model('catboost_cm_creditable')

class Data(BaseModel):
    age: float
    live_province: str
    live_city: str
    live_area_big: str
    live_area_small: str
    sex: float
    marital: float
    bank: str
    salary: float
    amount: float

input_dict = Data

@app.post("/predict")
def predict(model, input_dict):
    predictions_df = predict_model(estimator=model, data=input_dict)
    predictions = predictions_df['Score'][0]
    return predictions

当我尝试运行 uvicorn script:app 并转到文档时,我找不到我的功能的参数,参数只显示模型和 input_dict

如何将我的特征带入 API 中的参数?

【问题讨论】:

    标签: python machine-learning production fastapi pycaret


    【解决方案1】:

    您需要键入提示您的 Pydantic 模型以使其与您的 FastAPI 一起使用

    想象一下,当您需要记录该函数时,您实际上是在使用标准 Python,

    def some_function(price: int) ->int:
        return price
    

    使用 Pydantic 与上面的示例没有什么不同

    你的class Data实际上是一个拥有超能力的蟒蛇@dataclass(来自Pydantic)

    from fastapi import Depends
    
    class Data(BaseModel):
        age: float
        live_province: str
        live_city: str
        live_area_big: str
        live_area_small: str
        sex: float
        marital: float
        bank: str
        salary: float
        amount: float
    
    
    @app.post("/predict")
    def predict(data: Data = Depends()):
        predictions_df = predict_model(estimator=model, data=data)
        predictions = predictions_df["Score"][0]
        return predictions
    

    有一个小技巧,使用 Depends,您将获得一个查询,就像您分别定义每个字段时一样。

    依赖于

    不依赖

    【讨论】:

    • 嗨,我试过了,我的 API 运行良好,但是当我尝试运行 API 时,它返回 500 Internal Server Error ERROR: Exception in ASGI application 我相信是因为我没有正确调用模型,但我无法弄清楚加载泡菜文件的正确方法。你能帮帮我吗?
    • @ebuzz168 你能提供回溯吗?
    • 它抛出 AttributeError: 'Data' object has no attribute 'columns' 错误,这与问题无关,你应该问一个新问题,但据我了解你正在做 data.columns = [str(i) for i in data.columns] ,这对我来说似乎很奇怪,因为,但你只是重申它,错误说 Data object has no attr columns,它确实 hasattr(Data "columns") 下面。
    【解决方案2】:

    您的问题在于 API 函数的定义。您为数据输入添加了一个参数,但您没有告诉 FastAPI 它的类型。 另外我假设您的意思是不要使用全局加载的模型,而不是将其作为参数接收。此外,您不需要为输入数据创建全局实例,因为您想从用户那里获取它。

    因此,只需将函数的签名更改为:

    def predict(input_dict: Data):
    

    并删除该行:

    input_dict = Data
    

    (这只是为您的班级创建了一个别名Data,命名为input_dict

    你最终会得到:

    app = FastAPI()
    
    model = load_model('catboost_cm_creditable')
    
    class Data(BaseModel):
        age: float
        live_province: str
        live_city: str
        live_area_big: str
        live_area_small: str
        sex: float
        marital: float
        bank: str
        salary: float
        amount: float
    
    @app.post("/predict")
    def predict(input_dict: Data):
        predictions_df = predict_model(estimator=model, data=input_dict)
        predictions = predictions_df['Score'][0]
        return predictions
    

    另外,我建议将Data 类的名称更改为更清晰、更易于理解的名称,即使DataUnit 在我看来会更好,因为Data 太笼统了。

    【讨论】: