查看全课大纲(第 64 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

YOLOv2_9000

YOLO v2 与 YOLO 9000

小象实战讲义 · 基于深度学习的计算机视觉

在上一节我们学习了YOLO v1,它以其“只看一次”的端到端检测思想带来了速度上的巨大优势,但也在定位精度和小目标检测上存在不足。本节我们将深入剖析YOLO v2,它通过一系列精心设计的改进,在保持速度优势的同时,显著提升了检测精度。我们还将了解其衍生版本YOLO 9000,看看它是如何实现同时检测超过9000个类别(9418类)的“疯狂”目标的。

💡 核心导读

  • 性能提升的基石:了解Batch Normalization和高分辨率分类器如何为YOLO v2带来稳定的性能增益。
  • Anchor Box的回归与优化:学习YOLO v2如何借鉴并改进Faster R-CNN的Anchor思想,通过聚类和位置预测限制来解决模型不稳定问题。
  • 网络架构的革新:认识全新的骨干网络Darknet-19,以及Passthrough层、多尺度训练等提升小目标检测和模型鲁棒性的关键技术。
  • 迈向大规模检测:探索YOLO 9000如何利用WordTree整合不同数据集,实现联合分类与检测,从而识别海量物体类别。

一、 核心改进:从稳定训练到高分辨率

YOLO v2并非对v1的简单修补,而是一系列系统性的改进。我们首先来看两项奠定性能基础的关键技术。

1. Batch Normalization(批归一化)

YOLO v2在所有卷积层之后都加入了Batch Normalization(BN)。我们之前课程中详细讲解过BN,它的核心作用是规范化每一层的输入分布,使其均值为0,方差为1。

带来的好处:

  • 平滑解空间:使损失函数的优化地形更加平滑,模型更容易收敛。
  • 加速训练:允许使用更高的学习率,加快训练速度。
  • 抑制过拟合:BN本身具有一定的正则化效果,使得YOLO v2在不使用Dropout的情况下,也能有效避免过拟合。

仅加入BN这一项改进,就在PASCAL VOC数据集上为YOLO v2带来了约2%的mAP提升。在竞争激烈的检测任务中,每一个百分点的提升都至关重要。

2. High Resolution Classifier(高分辨率分类器)

目标检测模型通常先在ImageNet等大型分类数据集上进行预训练,再迁移到检测任务。传统的预训练输入分辨率多为224×224或256×256。YOLO v1在预训练后,直接将输入分辨率提升到448×448进行检测微调,这种“跳跃”可能使网络难以适应。

YOLO v2采用了更精细的两步预训练法:

  1. 第一阶段:使用标准的224×224分辨率在ImageNet上预训练网络约160个epoch。
  2. 第二阶段:将输入分辨率提升至448×448,继续在ImageNet上对网络进行约10个epoch的微调(fine-tuning)。

这种方法让网络有充足的时间去适应高分辨率输入带来的细节变化。高分辨率意味着网络能“看”到更清晰的图像细节,这对于精确定位物体边界至关重要。这项改进为YOLO v2带来了显著的4%的mAP提升。

二、 Anchor Box的引入与优化

YOLO v1在每个网格预测两个边界框,但这两个框的形状是模型自由学习的,缺乏先验引导。以7×7的输出为例,整张图能产生的候选框总共只有 7×7×2=98 个。YOLO v2借鉴了Faster R-CNN中Anchor Box(锚框) 的思想,但进行了一系列关键优化。

1. 引入Anchor Boxes

YOLO v2移除了v1中的全连接层,使网络变为全卷积结构。它在最后的特征图(如13×13)的每个单元格上设置多个先验的Anchor Box。网络的任务变为预测每个Anchor Box的偏移量(Δx, Δy, Δw, Δh) 以及该框内包含物体的置信度和类别概率。

初步效果:单纯引入Anchor Box后,模型的召回率(Recall)提升了约7%,这意味着模型能发现更多被遗漏的目标。因为Anchor Box提供了更多形状各异的候选框,覆盖了更多潜在的目标位置。然而,初版引入导致mAP略有下降,主要原因是训练变得不稳定。

2. Dimension Clusters(维度聚类)

Faster R-CNN的Anchor尺寸和长宽比(如1:1, 1:2, 2:1)是人工设定的。YOLO v2的作者认为,更好的先验应该来自于数据本身。

他们使用K-means聚类算法,在训练集的真实边界框(Ground Truth Boxes)上进行聚类,以自动找出最具代表性的框尺寸。距离度量没有使用标准的欧氏距离(这会使大框产生更大的误差),而是使用了如下公式: d(box,centroid)=1−IoU(box,centroid)d(\text{box}, \text{centroid}) = 1 - \text{IoU}(\text{box}, \text{centroid}) 其中IoU是交并比。这个距离只关心两个框的重叠程度。

聚类发现:在PASCAL VOC和COCO数据集上分别做k=5的聚类,得到的5个先验框里瘦高型占多数(对应人、动物这类常见目标),扁宽型只有1个,另有1个接近正方形。这反映了数据集中物体宽高比的真实分布,和人凭经验拍出的1:1、1:2、2:1并不一样。

作者还发现,k从5继续加到9仍有收益,但边际提升有限;k=5已经在模型复杂度和召回率之间取得很好的平衡。

使用数据驱动的聚类Anchor,取代了人工设计的Anchor,让先验知识更贴合实际。

3. Direct Location Prediction(直接位置预测)

引入Anchor后,训练不稳定的根源在于边界框中心坐标(x, y)的预测。在Faster R-CNN的RPN中,预测的是相对于Anchor中心的偏移量,且没有范围限制。这可能导致一个Anchor去预测远离其所在网格的目标,使得训练初期难以收敛。

YOLO v2改变了预测方式,将预测值约束在当前网格单元内。具体而言,对于特征图上的每个单元格(坐标为(c_x, c_y)),网络预测5个值:(t_x, t_y, t_w, t_h, t_o)。最终的边界框(b_x, b_y, b_w, b_h)计算如下: bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=pheth置信度=σ(to)\begin{aligned} b_x &= \sigma(t_x) + c_x \\ b_y &= \sigma(t_y) + c_y \\ b_w &= p_w e^{t_w} \\ b_h &= p_h e^{t_h} \\ \text{置信度} &= \sigma(t_o) \end{aligned} 其中:

  • σ是sigmoid函数,将t_x, t_y压缩到(0, 1)之间,确保预测的边界框中心不会偏移出当前单元格。
  • (c_x, c_y)是当前单元格左上角在特征图上的坐标,以单元格为单位(13×13的特征图上取012的整数),不是归一化到01的小数。
  • (p_w, p_h)是聚类得到的Anchor框的宽度和高度,同样以单元格为单位。
  • e^{t_w}, e^{t_h}用于缩放Anchor的尺寸。

通过sigmoid函数将中心坐标的偏移限制在当前单元格内,极大地稳定了训练过程。下面的代码演示了sigmoid函数如何将任意输入映射到(0,1)区间:

import numpy as np

# 模拟网络预测的原始偏移量 t_x, t_y
t_x = np.array([-10.0, -1.0, 0.0, 1.0, 10.0])
t_y = np.array([-5.0, 0.5, 2.0, 3.0, 5.0])

# 应用sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

b_x_offset = sigmoid(t_x)  # 相对于单元格的归一化偏移
b_y_offset = sigmoid(t_y)

print("原始偏移 t_x:", t_x)
print("sigmoid后 b_x_offset:", b_x_offset)
print("\n原始偏移 t_y:", t_y)
print("sigmoid后 b_y_offset:", b_y_offset)
原始偏移 t_x: [-10.  -1.   0.   1.  10.]
sigmoid后 b_x_offset: [4.53978687e-05 2.68941421e-01 5.00000000e-01 7.31058579e-01
 9.99954602e-01]

原始偏移 t_y: [-5.   0.5  2.   3.   5. ]
sigmoid后 b_y_offset: [0.00669285 0.62245933 0.88079708 0.95257413 0.99330715]

可以看到,无论原始预测值t_x或t_y多大或多小,经过sigmoid函数后,其值都被严格限制在(0,1)之间。这意味着网络预测的边界框中心点,只会落在以当前单元格左上角为原点,边长为1个单元格的范围内,从而避免了预测框“乱跑”的问题。

三、 网络架构与训练技巧

1. 13×13特征图的由来:为什么检测输入是416×416

YOLO v2最终在13×13的特征图上进行检测,这个数字直接来自输入尺寸与网络的下采样倍数:416 / 32 = 13。

这里有一个容易忽略的细节:分类预训练用的是448×448,检测阶段却换成了416×416。原因是引入Anchor后,作者希望特征图的网格数是奇数(13×13)——画面正中心恰好落在一个单元格里,居中放置的大目标有唯一的预测位置,而不用被中心附近的4个格子平分。而448 / 2 = 224、224 / 2 = 112……一路除下去全是偶数,最终得到14×14。为了得到奇数网格,检测阶段的输入被调整为416×416。

2. Fine-Grained Features(细粒度特征)与Passthrough层

13×13的分辨率对大目标够用,但对图像中的小目标就可能丢失太多细节。

为了解决小目标检测问题,YOLO v2引入了Passthrough层。该层将前一层更高分辨率的特征图(例如26×26×512)进行重组,然后在通道维度与深层低分辨率特征图(13×13×1024)拼接。

具体操作(以26×26×512 -> 13×13×2048为例):

  1. 把26×26的特征图看成13×13个2×2的小块。
  2. 按每个小块内部的4个相对位置(左上、右上、左下、右下)把元素拆开。
  3. 每个相对位置收集成一个通道组,得到13×13×(512*4)= 13×13×2048的新特征图。
  4. 再与原本的13×13×1024的特征图拼接,得到13×13×3072的特征图。

这个过程类似于在通道维度上进行的“空间重组”:尺度减小了,但原来的空间信息一个都没丢,只是被搬到了通道里。这项改进带来了约1%的mAP提升。

下面的代码用一张4×4×1的小特征图模拟一次Passthrough:

import numpy as np

# 一个4x4x1的浅层特征图(高分辨率、通道少),用0~15标记每个位置
high_res = np.arange(16).reshape(4, 4, 1)
print("原始高分辨率特征图 (4x4x1):")
print(high_res[:, :, 0])

# Passthrough:把4x4看成2x2个2x2小块,
# 每个小块内相对位置相同的元素收进同一个通道
passthrough = np.stack(
    [high_res[i::2, j::2, 0] for i in range(2) for j in range(2)],
    axis=-1,
)
print("\nPassthrough后形状:", passthrough.shape)

for k, (i, j) in enumerate([(0, 0), (0, 1), (1, 0), (1, 1)]):
    print(f"\n通道 {k}(各小块内相对位置 ({i}, {j}) 的元素):")
    print(passthrough[:, :, k])
原始高分辨率特征图 (4x4x1):
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]

