【YOLO 入门到精通 08】推理预测完全指南:多数据源、流式推理与性能优化
标签 :
YOLO推理流式推理predict性能优化Results对象难度 :⭐⭐⭐ | 阅读时长 :约 60 分钟 | 系列 :第 08/12 集

写在前面
训练评估之后,模型要真正「干活」------处理图片、视频、摄像头、RTSP 流。本集是 推理的工程实战手册 :不只教 model(img),更教你怎么在生产环境稳定、高效地跑推理。
本集学习目标
- 掌握全部推理数据源及用法
- 使用 stream 模式处理长视频
- 调优 conf/imgsz/batch 等参数
- 集成到 Flask 等应用
文章目录
- [【YOLO 入门到精通 08】推理预测完全指南:多数据源、流式推理与性能优化](#【YOLO 入门到精通 08】推理预测完全指南:多数据源、流式推理与性能优化)
-
- 写在前面
- 本集学习目标
- [8.1 推理模式概览](#8.1 推理模式概览)
- [8.2 推理数据源大全](#8.2 推理数据源大全)
- [8.3 流式推理](#8.3 流式推理)
- [8.4 推理参数详解](#8.4 推理参数详解)
- [8.5 Results 对象深入](#8.5 Results 对象深入)
- [8.6 性能优化](#8.6 性能优化)
- [8.7 应用集成示例](#8.7 应用集成示例)
-
- [Flask API](#Flask API)
- 视频处理管道
- [8.8 踩坑指南](#8.8 踩坑指南)
- [8.9 常见问题 FAQ](#8.9 常见问题 FAQ)
- [8.10 本集小结](#8.10 本集小结)
8.1 推理模式概览
#mermaid-svg-w7DLzIkEA1ESpUdV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w7DLzIkEA1ESpUdV .error-icon{fill:#552222;}#mermaid-svg-w7DLzIkEA1ESpUdV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w7DLzIkEA1ESpUdV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w7DLzIkEA1ESpUdV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w7DLzIkEA1ESpUdV .marker.cross{stroke:#333333;}#mermaid-svg-w7DLzIkEA1ESpUdV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w7DLzIkEA1ESpUdV p{margin:0;}#mermaid-svg-w7DLzIkEA1ESpUdV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster-label text{fill:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster-label span{color:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster-label span p{background-color:transparent;}#mermaid-svg-w7DLzIkEA1ESpUdV .label text,#mermaid-svg-w7DLzIkEA1ESpUdV span{fill:#333;color:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV .node rect,#mermaid-svg-w7DLzIkEA1ESpUdV .node circle,#mermaid-svg-w7DLzIkEA1ESpUdV .node ellipse,#mermaid-svg-w7DLzIkEA1ESpUdV .node polygon,#mermaid-svg-w7DLzIkEA1ESpUdV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w7DLzIkEA1ESpUdV .rough-node .label text,#mermaid-svg-w7DLzIkEA1ESpUdV .node .label text,#mermaid-svg-w7DLzIkEA1ESpUdV .image-shape .label,#mermaid-svg-w7DLzIkEA1ESpUdV .icon-shape .label{text-anchor:middle;}#mermaid-svg-w7DLzIkEA1ESpUdV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w7DLzIkEA1ESpUdV .rough-node .label,#mermaid-svg-w7DLzIkEA1ESpUdV .node .label,#mermaid-svg-w7DLzIkEA1ESpUdV .image-shape .label,#mermaid-svg-w7DLzIkEA1ESpUdV .icon-shape .label{text-align:center;}#mermaid-svg-w7DLzIkEA1ESpUdV .node.clickable{cursor:pointer;}#mermaid-svg-w7DLzIkEA1ESpUdV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w7DLzIkEA1ESpUdV .arrowheadPath{fill:#333333;}#mermaid-svg-w7DLzIkEA1ESpUdV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w7DLzIkEA1ESpUdV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w7DLzIkEA1ESpUdV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w7DLzIkEA1ESpUdV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w7DLzIkEA1ESpUdV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w7DLzIkEA1ESpUdV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster text{fill:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV .cluster span{color:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w7DLzIkEA1ESpUdV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w7DLzIkEA1ESpUdV rect.text{fill:none;stroke-width:0;}#mermaid-svg-w7DLzIkEA1ESpUdV .icon-shape,#mermaid-svg-w7DLzIkEA1ESpUdV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w7DLzIkEA1ESpUdV .icon-shape p,#mermaid-svg-w7DLzIkEA1ESpUdV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w7DLzIkEA1ESpUdV .icon-shape .label rect,#mermaid-svg-w7DLzIkEA1ESpUdV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w7DLzIkEA1ESpUdV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w7DLzIkEA1ESpUdV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w7DLzIkEA1ESpUdV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入源
预处理
模型推理
后处理
Results
可视化/保存/API
| 特点 | 说明 |
|---|---|
| 多源 | 图/视频/摄像头/URL/流 |
| 流式 | stream=True 省内存 |
| 批量 | batch=N 提吞吐 |
| 可定制 | conf/iou/imgsz/classes |
8.2 推理数据源大全
| 来源 | 示例 | stream | 说明 |
|---|---|---|---|
| 图片 | 'img.jpg' |
❌ | 单张 |
| 目录 | 'images/' |
✅ | 批量 |
| 视频 | 'v.mp4' |
✅ | MP4/AVI |
| URL | 'https://...' |
❌ | 网络图 |
| 摄像头 | 0 |
✅ | 设备索引 |
| PIL | Image.open() |
❌ | RGB |
| OpenCV | cv2.imread() |
❌ | BGR ndarray |
| RTSP | 'rtsp://...' |
✅ | 监控流 |
| YouTube | 'https://youtu.be/...' |
✅ | 在线视频 |
| Glob | '*.jpg' |
✅ | 通配符 |
python
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model("img.jpg") # 路径
model("images/") # 目录
model("video.mp4") # 视频
model(source=0) # 摄像头
model("rtsp://ip/stream") # RTSP
8.3 流式推理
长视频必须用
stream=True,否则所有帧结果堆在内存里会 OOM。
python
results = model.predict(source="long_video.mp4", stream=True, save=True)
for result in results:
n = len(result.boxes)
# 处理完即释放,内存稳定
实时摄像头
python
import cv2
results = model.predict(source=0, stream=True, show=False)
for r in results:
frame = r.plot()
cv2.imshow("YOLO", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
8.4 推理参数详解
| 参数 | 默认 | 说明 | 调优 |
|---|---|---|---|
conf |
0.25 | 置信度阈值 | 误检↑conf,漏检↓conf |
iou |
0.7 | NMS IoU | 重复框↓iou |
imgsz |
640 | 输入尺寸 | 小目标↑imgsz |
max_det |
300 | 最大检测数 | 密集场景调大 |
classes |
None | 过滤类别 | [0,2] 只检人/车 |
half |
False | FP16 | GPU 加速 |
device |
auto | 设备 | 0/cpu |
batch |
1 | 批次 | 目录推理可增大 |
rect |
True | 最小矩形填充 | 导出模型匹配用 False |
python
results = model.predict(
source="street.jpg",
conf=0.5,
classes=[0, 2, 5],
imgsz=1280,
save=True,
save_txt=True,
save_crop=True,
line_width=2,
)
8.5 Results 对象深入
python
r = results[0]
# 属性
r.orig_img, r.orig_shape, r.path, r.speed
r.boxes # 检测
r.masks # 分割
r.keypoints # 姿态
# 提取数据
xyxy = r.boxes.xyxy.cpu().numpy()
conf = r.boxes.conf.cpu().numpy()
cls = r.boxes.cls.cpu().numpy()
# 可视化
r.show()
r.save("out.jpg")
img = r.plot() # BGR ndarray
8.6 性能优化
| 技巧 | 方法 | 效果 |
|---|---|---|
| GPU | device=0 |
5~10x |
| FP16 | half=True |
1.5~2x |
| 小模型 | yolo26n | 2~5x |
| 小尺寸 | imgsz=320 | 2~4x |
| 批量 | batch=8 | 1.5~2x |
| 导出 | TensorRT | 2~5x |
python
import time
model = YOLO("yolo26n.pt")
model("warmup.jpg", verbose=False)
times = []
for _ in range(100):
t0 = time.time()
model("test.jpg", verbose=False)
times.append(time.time() - t0)
print(f"平均: {sum(times)/len(times)*1000:.1f}ms, FPS: {len(times)/sum(times):.1f}")
8.7 应用集成示例
Flask API
python
from flask import Flask, request, jsonify
from ultralytics import YOLO
import cv2, numpy as np, base64
app = Flask(__name__)
model = YOLO("best.pt")
@app.route("/detect", methods=["POST"])
def detect():
img_b64 = request.json["image"]
arr = np.frombuffer(base64.b64decode(img_b64), np.uint8)
img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
results = model(img, conf=0.5)
dets = [{
"class": model.names[int(b.cls[0])],
"conf": float(b.conf[0]),
"bbox": b.xyxy[0].tolist(),
} for b in results[0].boxes]
return jsonify({"detections": dets})
# uvicorn 用户可换 FastAPI,逻辑相同
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
视频处理管道
python
def process_video(inp, out, model_path="yolo26n.pt"):
model = YOLO(model_path)
cap = cv2.VideoCapture(inp)
fps = int(cap.get(cv2.CAP_PROP_FPS)) or 30
w, h = int(cap.get(3)), int(cap.get(4))
writer = cv2.VideoWriter(out, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
for r in model.predict(inp, stream=True):
writer.write(r.plot())
cap.release(); writer.release()
8.8 踩坑指南
| 坑 | 解决 |
|---|---|
| 长视频 OOM | stream=True |
| 无 GUI 无法 show | save=True |
| RTSP 断流 | 加重连逻辑 |
| 导出模型尺寸不匹配 | rect=False, imgsz=固定值 |
| 推理比训练慢很多 | 检查是否在用 CPU |
8.9 常见问题 FAQ
Q1:model() 和 model.predict()?
A:完全等价。
Q2:能并发处理多路流吗?
A:可以,每路独立 model 实例或线程池。
8.10 本集小结
| 场景 | 推荐 |
|---|---|
| 单图 | model("img.jpg") |
| 批量 | model("dir/", batch=16) |
| 长视频 | stream=True |
| 监控 | stream=True + RTSP |
| ← 第07集 | 第09集:目标跟踪 → |
|---|