用 7 年前的 SHWD 数据,带你读一遍 Ultralytics predict 链

摘要 :SHWD 转 YOLO 后,用 YOLO26n 微调出 best.pt;本文不堆 SOTA,重点带读 Ultralytics predict------数据坑点、预训练 vs 微调一眼对比,以及图进 predict 后 preprocess→NMS→Results 全链路,并扣回安全帽 FastAPI demo。


0. 引子

Agent 风很大,这篇偏冷一点:AI 视觉 ------从老数据集转换,到训练,再到线上天天跑的 predict。

数据来自 Safety-Helmet-Wearing-Dataset(SHWD),2018 年前后的工业安全帽场景,VOC 标注。工业视觉需求一直在;原仓自带的老模型效果已经不错,我们要做的是 VOC→YOLO → 微调 → predict 落地 。训练只简述;正文主吃 predict 链------不通读 loss、不卷 mAP、不在这篇开调优 KPI。

产出:YOLO26n 微调后的 best.pt,以及已部署的安全帽 FastAPI demo(后文两三行)。这是专栏 「AI 视觉之路」 的第一块砖。闲言少叙。


1. 数据:SHWD 接到 YOLO

整条链就四步:

text 复制代码
SHWD(VOC)→ voc_to_yolo_shwd.py(--limit 10 冒烟 → 全量)
→ images/ + labels/ + data.yaml
→ yolo train → best.pt

全量大约 3GB ;务必先 --limit 10 冒烟,再跑全量。脚本核心:读 VOC xml → 坐标换算 → 摆 YOLO 目录 → 写 data.yaml。细节见仓库 voc_to_yolo导读.md,正文只记坑。