Passthrough后形状: (2, 2, 4)

通道 0(各小块内相对位置 (0, 0) 的元素):
[[ 0  2]
 [ 8 10]]

通道 1(各小块内相对位置 (0, 1) 的元素):
[[ 1  3]
 [ 9 11]]

通道 2(各小块内相对位置 (1, 0) 的元素):
[[ 4  6]
 [12 14]]

通道 3(各小块内相对位置 (1, 1) 的元素):
[[ 5  7]
 [13 15]]

注意通道的含义:第k个通道收集的是每个2×2小块中同一相对位置的元素,而不是把4个象限各自压成一个通道。

3. Multi-Scale Training(多尺度训练)

由于Darknet-19取消了全连接层、只由卷积和池化组成(下一小节详述),网络可以接受任意尺寸的输入图像。YOLO v2利用了这一特性,在训练过程中每10个批次(batch),就随机选择一个新的输入图像尺寸。

尺度选择:从集合{320, 352, 384, 416, 448, 480, 512, 544, 576, 608}中随机选取,这些尺寸都是32的倍数(因为网络下采样倍数为32)。

好处:

  • 提高模型鲁棒性:迫使模型学习在不同尺度下检测目标,更好地泛化到各种分辨率的输入图像,也避免对某一固定尺度过拟合。
  • 实现速度与精度的折衷:在测试时,可以用较小尺寸(如320)实现更快的检测,或用较大尺寸(如608)实现更高的精度。

