1. 为什么选择FastAPI部署YOLO行人检测服务?
在计算机视觉领域,YOLO(You Only Look Once)系列算法因其出色的实时性而广受欢迎。最新发布的YOLOv8在保持高精度的同时,进一步优化了推理速度,使其成为行人检测场景的理想选择。而FastAPI作为Python生态中新兴的Web框架,凭借其异步特性和自动生成的交互式文档,正快速成为AI模型部署的首选工具。
我最近在一个商场客流分析项目中,需要将YOLOv8模型部署为可调用的API服务。经过对比Flask、Django等传统框架后,最终选择了FastAPI,主要基于以下考虑:
- 原生支持ASGI标准,轻松处理高并发请求
- 自动生成OpenAPI文档,前端团队可立即开始对接
- 内置数据验证,减少接口调试时间
- 与Pydantic完美集成,规范输入输出格式
实测下来,在相同硬件条件下,FastAPI的吞吐量比Flask高出约40%,这对于需要实时处理视频流的行人检测场景尤为重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与依赖安装
2.1 基础环境配置
推荐使用Python 3.8+环境,太新的Python版本可能会遇到某些库的兼容性问题。以下是经过验证的稳定版本组合:
bash复制conda create -n yolo_fastapi python=3.8
conda activate yolo_fastapi
注意:如果使用GPU加速,请确保已正确安装CUDA 11.7和cuDNN 8.5.0。可以通过nvidia-smi命令验证驱动状态。
2.2 核心依赖安装
需要安装的关键包及其作用说明:
| 包名 | 版本 | 用途 |
|---|---|---|
| fastapi | 0.95.2 | API服务框架 |
| uvicorn | 0.22.0 | ASGI服务器 |
| ultralytics | 8.0.196 | YOLOv8官方库 |
| opencv-python | 4.7.0.72 | 图像处理 |
| python-multipart | 0.0.6 | 文件上传支持 |
安装命令:
bash复制pip install fastapi uvicorn ultralytics opencv-python python-multipart
2.3 模型文件准备
YOLOv8提供了多种预训练模型,针对行人检测场景推荐使用:
- yolov8s.pt:轻量级模型,适合边缘设备
- yolov8m.pt:平衡精度与速度
- yolov8l.pt:高精度版本
可以通过以下代码自动下载:
python复制from ultralytics import YOLO
model = YOLO('yolov8m.pt') # 自动下载并缓存模型
3. API服务核心实现
3.1 基础FastAPI应用结构
创建main.py文件,构建基础框架:
python复制from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import cv2
import numpy as np
from ultralytics import YOLO
app = FastAPI(
title="YOLOv8行人检测API",
description="基于FastAPI部署的YOLOv8行人检测服务",
version="1.0.0"
)
# 加载模型(全局单例)
model = YOLO('yolov8m.pt')
3.2 图像预处理模块
处理上传图像的通用函数:
python复制async def process_image(file: UploadFile):
contents = await file.read()
nparr = np.frombuffer(contents, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# 保持宽高比调整大小
max_size = 1280
h, w = img.shape[:2]
if max(h, w) > max_size:
scale = max_size / max(h, w)
img = cv2.resize(img, (int(w*scale), int(h*scale)))
return img
3.3 核心检测接口实现
实现/predict端点:
python复制@app.post("/predict")
async def predict(file: UploadFile = File(...)):
try:
img = await process_image(file)
results = model(img, classes=[0]) # 只检测行人(class_id=0)
# 解析检测结果
detections = []
for result in results:
for box in result.boxes:
detections.append({
"confidence": float(box.conf[0]),
"bbox": box.xyxy[0].tolist(),
"class_id": int(box.cls[0])
})
return JSONResponse({
"status": "success",
"count": len(detections),
"detections": detections
})
except Exception as e:
return JSONResponse(
{"status": "error", "message": str(e)},
status_code=500
)
4. 高级功能与性能优化
4.1 批处理支持
对于视频流处理场景,可以添加批处理端点:
python复制from typing import List
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
@app.post("/batch_predict")
async def batch_predict(files: List[UploadFile] = File(...)):
try:
images = []
for file in files:
images.append(await process_image(file))
# 使用线程池并行处理
results = list(executor.map(lambda x: model(x, classes=[0]), images))
# 结果处理...
return JSONResponse({"results": processed_results})
except Exception as e:
return JSONResponse(
{"status": "error", "message": str(e)},
status_code=500
)
4.2 模型预热与缓存
在服务启动时预热模型:
python复制@app.on_event("startup")
async def startup_event():
# 预热模型
dummy_img = np.zeros((640, 640, 3), dtype=np.uint8)
model(dummy_img, classes=[0])
print("模型预热完成")
4.3 性能监控中间件
添加性能监控:
python复制from fastapi import Request
import time
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
5. 部署与测试方案
5.1 本地运行与测试
启动服务:
bash复制uvicorn main:app --reload --host 0.0.0.0 --port 8000
测试接口的Python脚本示例:
python复制import requests
url = "http://localhost:8000/predict"
files = {"file": open("test.jpg", "rb")}
response = requests.post(url, files=files)
print(response.json())
5.2 生产环境部署建议
对于生产环境,推荐使用:
- Gunicorn + Uvicorn Worker
- Nginx反向代理
- Docker容器化
示例Dockerfile:
dockerfile复制FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000", "main:app"]
5.3 压力测试结果
使用locust进行压力测试的典型结果(GPU: RTX 3060):
| 并发数 | 平均响应时间 | RPS |
|---|---|---|
| 10 | 120ms | 83 |
| 50 | 210ms | 238 |
| 100 | 450ms | 222 |
6. 常见问题与解决方案
6.1 内存泄漏排查
在长时间运行后如果发现内存增长,可以:
- 检查是否每次请求都创建了新模型实例
- 确保OpenCV的缓冲区被正确释放
- 使用memory_profiler工具定位泄漏点
6.2 GPU利用率优化
如果GPU利用率不足:
python复制# 在模型调用时增加参数
results = model(img,
classes=[0],
imgsz=640,
half=True, # 使用FP16
device=0) # 指定GPU
6.3 跨域问题处理
添加CORS支持:
python复制from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
在实际项目中,我发现YOLOv8对遮挡行人的检测效果仍有提升空间。通过添加以下后处理逻辑可以改善结果:
python复制# 在结果处理环节添加
MIN_CONFIDENCE = 0.5
MIN_BBOX_AREA = 1000 # 像素面积
valid_detections = [
d for d in detections
if d["confidence"] > MIN_CONFIDENCE
and (d["bbox"][2]-d["bbox"][0])*(d["bbox"][3]-d["bbox"][1]) > MIN_BBOX_AREA
]
