跳转到内容

10.3.4 YOLO 系列

YOLO 网格检测流程图

  • 理解 YOLO 属于哪类检测器
  • 理解单阶段检测和两阶段检测的主要差别
  • 理解置信度、框筛选和 NMS 的基本作用
  • 建立 YOLO 在工程部署里的价值判断

YOLO 想做的是:

  • 不分两步
  • 直接从图像一次性输出类别和框

因为它减少了:

  • 额外 proposal 阶段
  • 更复杂的检测流水线

所以更容易做到:

  • 实时

两阶段检测像先圈可疑区域,再派人逐一核查。 YOLO 更像一眼扫过去,同时报出:

  • 哪有目标
  • 是什么

通常可以粗略理解成一组候选框,每个候选都带:

  • 类别
  • 置信度
  • 边界框坐标

后面再通过筛选和 NMS,得到最终结果。

可以先把 YOLO 想成:

  • 模型先扫完整张图
  • 然后一次性报出“哪里像有东西、像什么、框大概在哪”

这和两阶段检测很不一样。 两阶段更像:

  • 先到处圈可疑区域
  • 再对每个区域做细查

而 YOLO 更像:

一眼看完,再把候选目标整体报出来。

一个很适合初学者先记的判断表

Section titled “一个很适合初学者先记的判断表”
你现在关心什么更值得先看哪一层
为什么它快单阶段路线和短推理链
为什么会有一堆框候选框输出
为什么结果会重叠NMS 和阈值
为什么实时项目爱用它工程部署和生态成熟度

这个表很适合新人,因为它会把 YOLO 从“版本名集合”重新变成几个具体问题。

下面这个例子不是在模拟真实 YOLO 网络, 而是在帮你建立一个很关键的直觉:

  • 模型输出通常不是“最终答案”
  • 而是一批带分数的候选框
predictions = [
{"class": "person", "score": 0.93, "box": (12, 18, 80, 160)},
{"class": "person", "score": 0.87, "box": (15, 20, 82, 158)},
{"class": "dog", "score": 0.78, "box": (120, 60, 190, 150)},
]
for pred in predictions:
print(pred)

预期输出:

Terminal window
{'class': 'person', 'score': 0.93, 'box': (12, 18, 80, 160)}
{'class': 'person', 'score': 0.87, 'box': (15, 20, 82, 158)}
{'class': 'dog', 'score': 0.78, 'box': (120, 60, 190, 150)}

前两个框都是 person 候选,而且位置很接近。下面的 NMS 示例正是用来处理这种情况。

这段输出最值得先记住的不是字段名, 而是:

  • 单阶段检测经常天然会吐出很多候选
  • 后处理本来就是检测链的一部分

def iou(box_a, box_b):
ax1, ay1, ax2, ay2 = box_a
bx1, by1, bx2, by2 = box_b
inter_x1 = max(ax1, bx1)
inter_y1 = max(ay1, by1)
inter_x2 = min(ax2, bx2)
inter_y2 = min(ay2, by2)
inter_w = max(0, inter_x2 - inter_x1)
inter_h = max(0, inter_y2 - inter_y1)
inter_area = inter_w * inter_h
area_a = (ax2 - ax1) * (ay2 - ay1)
area_b = (bx2 - bx1) * (by2 - by1)
union = area_a + area_b - inter_area
return inter_area / union if union > 0 else 0.0
predictions = [
{"box": (10, 10, 30, 30), "score": 0.95},
{"box": (12, 12, 31, 31), "score": 0.88},
{"box": (60, 60, 90, 90), "score": 0.91},
]
def nms(preds, iou_threshold=0.5):
preds = sorted(preds, key=lambda x: x["score"], reverse=True)
kept = []
while preds:
best = preds.pop(0)
kept.append(best)
preds = [
pred for pred in preds
if iou(best["box"], pred["box"]) < iou_threshold
]
return kept
print(nms(predictions))

预期输出:

Terminal window
[{'box': (10, 10, 30, 30), 'score': 0.95}, {'box': (60, 60, 90, 90), 'score': 0.91}]

中间那个框被移除,是因为它和分数最高的第一个框重叠太多。第三个框被保留,是因为它离得很远,更像另一个目标。

这个例子最关键的价值是什么?

Section titled “这个例子最关键的价值是什么?”

它说明检测输出并不是直接就能用。 很多时候模型会给出:

  • 一堆重叠候选框

而 NMS 的作用就是:

  • 保留最有代表性的那几个

因为 YOLO 这种单阶段路线天然会产生很多候选, 后处理筛选就是整个检测链的一部分。

再看一个最小“阈值先筛一轮”示例