4. 新的骨干网络:Darknet-19

YOLO v1使用受GoogLeNet启发的自定义网络(24个卷积层+2个全连接层,用1×1降维卷积替代Inception模块)作为特征提取器。YOLO v2提出了一个更简洁、高效的网络——Darknet-19。它包含19个卷积层和5个最大池化层,其特点如下:

  • 大量使用3×3卷积:借鉴VGG的思想,用多个小卷积核代替大卷积核。
  • 使用1×1卷积进行通道降维:在3×3卷积之间插入1×1卷积,压缩特征通道数,减少计算量。
  • 引入全局平均池化(Global Average Pooling):替代全连接层进行分类,大大减少参数数量,并防止过拟合。
  • 整合Batch Normalization:在每个卷积层后都加入BN层以稳定训练。

Darknet-19在ImageNet上能达到top-1准确率72.9%,top-5准确率91.2%,同时保持了较快的速度。也正是这种全卷积结构(没有全连接层),让上一小节的多尺度训练得以成立。

四、 性能总结与YOLO 9000

1. YOLO v2性能一览

将上述所有改进累积起来,YOLO v2在PASCAL VOC 2007数据集上的mAP从v1的63.4% 提升到了78.6%,同时保持了实时检测的速度。需要注意78.6%对应的是544×544输入(Titan X上约40 FPS);若用416×416输入,mAP为76.8%、速度约67 FPS,288×288输入则可达约91 FPS(mAP 69.0)。下表概括了各项改进的贡献:

