用 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 10labels/*.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.ptbest.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 traindata.yamlimages/ + labels/ 成对;predict 只要图、不要标注 。Python API 返回 list[Results] ;CLI yolo predictpredict_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)、imgszdevicesave / 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(...) 里,confdeviceimgsz 等合成一份 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 还原原图 confiou(见下) DetectionPredictor:框坐标回到 原图像素

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

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

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

官方还支持 predict 回调(Callbacks)------在 on_predict_starton_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。

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

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

相关推荐
硅谷秋水2 小时前
ProDrive:基于自身-环境协同演化的自动驾驶主动规划
人工智能·深度学习·机器学习·计算机视觉·自动驾驶
菜鸟‍2 小时前
【论文学习】2026.5 || 分解式视觉-语言对齐用于细粒度开放词汇分割
人工智能·深度学习·计算机视觉
郝学胜-神的一滴3 小时前
[简化版 GAMES 101] 计算机图形学 13:从光栅化到着色——赋予三维像素光影灵魂
c++·计算机视觉·unity·godot·图形渲染·opengl·unreal
硅谷秋水13 小时前
面向长上下文自动驾驶的规划对齐Token压缩
人工智能·深度学习·机器学习·计算机视觉·自动驾驶
YOLO数据集集合15 小时前
无人机山地灾害巡检数据集 | 滑坡多区域实例分割 遥感影像解译 地质灾害预警深度学习数据10296期
人工智能·深度学习·目标检测·计算机视觉·无人机
庄周迷蝴蝶16 小时前
Vision Banana
人工智能·计算机视觉
Java患者·19 小时前
《Python 人脸识别入门实践:从人脸检测到人脸比对完整实现》
开发语言·python·opencv·目标检测·计算机视觉·目标跟踪·视觉检测
丨白色风车丨1 天前
OpenCV 实战入门:轮廓检测、模板匹配与命令行参数解析
人工智能·opencv·计算机视觉
乐迪信息1 天前
乐迪信息:港口船舶偏航难监管,AI智能监测实时发出预警提醒
大数据·人工智能·安全·计算机视觉·目标跟踪