应使用 lifespan 异步上下文管理器加载模型,配合 cpu 预加载、懒加载标记和首次请求时移至 gpu;输入用 pydantic 校验并转 float32 张量;输出必须调用 .tolist() 转为 json 可序列化类型。

FastAPI 启动后模型加载太慢,请求超时怎么办
模型在 startup 事件里加载是常见做法,但大模型(比如 1GB+ 的 PyTorch model.pth)直接在 app = FastAPI() 后同步加载,会导致 uvicorn 启动卡住、健康检查失败、K8s 探针反复重启 Pod。
- 把模型加载逻辑放进
lifespan异步上下文管理器,而非@app.on_event("startup")—— 后者不支持await,强行 await 会阻塞事件循环 - 使用
torch.load(..., map_location="cpu")避免 GPU 初始化抢占显存,等首次请求再移到cuda(如果需要) - 加一层懒加载标记:用
global _model+if _model is None:控制只加载一次,避免多 worker 下重复初始化
from contextlib import asynccontextmanager
import torch
<p>_model = None</p><p>@asynccontextmanager
async def lifespan(app: FastAPI):
global _model
_model = torch.load("model.pth", map_location="cpu")
yield
_model = None # 可选:退出时清理</p>
POST /predict 接收 JSON 但模型要 tensor 输入,怎么安全转换
用户传 {"input": [0.1, 0.5, 0.9]} 很常见,但直接 torch.tensor(data["input"]) 有风险:类型不一致、维度错位、NaN 溢出,FastAPI 默认 500 错误不带具体原因。
- 用 Pydantic
BaseModel显式声明输入结构,自动校验类型和长度,比手动try/except更可靠 -
torch.tensor(..., dtype=torch.float32)必须指定 dtype,否则 NumPy 默认float64会让模型报Expected float32 - 加
.to(device)前先检查_model.device,别硬写"cuda"—— 本地调试可能没 GPU
class PredictRequest(BaseModel):
input: List[float]
<p>@app.post("/predict")
def predict(req: PredictRequest):
x = torch.tensor(req.input, dtype=torch.float32).unsqueeze(0) # 补 batch 维度
x = x.to(_model.device)
y = _model(x).item()
return {"output": y}</p>
Uvicorn 多 worker 下模型被重复加载或共享失败
用 uvicorn app:app --workers 4 启动时,每个子进程都会执行一次 lifespan,模型白白加载 4 次;若用 multiprocessing 共享模型,又容易触发 RuntimeError: cannot pickle 'module' object。
- 不要依赖 fork 共享模型 —— PyTorch 模型含不可序列化对象(如 CUDA 上下文),fork 后子进程调用会崩
- 改用
--workers 1 --reload开发,生产环境用--workers N+ 单进程内模型懒加载(见第一个副标题的global _model方案) - 更稳的做法:启动前预加载模型到内存,用
spawn启动 worker(需额外封装),但多数场景没必要,1 个 worker + GIL 并发够用
模型输出要返回概率、置信度、类别名,但 FastAPI 默认只序列化 dict 和基本类型
直接 return {"probs": model_output.softmax(1)} 会报 TypeError: Object of type Tensor is not JSON serializable,这是最常卡住新手的地方。
- 必须显式转成 Python 基本类型:
.tolist()是最安全的选择,.numpy().tolist()多余且慢 - 别用
json.dumps手动序列化再Response—— FastAPI 已内置 JSON 响应,手动做反而绕过校验和 content-type 设置 - 如果要返回类别名,提前把
idx_to_class = {0: "cat", 1: "dog"}定义为模块级变量,别每次请求都重建
y_probs = torch.nn.functional.softmax(_model(x), dim=1)[0]
return {
"class_id": int(y_probs.argmax().item()),
"confidence": float(y_probs.max().item()),
"probabilities": y_probs.tolist() # ← 关键:必须 .tolist()
}
模型热更新、跨进程通信、GPU 显存隔离这些事,得先确保单实例跑稳了再说。很多问题其实不是 FastAPI 不行,而是把模型当普通函数用了——它真不是。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











