2. 使用FastAPI部署TensorFlow文本分类模型
任务目标
构建一个FastAPI异步接口,加载预训练的TensorFlow BERT模型(中文情感分类),接收JSON格式的文本输入,返回情感类别(正面/负面)及对应的置信度分数。
环境依赖
tensorflow==2.12.0
transformers==4.30.0
fastapi==0.100.0
uvicorn==0.23.0
pydantic==2.0.0
完整实现代码
import asyncio
from functools import lru_cache
from typing import Dict
import numpy as np
import tensorflow as tf
from fastapi import FastAPI
from pydantic import BaseModel
from transformers import TFAutoModelForSequenceClassification, AutoTokenizer
# ---------- 模型与分词器加载 ----------
MODEL_NAME = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = TFAutoModelForSequenceClassification.from_pretrained(
MODEL_NAME, num_labels=2
)
# 编译模型(TensorFlow SavedModel 或权重加载后需要)
dummy_input = tokenizer("测试", return_tensors="tf")
_ = model(dummy_input) # 触发一次前向传播以构建图
# ---------- FastAPI 应用 ----------
app = FastAPI(title="BERT情感分类API")
class TextRequest(BaseModel):
text: str
class PredictionResponse(BaseModel):
label: str
confidence: float
@lru_cache(maxsize=128)
def predict_sync(text: str) -> Dict[str, float]:
"""同步推理函数,使用 lru_cache 缓存重复请求结果"""
inputs = tokenizer(text, return_tensors="tf", truncation=True, max_length=128)
logits = model(inputs).logits
probs = tf.nn.softmax(logits, axis=-1).numpy()[0]
return {"positive": float(probs[1]), "negative": float(probs[0])}
@app.post("/predict", response_model=PredictionResponse)
async def predict(request: TextRequest):
"""异步接口:在线程池中执行同步推理,避免阻塞事件循环"""
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(None, predict_sync, request.text)
if result["positive"] >= result["negative"]:
return PredictionResponse(label="positive", confidence=result["positive"])
else:
return PredictionResponse(label="negative", confidence=result["negative"])
@app.get("/health")
async def health_check():
return {"status": "ok"}
运行方式
# 启动服务(默认端口8000)
uvicorn main:app --host 0.0.0.0 --port 8000
调用与验证
使用curl或浏览器访问接口:
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"text": "这部电影非常精彩,演员演技出色"}'
预期输出(基于模型权重,数值可能略有不同):
{"label":"positive","confidence":0.87}
验证通过条件:
- 服务启动无报错,
/health返回{"status":"ok"}; - POST请求返回200状态码,响应体包含
label和confidence字段; - 输入正面文本(如示例)时
label为positive,输入“这部电影很糟糕,浪费时间”时label为negative; - 置信度值在0到1之间,且正面与负面概率之和为1。
关键说明
- 模型使用
bert-base-chinese预训练权重,未经过微调,因此分类精度有限,但接口逻辑完整可用; - 若需更高精度,可用标注数据微调模型后替换加载路径;
- 异步接口通过
run_in_executor将阻塞推理放入线程池,保证高并发下事件循环不被阻塞; - 使用
lru_cache缓存相同文本的推理结果,减少重复计算。