跳到主要内容

目标检测:从滑窗到 YOLO

这一章讲三件事: 「检测」比「分类」多出来的那个「在哪」怎么解; R-CNN 到 YOLO 的整条进化线,每一步在修前一步的哪个耗时点; 以及怎么用开源(公开源代码、免费可用)工具训练识别你自己关心的目标。 这一章也是全书「工程进化史」最集中的一章——算法不是为了优雅而发明,是为了快。

1. 问题升级:从「是什么」到「在哪里」

前面章节的分类模型回答「这张图是什么」;目标检测要多答一个「在哪」,而且往往图里不止一个目标。书里用 Joseph Redmon(YOLO 发明人)的照片开场:机器人要翻煎饼,必须知道饼的位置才能翻;有两张饼,还得知道该翻哪张1。应用从自动驾驶(实时掌握路况避障)、智能交通(两个时间点的位置差算车速,进而推拥堵、抓违规),到生产线瑕疵检测、无人商店自动结账2

任务本身可以拆成两个老朋友的组合3:

检测 = 分类(框里是什么) + 回归(框在哪:左上角坐标 + 宽高)

按「标到多细」分四档(两条线在本章,分割两条线在第 09 章):定位(单对象类别+位置)、目标检测(多对象);语义(类别含义)分割(按类别给像素上色,两只狗同色)、实例分割(连同类个体也分开)4

2. 史前时代:没有神经网络的检测

滑窗+影像金字塔:设定一个窗口,从左上角开始裁一块、分类、滑一格、再裁……扫完整图后,把原图缩小再来一轮——这样大目标小目标都逃不掉。缩图的套路叫影像金字塔5。穷举的天真,恰是它准确的天真:它不偷工,但慢

HOG(方向梯度直方图)+分类器:HOG 把图切成小块,统计每块的边缘方向,拼出目标的轮廓特征;然后配一个分类器判「有没有目标」。书里照一篇经典流程完整实战了一遍人脸检测6:

  1. 正样本:13233 张人脸;负样本:不含人脸的图(负样本扩到 27000 批);
  2. 训练二分类器(SVM,配合网格搜索调参):最佳模型准确率 98.77%;
  3. Hard-negative Mining:用模型扫负样本,凡是误报的窗口(伪阳性)塞回训练集重训,反复几轮——类似 Boosting 的思路;
  4. 实测:滑窗扫出 55 个合格窗口——同一张脸周围全是重叠的框;
  5. NMS(非极大值抑制):按重叠比例阈值(常取 0.3~0.5)把「同一目标的一堆框」合并成一个,最后剩下 2 个框,正好两张脸7

这一节的三样东西全部活到了今天:滑窗思想变成了 Anchor(见后)、NMS 是所有检测器的标配后处理、「把误报喂回去重训」的思路仍在用。书里随后用 ResNet50+滑窗做了现代版:三匹斑马因为重叠只检测到两匹——通用分类器逐窗打分的思路到顶了8

3. R-CNN:神经网络进场,以及它的笨办法

2014 年 R-CNN(Rich feature hierarchies)开山,流程五步9:

  1. 区域推荐(Region Proposal):不再穷举窗口,用 Selective Search 算法按颜色、纹理、规模、空间关系合并相似区域,只挑 2000 个「可能有东西」的候选框;
  2. 每个候选框变形到固定尺寸,送 CNN 提特征(AlexNet 出 4096 维向量);
  3. SVM 分类器判断框里是什么(一类一个二分类器);
  4. NMS 用 IoU(交并比:两框交集面积/并集面积,越高越重叠)剔重复框;
  5. 回归微调框的位置。

骨架已备,但每一环都在烧时间。书里算过账:R-CNN 的三大痛点——2000 个框逐个过 CNN(2000×4096=8 192 000 个特征向量,内存爆满)、区域推荐算法没有学习能力、三个模型串成流水线复杂;结果是一张图要 40 多秒——自动驾驶等不起10

4. 进化线:哪里耗时修哪里

R-CNN 之后的每一步,都是对着一个具体瓶颈动刀11:

算法修了什么还剩什么病
SPP-Net2000 个框逐个过 CNN → 一张图只过一次 CNN,SPP 层把任意尺寸的特征压成固定长度SVM 和回归还是慢
Fast R-CNN整图先提特征,候选框按坐标映射(按坐标换算)去特征图上取(ROI pooling)Selective Search 挑 2000 框仍然慢
Faster R-CNN把「找候选框」也换成网络:RPN(Region Proposal Network)+ 9 种预设尺寸的 Anchor Box(滑动窗口按 Anchor 生成框)仍是「两阶段」:先找框再分类,快不过一阶段

到了 Detectron2(Facebook 的现成实现)实测,之前滑窗版漏检的那三匹重叠斑马:三个框全部抓到,信赖度 0.9992 / 0.9986 / 0.9983,顺带输出每个对象的像素级 Mask(已做到实例分割)12

两阶段的天花板:先推荐再分类,无论如何要两趟。于是出现了**一阶段(Single Shot)**算法,两大代表:YOLO 与 SSD。

5. YOLO:You Only Look Once

书里引用了 YOLO 发明人在 2016 年 CVPR 的著名对比,这是「检测为什么必须快」的最直观版本:车身长约 8 英尺,Faster R-CNN 算完一次结果,车已经开出 12 英尺(1.5 个车身);YOLO 只要 2 英尺(1/4 个车身)13。高速上,这个差值就是安全距离。

YOLO 的快,靠的是结构性的取舍14:

  1. 放弃区域推荐——用 K-Means 从训练数据里统计出最常见的 N 种框尺寸当 Anchor(框的先验从算法猜变成数据统计);
  2. 图像直接划成 s×s 网格,每个网格只负责检查几种尺寸的 Anchor 里「有没有对象」;
  3. 一次前向传播(数据从头到尾过一遍网络)同时算出:每个 Anchor 含对象的概率+每个网格各类别的概率;
  4. 合并信息、NMS 去重,一遍结束——「只看一次」(You Only Look Once)。

代价:早期版本为了速度牺牲精度(书里明说「快是牺牲准确率所换来的」);其 C/CUDA 实现叫 Darknet。配套实测:官方权重跑 dog.jpg,自行车 92%、狗 98%、货车 92%、盆栽 33%15。另有 SSD,同属一阶段,曾以「比 R-CNN 快、比 YOLO v1 准」立足,后随 YOLO 迭代声量下降16

6. 换成你自己的目标:标注、配置、训练

YOLO 默认模型认 COCO 数据集的 80 类。要检测别的目标,书里给了一条完整的自助流水线(以「气球/人/狗」三类为例)17:

① 标注:LabelImg 给每张图画框,生成标注文件
格式:<类别ID> <框中心X> <框中心Y> <宽> <高>
② 改配置(以 3 类为例):
max_batches = 类别数×2000 = 6000 ← 训练轮数随类别数走
filters = (类别数+5)×3 = 24 ← 输出层通道数跟着类别数改
classes = 3
③ 显存不够:batch 64→16(代价是训练更久、效果可能打折)
④ 训练:300 张图约 6~8 小时;中途断了可从上一检查点续训

实测结果同样诚实:训练完测试,人和气球抓到了,但气球的信赖度只有 0.31——作者自己分析,可能与 batch 被迫降到 16(原作者建议 64)或训练量不足有关18。书里给这条流水线写的结语很直白:最重要的是一台高性能 GPU 机器,「用金钱换时间」19

6a. TF 这边怎么接:权重转换与 Object Detection API

YOLO 的 Darknet 是 C/CUDA 世界,想留在 TensorFlow 里有两条现成路(原书 8-8/8-11 两节):

  1. 把 YOLO 权重转成 Keras 格式:用 Keras 重建 YOLO 模型结构,加载官方权重文件,再 Save()——从此就是普通 Keras 模型;输出是三个尺度的特征图 [(1,13,13,255)、(1,26,26,255)、(1,52,52,255)],经 NMS 后处理得到框20。另一条路是不转换、直接加载权重文件使用:书里用 kite.jpg 实测,成功标示出人和飞行伞21
  2. TensorFlow Object Detection API:TF 官方的检测模型库,内含 CenterNet、EfficientDet、SSD、Faster R-CNN22。书里还给了一个工程细节的对照:同一模型,一种加载方式花 160.80 秒,另一种只要 0.5 秒——同一份模型,加载姿势不同,差 300 倍23。支持视频检测,也能接 WebCam。