改进措施mAP提升关键作用
Batch Normalization+2.0%稳定训练,加速收敛,正则化
High Resolution Classifier+4.0%适应高分辨率输入,提升细节感知
Convolutional With Anchor Boxes召回率+7%,mAP略降提供形状先验,增加候选框
Dimension Clusters(结合后)数据驱动的Anchor尺寸,更贴合实际
Direct Location Prediction(结合后)约束预测范围,解决训练不稳定
Fine-Grained Features (Passthrough)+1.0%引入细粒度特征,改善小目标检测
累计效果 (VOC 2007)+15.2%mAP从63.4%提升至78.6%

2. YOLO 9000:联合分类与检测

YOLO 9000是YOLO v2的一个变种,其目标不是进一步提升精度,而是极大地扩展可检测的类别数量。它能够实时检测超过9000个类别(WordTree 规模为 9418 类)的不同物体。

核心挑战:检测数据集(如COCO,80类)类别少但标注精细(有边界框);分类数据集(如ImageNet,两万多个类别)类别多但只有图像级标签。如何让模型同时利用这两种数据?

解决方案:WordTree与联合训练

  1. 构建WordTree:利用WordNet(一个词汇语义网络)构建一个层次化的标签树。例如,“狗”是“哺乳动物”的子类,“哺乳动物”是“动物”的子类。作者用 WordNet 构建出覆盖 9418 个类别的 WordTree(并非 ImageNet 全部两万多个类别),再把 COCO 的 80 类映射到这棵树上。
  2. 联合训练(Joint Training):
    • 当输入是检测图片时,反向传播完整的损失(包括边界框坐标、置信度和分类损失)。
    • 当输入是分类图片时,只反向传播分类损失。在WordTree上,分类损失是从预测的特定类别一直向上追溯到根节点的路径上的损失之和。例如,对于一张“拉布拉多犬”的图片,模型需要同时在“狗”、“哺乳动物”、“动物”等层级做出正确的预测。
  3. 预测时的层次化softmax:在预测时,沿着WordTree向下遍历,在每个节点使用softmax在子类间进行选择,直到达到某个置信度阈值或叶子节点。