坑 怎么踩、怎么避
VOC 坐标 1-based 中心点换算要 - 1 ,和 Ultralytics VOC.yaml 同源
类名必须对齐 脚本认 hat / person(0/1),xml 写 helmet 会被静默丢掉
冒烟再全量 --limit 10 看 labels/*.txt 四列是否在 0~1
train/val 划分 跟 SHWD 自带 ImageSets/Main/*.txt,脚本不随机切
线上 predict 不要 data.yaml、不要 labels------只有 train 吃标注

数据篇只保证「能训」;真正线上跑的是 predict。


2. 训练与第一眼效果

底座 YOLO26n,在全量 SHWD 上微调:

bash 复制代码
yolo train model=yolo26n.pt data=shwd_yolo/data.yaml epochs=... imgsz=640

产出在 runs/detect/train/weights/best.pt。本篇 不贴 mAP、不贴训练曲线

只放一张同图上的两次 predict 效果图: yolo26n.pt、best.pt,框的差异一眼能看懂。

预训练 vs 微调 ------同一张图跑两次 predict:

yolo26n.pt best.pt
框什么 只框 人(COCO 习惯) 框 hat / person(安全帽业务)
读者带走 预训练 ≠ 你的场景 微调换的是 检测目标

训练证明数据能学。半个安全帽在现版权重下不一定检出------多半是数据难例 / 标注覆盖不足,不是 predict 链 bug。补标(半帽、未戴帽的头部)和 OpenCV 辅助看图留系列后文,这篇不收工在这。


3. predict 链:图进来之后发生了什么

best.pt 到手之后,真正线上天天调用的是 predict。图片进入 predict 之后,都经历了什么?

先背四句话:合并参数 → 转成模型能吃的 → 各步吃不同参数 → 拼成 Results。

text 复制代码
source → 合并 args → preprocess → inference → postprocess → Results[0].boxes

和 train 的分界 :yolo train 要 data.yaml 和 images/ + labels/ 成对;predict 只要图、不要标注 。Python API 返回 list[Results] ;CLI yolo predict 走 predict_cli,默认写 runs/detect,不把 Results 还给 shell。

调用链(文件级,贴正文比 prose 省事):

text 复制代码
yolo predict model=best.pt source=... conf=0.25
  │
  ▼
cfg/__init__.py :: entrypoint()
  ▼
engine/model.py :: Model.predict()     ← 拼 args,选 predictor
  │  CLI → predict_cli  |  API → list[Results]
  ▼
models/yolo/model.py :: task_map       ← detect → DetectionPredictor
  ▼
engine/predictor.py :: stream_inference()
  │  preprocess → inference → postprocess
  ▼
models/yolo/detect/predict.py :: postprocess()   ← NMS + scale_boxes
  ▼
engine/results.py :: Results / Boxes             ← FastAPI 吃这层

入口前先认门 :predict 能接的 source 类型很多------单张路径、目录、摄像头、URL、PIL、numpy ndarray 、tensor 都行;常见入参还有 conf(置信度阈值)、iou(NMS)、imgsz、device、save / show 等。完整列表以 Ultralytics Predict 官方文档 为准,别背参数表,需要时查。

我们安全帽 FastAPI 走的是 source=ndarray 那条:上传图解码成 BGR 数组,再 model.predict(source=ndarray, conf=0.25)。终端 yolo predict source=某.jpg 会先读文件,前面多一步「怎么拿到图」 ;进 stream_inference 之后,和 ndarray 走的是 同一套 preprocess → inference → postprocess。

参数合并 :model.predict(...) 里,conf、device、imgsz 等合成一份 args(右边 kwargs 覆盖左边)。detect 任务落到 DetectionPredictor,主循环在 stream_inference。

预处理 → 推理 → 后处理(三步拆开看,别挤一段):

步 干什么 谁吃哪些参数 安全帽线落在哪
preprocess 各种 source 统一收成 float tensor imgsz(letterbox/resize) 上传 ndarray → BGR → letterbox → RGB → BCHW → /255
inference self.model(im) forward augment 等 模型 只吃 tensor;前面读文件还是收 HTTP,都是为这一步备料
postprocess 先 conf 筛框 ,再 NMS(iou)去重合 ,最后 scale_boxes 还原原图 conf、iou(见下) DetectionPredictor:框坐标回到 原图像素

conf 和 iou 要认 :都在 postprocess,但 顺序是先 conf、后 iou 。forward 吐出一堆候选框之后,先用 conf(置信度阈值) 卡一刀------分数低于阈值的丢掉;阈值越低,放出来的框越多 (漏检少、误检可能多)。剩下来的框再做 NMS : iou 看两框重叠程度 (交并比),重叠太高的视为同一目标,留分高的、删重合的。所以 iou 不是「越大框越多」,而是 NMS 里判定『算不算同一个框』的门闩 ------通常 iou 阈值设得高,才更容易把重叠框并掉。最后再 scale_boxes,从 letterbox 尺寸映射回上传图的原尺寸。

补一句易混:像素 /255 是 tensor 归一化,不是 标签 txt 里框坐标的 0~1。面试可以这么说:模型吐候选框,conf 筛、iou 去重,NMS 留不相重的。

Results :Results / Boxes 官方说明 里字段和方法很多------plot()、save()、to_json()、summary() 等,检测线不必通读一千多行实现。我们服务化只摘 results[0].boxes 的 xyxy、conf、cls 转 JSON;照仓库 scripts/predict_batch.py 的 detection_to_dict 即可。

官方还支持 predict 回调(Callbacks)------在 on_predict_start、on_predict_batch_end 等钩子里插自己的处理或测试步骤,整条链是可扩展的。这篇没玩,后面系列可以试。

误区 正解
predict 要吃 labels 只有 train 要标注
基类 postprocess 没 NMS DetectionPredictor 里写了
BGR 直接进网络 preprocess 里转 RGB

图进来先 letterbox,模型出 raw box,NMS 去重叠,Results 包成可画可 JSON;FastAPI 只摘 results[0].boxes。


4. 扣回工程:predict 之后怎么用

带读 predict 链,是为了 接到自己的工程里 。这里面最值钱的一块是 best.pt------微调后的权重 ;data.yaml 和训练脚本可以留在训练机,线上推理只要权重 + Ultralytics 库。

思路很直:在自己的 FastAPI 项目里装 ultralytics,启动时 YOLO("path/to/best.pt") 加载一次;暴露 POST /detect,收上传图 → 解码成 ndarray → model.predict(source=ndarray) → 把 results[0].boxes 转成 JSON 返回。和 §3 是同一套 predict 链,不是另写一套推理。漏检、空检是模型/数据问题,不是 API 层 bug。

前端不用上复杂框架:一个 index.html + <canvas> 就够做演示------选图上传,拿回 xyxy / conf / cls,在 canvas 上画框、标类名,就是一个能给别人看的小工具。


5. 作者的话

AI出现之后,总感觉是放大了一些幻想。

能看到很多地方让AI跑所有的开发工作,200刀的套餐,就是全自动生产状态了。

很多在技术深耕多年的程序员,在看到贵价AI写的高质量代码之后,陷入了焦虑。

多年积攒下来的技术骄傲,好像瞬间粉碎了。

他们变得害怕错误,什么事情都交给AI。

我看着他们的自我意识逐渐被吞噬,只想一直向前游,游到海水变蓝。

真的还想继续深耕下去,我还不想放弃。

相关推荐
Zentceh3 小时前
PixelClean 这类 AI 降噪算法是怎么工作的?从 RAW 域到 GAN 色彩重建的技术拆解
图像处理·人工智能·科技·算法·计算机视觉·车载系统·智能硬件
ss.li5 小时前
rppg阅读笔记 2026.10.15
图像处理·python·计算机视觉
词却5 小时前
计算机视觉:YOLO 目标检测
yolo·目标检测·计算机视觉
再__努力1点18 小时前
OpenCV 5 vs OpenCV 4:一次讲清所有差异
人工智能·opencv·计算机视觉
pride.li18 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
kyle~20 小时前
实时系统通信抖动(Jitter)
计算机视觉·机器人·接口隔离原则·传感器
xingyuzhisuan1 天前
一文读懂星宇智算 StarVerse-AI 无限画布,AI 视频场景的空间扩展方案
人工智能·计算机视觉
晨间晓1 天前
两张图片哪里不一样?用 OpenCV 做图像差异检测工具
人工智能·opencv·计算机视觉
波力海苔夹心脆6751 天前
VisionPro 与 VisionMaster 对比(上):软件定位、开发环境与核心视觉工具对照
图像处理·算法·计算机视觉·c#·视觉检测·个人开发·vp9
richard_yuu1 天前
OpenCV 实战第 13 篇:工程化收尾,内存拷贝、并行与一条完整流水线
人工智能·opencv·计算机视觉