7. 效果衡量:mAP

检测的效果不看单一准确率,看 mAP(mean Average Precision,平均精确度均值):以 IoU 为阈值,画出各阈值下的精确率-召回率曲线(召回率横轴、精确率纵轴),再对多类别取平均。它是第 04 章「精确率/召回率」的检测版——不同点在于判「框得对不对」要过 IoU 这道门24

8. 可带走的

  1. 检测=分类+回归:类别+左上角坐标+宽高;四档粒度(定位/检测/语义分割/实例分割)按需选;
  2. 史前方案不丢人:滑窗+影像金字塔+HOG+SVM(人脸 98.77%)教完了整条流水线——NMS 和「误报喂回重训」至今标配;
  3. R-CNN 家族是一条「耗时点迁移」链:2000 框逐个过 CNN(40 多秒/张,8192000 个特征向量)→整图一次 CNN→候选框也交给网络(RPN+Anchor);Detectron2 实测三匹斑马信赖度 0.9992/0.9986/0.9983;
  4. IoU(交并比)是检测的通用语言:NMS 去重看它,评估 mAP 也看它;
  5. YOLO 快在「只看一次」:放弃区域推荐,网格+Anchor 一趟前向全出;Anchor 尺寸用 K-Means 从数据统计;
  6. 快与准是取舍:YOLO 早期牺牲精度换实时(12 英尺 vs 2 英尺的车距账);
  7. 自训三件套:标注文件格式、配置公式(max_batches=类别数×2000、filters=(类别数+5)×3)、显存换 batch;300 张图 6~8 小时,气球 0.31 的教训——硬件和训练量偷不得懒;
  8. 检测看 mAP:精确率-召回率曲线+IoU 门槛,多类别取平均;
  9. 前沿在动:姿态检测(判断运动姿势是否标准)、手势、体感游戏——检测的「框」正在变成「骨架」25;
  10. TF 侧的两条接入路:权重转 Keras(.h5)或直接用权重文件;TF OD API 内含 CenterNet/EfficientDet/SSD/Faster R-CNN——同一模型加载姿势不同,160.80 秒 vs 0.5 秒。

9. 原文地图