Section titled “再看一个最小“阈值先筛一轮”示例”
predictions = [
{"class": "person", "score": 0.93},
{"class": "person", "score": 0.48},
{"class": "dog", "score": 0.78},
]
def filter_by_score(preds, threshold=0.5):
return [pred for pred in preds if pred["score"] >= threshold]
print(filter_by_score(predictions, threshold=0.5))

预期输出:

Terminal window
[{'class': 'person', 'score': 0.93}, {'class': 'dog', 'score': 0.78}]

低分的 person 候选被移除了。真实项目里,调整这个阈值会直接影响漏检和误检之间的平衡。

这个示例很适合初学者,因为它会帮助你看到:

  • 检测系统通常不是直接拿全部候选去画框
  • 而是会先用分数和规则筛一轮

YOLO 候选框、阈值与 NMS 图


四、为什么 YOLO 在工程上这么受欢迎?

Section titled “四、为什么 YOLO 在工程上这么受欢迎?”

很多场景直接要求:

  • 摄像头实时检测
  • 边缘设备快速响应

YOLO 这类路线很适合这种需求。

对很多工程同学来说,它比复杂多阶段管线更容易落地。

这让它在真实项目里更常被优先尝试。

第一次做实时检测项目时,为什么很多团队会先试 YOLO?

Section titled “第一次做实时检测项目时,为什么很多团队会先试 YOLO?”

因为 YOLO 往往同时满足了几个很现实的条件:

  • 上手快
  • 推理链短
  • 社区模型多
  • 部署资料多

也就是说,它的吸引力不只是精度, 而是:

它特别容易先跑出一个“工程上能看见效果”的版本。

如果把 YOLO 放进项目里,最值得先展示什么

Section titled “如果把 YOLO 放进项目里,最值得先展示什么”

最值得展示的通常不是:

  • 只贴一张检测效果图

而是:

  1. baseline 检测结果
  2. 阈值调整前后对比
  3. NMS 前后框变化
  4. 误检、漏检、小目标案例

这样别人会更容易看出:

  • 你理解的是检测链路
  • 不只是调用了一个现成模型

YOLO 是重要路线,但不是全部。

还要看:

  • 小目标表现
  • 框定位质量
  • 部署约束

NMS、阈值设置这些后处理会直接影响最终体验。

六、第一次做 YOLO 项目时,最稳的默认顺序

Section titled “六、第一次做 YOLO 项目时,最稳的默认顺序”

第一次把 YOLO 放进项目里,通常更稳的顺序是:

  1. 先把类别边界和标注规范定清楚
  2. 先用默认模型和默认阈值跑出 baseline
  3. 先看误检、漏检、小目标表现
  4. 再调阈值和 NMS
  5. 最后再考虑更换更大模型或更复杂增强

这个顺序很重要,因为很多新人最容易犯的错是:

  • 一上来就换模型
  • 但根本没看清 baseline 到底错在哪

一个新人可直接照抄的排查顺序

Section titled “一个新人可直接照抄的排查顺序”

如果 YOLO 项目效果不理想,更稳的排查顺序通常是:

  1. 先看类别边界和标注规范
  2. 再看 score threshold 和 NMS
  3. 再看误检 / 漏检主要集中在哪类目标
  4. 最后再考虑换更大模型或更复杂增强

这样通常比直接换版本号更有效。


学完这一页,至少保留这张证据卡:

输入图像
带有真实或期望目标的检测样本
预测
框、标签、置信分数、IoU 和阈值设置
指标
精确率/召回率、mAP、误报和漏报
失败检查
小目标、重叠、NMS、标签差或置信度阈值问题
期望产出
带标注的图片,以及检测指标或错误分组

这节最重要的是建立一个工程判断:

YOLO 代表的是单阶段、实时友好的检测路线,它之所以广泛流行,不只是因为“能检测”,而是因为“更容易在工程里快速检测”。

  • YOLO 最重要的不是版本号,而是它代表的单阶段实时路线
  • 它的输出通常是一批候选框,后处理是检测链的一部分
  • 第一次做项目时,先把 baseline 的误检和漏检看清,再谈模型升级

  1. 调整示例里的 iou_threshold,看看保留框数如何变化。
  2. 用自己的话解释:为什么单阶段检测更容易做到实时?
  3. 为什么 NMS 对检测任务很重要?
  4. 想一想:什么时候你可能不会优先选 YOLO?
解题思路与讲解
  1. 在 NMS 里,iou_threshold 越高,通常抑制越不严格,留下的重叠框可能更多;阈值越低,抑制越激进。
  2. 一阶段检测更容易做到实时,因为框和类别在一次前向传播中直接预测,不需要单独的 proposal 阶段。
  3. NMS 很重要,因为检测器常会为同一个目标输出多个重叠框。NMS 会保留最可信的框,并去掉重复框。
  4. 如果项目更看重严格的小目标精度、精细定位、严重遮挡处理,或非实时的高精度复核,就不一定优先选 YOLO。