通过这种方式,YOLO 9000将检测数据集的精确定位能力和分类数据集的庞大类别信息结合起来,创造了一个能识别超过9000个类别(9418类)的检测器。需要如实说明:它在COCO类别上的检测精度明显低于YOLO v2——联合训练把模型容量分摊到九千多个类别上,单类精度必然让步——但它展示了迈向大规模、通用物体检测的重要一步。

📝 动手练一练

  1. 概念辨析:YOLO v2引入Anchor Box后,最初的mAP反而有所下降,但作者仍然保留了这项改进。请问主要原因是什么?随后又通过哪两项关键技术解决了mAP下降的问题?
  2. 代码思考:在“直接位置预测”的代码演示中,网络输出的t_x原始值为2.0,σ(2.0)≈0.881。假设当前单元格在13×13特征图上的左上角横坐标c_x = 5(即以单元格为单位),最终预测框中心的b_x是多少?它为什么不可能跑出当前单元格?换成416×416输入时,这个偏移对应多少像素?
👉 点击查看参考答案
  1. 答案:主要原因是召回率(Recall)显著提升了约7%,意味着模型能检测到更多目标。虽然定位精度(影响mAP)暂时下降,但召回率的提升是更有价值的。随后通过Dimension Clusters(维度聚类) 和 Direct Location Prediction(直接位置预测) 两项关键技术解决了训练不稳定和定位不准的问题,最终使mAP得到大幅提升。
  2. 答案:b_x = σ(t_x) + c_x ≈ 0.881 + 5 = 5.881。这里的坐标以单元格为单位,13×13特征图的取值范围是013,不是归一化到01的小数。因为 σ(tx)\sigma(t_x) 恒在 (0,1) 之间,b_x必然落在(c_x, c_x+1)即(5, 6)区间内——中心点一定还在当前单元格里,只是偏向右侧约0.88个单元格,这正是直接位置预测收敛稳定的原因。换算到416×416输入:每个单元格对应416/13=32像素,0.881×32≈28像素。

本章小结

本节我们深入解析了YOLO v2,它通过一系列精巧且系统的改进,在YOLO v1的基础上实现了性能的飞跃。从稳定训练的Batch Normalization,到提升细节感知的高分辨率分类器;从借鉴并优化Anchor Box机制,到提升小目标检测的Passthrough层、增强鲁棒性的多尺度训练,再到全新的骨干网络Darknet-19,每一步改进都直指v1的痛点。最后,我们还看到了YOLO 9000如何利用层次化标签树进行联合训练,将检测模型的能力边界拓展到超过9000个类别(9418类),展示了通用物体检测的潜力。

YOLO v2的成功在于它没有盲目追求单一指标的突破,而是在速度、精度、鲁棒性和扩展性之间取得了出色的平衡,为后续YOLO系列的发展奠定了坚实的基础。

最后补一句历史定位:YOLO v2是2016年的工作(CVPR 2017),本节的Anchor聚类、直接位置预测、Darknet-19都是那个阶段的代表做法。此后YOLOv3用多尺度特征金字塔替代了单一的Passthrough层,检测器又先后走过anchor-free(如FCOS)、自适应标签分配(如YOLOv5/v8系列)和基于Transformer的DETR路线;YOLO 9000的WordTree层次分类,在今天则被开放词表检测用文本嵌入的方式重新实现。读这一节,重点是把“用先验框约束回归”的动机吃透,具体结构不必当作当前最佳实践。

📋 行动清单

  • 梳理改进清单:默写或复述YOLO v2的主要改进措施及其各自贡献(BN +2% mAP、高分辨率分类器 +4% mAP、Passthrough +1% mAP,以及Anchor聚类、直接位置预测、多尺度训练与Darknet-19骨干)。
  • 理解核心机制:重点理解Dimension Clusters和Direct Location Prediction是如何解决Anchor Box引入后的训练不稳定问题的。
  • 思考应用场景:如果让你为一个监控场景(小目标多,如停车场车辆)选择模型,YOLO v2的哪项改进对你最有吸引力?为什么?

—— 小象教研组