主题原书章原文位置
煎饼机器人、检测=分类+回归第8章 目标检测 · 8-2 滑动窗口text/55-ch08.txt:15(搜「机器人要能完成煎饼」) · text/57-ch08-8-2.txt:7(搜「辨识对象的类别」)
四档粒度8-1 图像辨识模型的发展text/56-ch08-8-1.txt:15(搜「语义分割:按照对象类别」) · text/56-ch08-8-1.txt:21(搜「实例分割(Instance Segmentation」)
滑窗与影像金字塔8-2 滑动窗口text/57-ch08-8-2.txt:25(搜「影像金字塔(Image Pyramid」)
HOG 实战全流程8-3 方向梯度直方图text/58-ch08-8-3.txt:43(搜「13233」) · text/58-ch08-8-3.txt:67(搜「最佳模型准确率为98.77%」) · text/58-ch08-8-3.txt:83(搜「55个合格窗口」)
Hard-negative Mining、NMS8-3 方向梯度直方图text/58-ch08-8-3.txt:25(搜「Hard-negative Mining」) · text/58-ch08-8-3.txt:97(搜「OverlapThresh」)
ResNet50 漏检斑马8-3 方向梯度直方图text/58-ch08-8-3.txt:129(搜「因为图中的斑马有重叠」)
R-CNN 流程、Select Search、IoU8-4 R-CNN目标检测text/59-ch08-8-4-r-cnn.txt:41(搜「区域推荐(Region Proposal」) · text/59-ch08-8-4-r-cnn.txt:43(搜「Selective Search」) · text/59-ch08-8-4-r-cnn.txt:53(搜「IoU(Intersection-over Union」)
R-CNN 三痛点、40 多秒8-4 R-CNN目标检测text/59-ch08-8-4-r-cnn.txt:151(搜「8 192 000」) · text/59-ch08-8-4-r-cnn.txt:155(搜「40多秒」)
SPP-Net→Fast→Faster8-5 R-CNN改良text/60-ch08-8-5-r-cnn.txt:7(搜「Spatial Pyramid Pooling」) · text/60-ch08-8-5-r-cnn.txt:49(搜「RPN(Region Proposal Network」)
Detectron2 斑马实测8-5 R-CNN改良text/60-ch08-8-5-r-cnn.txt:91(搜「0.9992」) · text/60-ch08-8-5-r-cnn.txt:99(搜「还有准确的屏蔽」)
12 英尺 vs 2 英尺8-6 YOLO算法简介text/61-ch08-8-6-yolo.txt:11(搜「车子早已行驶了12英尺」)
YOLO 四步取舍、Darknet8-6 YOLO算法简介text/61-ch08-8-6-yolo.txt:45(搜「K-Means」) · text/61-ch08-8-6-yolo.txt:65(搜「Darknet」)
dog.jpg 实测概率8-7 YOLO环境配置text/62-ch08-8-7-yolo.txt:47(搜「92%、98%、92%、33%」)
SSD 定位8-10 SSD算法text/65-ch08-8-10-ssd.txt:5(搜「Single Shot MultiBox Detector」)
自定义训练全流程8-9 YOLO模型训练text/64-ch08-8-9-yolo.txt:7(搜「COCO数据集」) · text/64-ch08-8-9-yolo.txt:83(搜「batch=16」) · text/64-ch08-8-9-yolo.txt:87(搜「max_batches = 6000」) · text/64-ch08-8-9-yolo.txt:97(搜「filters=24」)
训练 8 小时、气球 0.318-9 YOLO模型训练text/64-ch08-8-9-yolo.txt:141(搜「8小时」) · text/64-ch08-8-9-yolo.txt:159(搜「0.31」)
用金钱换时间8-9 YOLO模型训练text/64-ch08-8-9-yolo.txt:163(搜「用金钱换时间」)
mAP 定义8-12 目标检测的效果衡量指标text/67-ch08-8-12.txt:5(搜「mAP」)
动态检测前沿8-13 总结text/68-ch08-8-13.txt:11(搜「姿态(Pose)侦测」)

Footnotes

  1. 出处:「第8章 目标检测」第 15 段(text/55-ch08.txt:15,搜「机器人要能完成煎饼」)。

  2. 出处:「第8章 目标检测」第 17 段(text/55-ch08.txt:17,搜「自动驾驶汽车」)。

  3. 出处:「8-2 滑动窗口」第 7 段(text/57-ch08-8-2.txt:7,搜「辨识对象的类别」)。分类+回归两项任务在同段与其后。

  4. 出处:「8-1 图像辨识模型的发展」第 15 段(text/56-ch08-8-1.txt:15,搜「语义分割:按照对象类别」)与第 17 段(text/56-ch08-8-1.txt:17,搜「定位(Classification + Localization」)、第 21 段(text/56-ch08-8-1.txt:21,搜「实例分割(Instance Segmentation」)。

  5. 出处:「8-2 滑动窗口」第 25 段(text/57-ch08-8-2.txt:25,搜「影像金字塔(Image Pyramid」)。

  6. 出处:「8-3 方向梯度直方图」第 43 段(text/58-ch08-8-3.txt:43,搜「13233」)、第 67 段(text/58-ch08-8-3.txt:67,搜「最佳模型准确率为98.77%」)、第 83 段(text/58-ch08-8-3.txt:83,搜「55个合格窗口」)。负样本 27000 批在第 51 段(搜「27000」)。

  7. 出处:「8-3 方向梯度直方图」第 25 段(text/58-ch08-8-3.txt:25,搜「Hard-negative Mining」)与第 97 段(text/58-ch08-8-3.txt:97,搜「OverlapThresh」)。最后剩两个窗口在第 101 段(搜「两个合格窗口」)。

  8. 出处:「8-3 方向梯度直方图」第 129 段(text/58-ch08-8-3.txt:129,搜「因为图中的斑马有重叠」)。

  9. 出处:「8-4 R-CNN目标检测」第 41 段(text/59-ch08-8-4-r-cnn.txt:41,搜「区域推荐(Region Proposal」)、第 43 段(text/59-ch08-8-4-r-cnn.txt:43,搜「Selective Search」)、第 53 段(text/59-ch08-8-4-r-cnn.txt:53,搜「IoU(Intersection-over Union」)。

  10. 出处:「8-4 R-CNN目标检测」第 147 段(text/59-ch08-8-4-r-cnn.txt:147,搜「不尽理想的原因」)、第 151 段(text/59-ch08-8-4-r-cnn.txt:151,搜「8 192 000」)与第 155 段(text/59-ch08-8-4-r-cnn.txt:155,搜「40多秒」)。

  11. 出处:「8-5 R-CNN改良」第 7 段(text/60-ch08-8-5-r-cnn.txt:7,搜「Spatial Pyramid Pooling」)与第 49 段(text/60-ch08-8-5-r-cnn.txt:49,搜「RPN(Region Proposal Network」)。Fast R-CNN 的做法与优缺点在第 29~37 段(搜「Fast R-CNN做法如下」)。

  12. 出处:「8-5 R-CNN改良」第 91 段(text/60-ch08-8-5-r-cnn.txt:91,搜「0.9992」)与第 99 段(text/60-ch08-8-5-r-cnn.txt:99,搜「还有准确的屏蔽」)。

  13. 出处:「8-6 YOLO算法简介」第 11 段(text/61-ch08-8-6-yolo.txt:11,搜「车子早已行驶了12英尺」)。

  14. 出处:「8-6 YOLO算法简介」第 41 段(text/61-ch08-8-6-yolo.txt:41,搜「牺牲准确率所换来的」)、第 45 段(text/61-ch08-8-6-yolo.txt:45,搜「K-Means」)与第 65 段(text/61-ch08-8-6-yolo.txt:65,搜「Darknet」)。

  15. 出处:「8-7 YOLO环境配置」第 47 段(text/62-ch08-8-7-yolo.txt:47,搜「92%、98%、92%、33%」)。

  16. 出处:「8-10 SSD算法」第 5 段(text/65-ch08-8-10-ssd.txt:5,搜「Single Shot MultiBox Detector」)。

  17. 出处:「8-9 YOLO模型训练」第 7 段(text/64-ch08-8-9-yolo.txt:7,搜「COCO数据集」)、第 83 段(text/64-ch08-8-9-yolo.txt:83,搜「batch=16」)、第 87 段(text/64-ch08-8-9-yolo.txt:87,搜「max_batches = 6000」)、第 97 段(text/64-ch08-8-9-yolo.txt:97,搜「filters=24」)。标注格式在第 65 段(搜「标注框中心点X坐标」)。

  18. 出处:「8-9 YOLO模型训练」第 141 段(text/64-ch08-8-9-yolo.txt:141,搜「8小时」)与第 159 段(text/64-ch08-8-9-yolo.txt:159,搜「0.31」)。

  19. 出处:「8-9 YOLO模型训练」第 163 段(text/64-ch08-8-9-yolo.txt:163,搜「用金钱换时间」)。

  20. 出处:「8-8 以TensorFlow实践YOLO模型」第 7 段(text/63-ch08-8-8-tensorflow-yolo.txt:7,搜「转为TensorFlow/Keras格式」)与第 13 段(text/63-ch08-8-8-tensorflow-yolo.txt:13,搜「How to Perform」)。三尺度输出见「8-8」范例 2 的执行结果。

  21. 出处:「8-8 以TensorFlow实践YOLO模型」范例 3(text/63-ch08-8-8-tensorflow-yolo.txt:61,搜「kite.jpg」)。

  22. 出处:「8-11 TensorFlow Object Detection API」第 7 段(text/66-ch08-8-11-tensorflow-object-detection-api.txt:7,搜「CenterNet、EfficientDet」)。

  23. 出处:「8-11 TensorFlow Object Detection API」第 83 段(text/66-ch08-8-11-tensorflow-object-detection-api.txt:83,搜「160.80秒」)与第 109 段(text/66-ch08-8-11-tensorflow-object-detection-api.txt:109,搜「0.5秒」)。

  24. 出处:「8-12 目标检测的效果衡量指标」第 5 段(text/67-ch08-8-12.txt:5,搜「mAP」)与第 13 段(text/67-ch08-8-12.txt:13,搜「以IoU为基准」)。

  25. 出处:「8-13 总结」第 11 段(text/68-ch08-8-13.txt:11,搜「姿态(Pose)侦测」)。