在 FastAPI 中使用 Pydantic 模型进行基于模型的预测时出现错误 "value is not a valid dict"

Getting error "value is not a valid dict" when using Pydantic models in FastAPI for model-based predictions

我正在尝试将 Pydantic 模型与 FastAPI 结合使用来进行多项预测(针对输入列表)。问题是不能将 Pydantic 模型直接传递给 model.predict() 函数,所以我将它转换为字典,但是,我收到以下错误:

AttributeError: 'list' object has no attribute 'dict'

我的代码:

from fastapi import FastAPI
import uvicorn
from pydantic import BaseModel
import pandas as pd
from typing import List

app = FastAPI()

class Inputs(BaseModel):
    id: int
    f1: float
    f2: float
    f3: str

class InputsList(BaseModel):
    inputs: List[Inputs]

@app.post('/predict')
def predict(input_list: InputsList):
    df = pd.DataFrame(input_list.inputs.dict())
    prediction = classifier.predict(df.loc[:, df.columns != 'id'])
    probability = classifier.predict_proba(df.loc[:, df.columns != 'id'])
    return {'id': df["id"].tolist(), 'prediction': prediction.tolist(), 'probability': probability.tolist()}

我也遇到了 return 的问题,我需要输出类似于:

    [
      {
        "id": 123,
        "prediction": "class1",
        "probability": 0.89
      },
      {
        "id": 456,
        "prediction": "class3",
        "probability": 0.45
      }
    ]

PS:Inputs class 中的 id 没有出现在预测中(不是特征),但我需要显示它在它的预测旁边(参考它)。

要求

您对视图函数输入架构的定义与您发送的内容不匹配:

class Inputs(BaseModel):
    id: int
    f1: float
    f2: float
    f3: str

class InputsList(BaseModel):
    inputs: List[Inputs]

这与以下格式的请求正文相匹配:

{
  "inputs": [
    {
      "id": 1,
      "f1": 1.0,
      "f2": 1.0,
      "f3": "foo"
    }, {
      "id": 2,
      "f1": 2.0,
      "f2": 2.0,
      "f3": "bar"
    }
  ]
}

您发送的请求正文与预期格式不匹配,因此您收到 422 响应。

要么更改您要发送的对象以匹配 FastAPI 预期的格式,要么删除 InputsList 包装器并将输入设置为 input_list: List[Inputs]

First,您的架构的 f1f2 属性末尾都有不必要的逗号 ,,以及在您发送的 JSON 负载中。因此,您的模式应该是:

class Inputs(BaseModel):
    id: int
    f1: float
    f2: float
    f3: str

第二个422错误是由于您发送的JSON负载与您的架构不匹配。正如@MatsLindh 所指出的,您的 JSON 有效载荷应如下所示:

{
  "inputs": [
    {
      "id": 1,
      "f1": 1.0,
      "f2": 1.0,
      "f3": "text"
    },
    {
      "id": 2,
      "f1": 2.0,
      "f2": 2.0,
      "f3": "text"
    }
  ]
}

第三,您正在以错误的方式创建 DataFrame。您正试图在 list 对象上调用 .dict() 方法;因此,AttributeError: 'list' object has no attribute 'dict'。相反,如 所示,您应该在 list 中的每个项目上调用 .dict() 方法,如下所示:

df = pd.DataFrame([i.dict() for i in input_list.inputs])

最后,以return你问题中提到的输出格式的结果,使用下面的。 注意 predict_proba() returns 列表数组,其中包含 input 的 class 概率。如果您只想 return 特定 class 的 probability,请改用该 class 的索引,例如 prob[0].

results = []
for (id, pred, prob) in zip(df["id"].tolist(), prediction.tolist(), probability.tolist()):
    results.append({"id": id, "prediction": pred, "probability": prob})
return results

或者,您可以使用 DataFrame 及其 .to_dict() 方法:

results = pd.DataFrame({'id': df["id"].tolist(),'prediction': prediction.tolist(),'probability': probability.tolist()})
return results.to_dict(orient="records") 

如果您在使用 DataFrame 时只想 return 特定 class 的 probability,您可以提取它并将其添加到新的 list 中,例如这个 prob_list = [item[0] for item in probability.tolist()] 或使用 operator.itemgetter() 像这样 prob_list = list(map(itemgetter(0), probability.tolist())),并在创建 DataFrame 时使用那个 list