【YOLO详解】You Only Look Once(一):YOLO 原论文笔记

You Only Look Once:
Unified, Real-Time Object Detection
; Joseph Redmon, Santosh Divvala, Ross Girshick, Ali Farhadi; University of Washington, Allen Institute for AI, Facebook AI Research

原文:https://arxiv.org/pdf/1506.02640.pdf

我:和 YOLO 小打小闹半年了
也是我:这是什么 → 看博客看源码 → 这是什么 → 看博客看源码 → 这是什么 → 看博客看源码 → 这是什么

是骡子也不能在这递归YOLO (∞) … 所以说脑子不好使就得记下来 …



1. Background

YOLO 本身是目标检测算法,简单来说就是分成两个部分,先找到图像中的物体的位置 → 再进行图像分类确认它是什么

在 YOLO 之前也有几个常用的方法:

  • deformable parts models (DPM)
    • 利用滑动窗口的思路,可以直观地理解为通过一个窗口在图片上滑动来一步一步爬着检测(虽然更多关于 DPM 的重点在优化 / 启发式算法 etc 上,这里就不过多涉及了)
    • 直观,但缺陷也十分明显(注意到物体在图中的位置和大小本身都是不确定的):此时移动的步长,起始位置,框的大小等都有很多的可能,不注意就是巨大的计算量(所以一般会配合启发式算法)

  • R-CNN 类
    • 总体思路:
      • 先生成多个候选区域(这里主要是通过相邻区域合并的方式生成的,也就是说此时生成的区域的大小并不是一定的,而后续的模型需要固定大小的输入,故这里再通过一个 CNN 来提取特征转化为固定大小的输入)
      • 扔进 SVM 里做分类(注意这里如果是 N 分类也就存在 N 个 SVM 的分类器)
      • 经过 NMS(非最大抑制,这个机制在 YOLO 里也有,后续介绍,简单来说就是将重合度比较大的框来进行合并)
      • rescore:通过 box regressor 进行修正
    • 缺点:慢!超慢!本身 SVM 分类的速度就很慢了,本身候选区域较多的时候带来的大量的特征数据还会很占存储,并且本身的优化是比较难做的(这里分为多个模块进行,比如生成候选区域是一个部分,后续的分类又是另外一个部分

YOLO 的思路很简单:将目标检测问题转化为一个回归问题进行求解,也就是说将图像作为输入(像素数据),直接输出物体的位置和所属于的类别的置信度(是以一个向量的形式表示的,后续会介绍),属于端到端的模型形式。

这种特点的模型存在几个优势:

  • 很快,YOLO 的训练和最后 inference 的速度较前面的几个思路都是快很多的
  • 不同于一般的滑动窗口的方式或事先筛选出候选区域的方式,YOLO 在处理图片的时候是直接输入整张图,也就是说较于上面的两种方式会有更多的上下文信息。也就是说 YOLO 在类似于 background error(也就是错误地将背景上的某一个东西当作目标切下来了) 的问题上会表现更好
  • 更容易学习到物体的泛化表示(也就是在这张图片上训练认识了狗,能够以更好的泛化性能同时认出来别的图片里的不太一样的狗)也就是说作为模型的泛化性能加强了

2. Model Structure

YOLO 是通过一个统一的神经网络来直接处理一张图片的,也就是说即使这个图片中存在多个目标,每一个目标还都是多分类问题,都是统一处理的;因此 YOLO 才能有比较好的速度;

2.1 overview 主要思路

  • 整个图片分为 S*S 的小区域,这里的 S 自己指定;注意到每一个目标 → 假设都存在一个 true answer 也就是针对这个目标的最好的检测框 → 则每一个目标的检测框的中心点一定是落在某一个小区域内的;如果此时的中心点落在 x 框内,则 x 小区域就负责搞定这个目标;注意此时可能多个目标落在同一个区域
  • 每一个小区域设定 B 个可能的候选框,并计算每一个可能的候选框的得分 = 置信度,是一个(该候选框和真实的目标检测框的重合程度)和(这个框里确实框住了某一个物体)的综合度量指标,计算方式如下:

    c

    o

    n

    f

    i

    d

    e

    n

    c

    e

    =

    P

    r

    (

    O

    b

    j

    e

    c

    t

    )

    I

    O

    U

    p

    r

    e

    d

    t

    r

    u

    t

    h

    confidence = Pr(Object) * IOU_{pred}^{truth}

    confidence=Pr(Object)IOUpredtruth

    • 这里的 IOU 也就是:

      I

      O

      U

      =

      t

      r

      u

      t

      h

      p

      r

      e

      d

      t

      r

      u

      t

      h

      p

      r

      e

      d

      IOU = \frac{truth 的检测框 \cap pred 的检测框}{truth 的检测框 \cup pred 的检测框}

      IOU=truthpredtruthpred,也就是真实的框和我预测的框的交并比

    • 同时注意这里为什么要同时考虑两个指标:
      • 考虑 IOU:想象此时有一个很大的狗,A 框只框住了狗头,B 框住了狗和一点点背景,此时 A 的Pr 为 0.999 而 B 的 Pr 为 0.998,但是本质上我宁愿选 B(A没全);也就是说还通过计算 IOU 考虑到一个是否框准了的问题
      • 考虑 Pr:比如狗后面有个树,本身树不是我们的识别目标,如果此时的 pred 的框 A 本身命中的是树,则可能和 狗 的 true answer 的 IOU 也是很高的,但是对应的 Pr 部分会比框住狗的预测框 B 更低,则此时通过 Pr 在前面控制,保证在后续的 NMS 部分会优先留下 B 而不是 A
  • 每一个小区域(共

    S

    2

    S^2

    S2 个小区域)计算 B 个候选框,共

    S

    S

    B

    S*S*B

    SSB 个,每一个预测是一个长度为 5 的向量,记作

    (

    x

    ,

    y

    ,

    w

    ,

    h

    ,

    c

    o

    n

    f

    )

    (x,y,w,h,conf)

    (x,y,w,h,conf)

    • (x, y) 表示当前预测的检测框的中心相对于我的小区域的位置(共

      S

      2

      S^2

      S2 个小区域),这里的 x 和 y 都是 0-1 之间的,也就是说是相对于当前小区域的左上角的偏移值

    • (w,h) 表示检测框的宽度和高度,一般是处理到 0-1 之间,标记当前的预测框和整个图片的宽度/高度的比例
    • conf 为上述的置信度,可以看作是当前的框的可信度的综合指标,由(是否框准了 = 是否和真实的预测框有较好的重合)和(是否框里确实框住了物体)两个部分影响
  • 同时计算每一个小区域(注意是小区域,一开始 S*S 的那个,不是预测框)对应为第 i 个类别的概率,记作

    P

    r

    (

    C

    l

    a

    s

    s

    i

    O

    b

    j

    e

    c

    t

    )

    Pr(Class_i|Object)

    Pr(ClassiObject);也就是说这里作者前提假设了同一个小区域内只有同一种物体的中心落在里面

    • 在测试的时候,则该区域内的所有的 B 个预测框都对应乘上这个 Pr 值得到:

      c

      o

      n

      f

      i

      d

      e

      n

      c

      e

      =

      P

      r

      (

      C

      l

      a

      s

      s

      i

      O

      b

      j

      e

      c

      t

      )

      P

      r

      (

      O

      b

      j

      e

      c

      t

      )

      I

      O

      U

      p

      r

      e

      d

      t

      r

      u

      t

      h

      =

      P

      r

      (

      C

      l

      a

      s

      s

      i

      )

      I

      O

      U

      p

      r

      e

      d

      t

      r

      u

      t

      h

      confidence = Pr(Class_i|Object) * Pr(Object) * IOU_{pred}^{truth} = Pr(Class_i) * IOU_{pred}^{truth}

      confidence=Pr(ClassiObject)Pr(Object)IOUpredtruth=Pr(Classi)IOUpredtruth,也就是说每一个小区域内对应的 B 个预测框的分类的 i 对应的条件概率(以确实框到了东西为条件)是一样的

    • 上面计算得到的 conf 也就是每一个预测框框住的是分类 i 的物体的一个综合置信度得分

举个例子:
在这里插入图片描述
这里的 S 是 7,也就是将整个图片分为 49 个小区域,对应的每一个小区域设定考虑 B 个不同的候选框(注意这里设定的 B 的主要目的是保证如果多个目标的中心都在同一个小区域内也可以抓得比较全)→ 计算共 S*S*B 个框的预测信息,每一个预测框都对应一个五维的向量作为预测值,包括:1)预测框的中心对应当前的小区域的相对位置;2)预测框的大小相对于整个图片的相对比值;3)置信得分 = P(确实框到东西了) * IOU → 同时对于一个 C 分类问题,则每一个小区域都有一个长度为 C 的向量,表示该小区域对应的预测框是 i 分类的概率

综上,此时整个模型的输出应该是大小为 S*S*(B*5 + C) 大小的一个向量

2.2 Network Design 网络设计

整体的网络设计依赖卷积神经网络的思路,也就是一大串卷积(共 24 层)后面跟着全连接层(两层全连接)输出需要的预测的向量,也就是传统的(卷积先提取特征)再(扔进全连接层进行预测)的思路
在这里插入图片描述

举例还是上面的 S = 7 的情况,设原图大小为 448*448*3(三通道 RGB 表示色彩);假设这里的 B = 2,C = 20,一开始冲上来扫的卷积大小为 7 ;则对应的最后的输出应该是 7*7*(2*5 + 20), 本身是三维的,最后一个为 30(最后一维输出的大小 = B*5 + C)


3 Training 训练和损失函数

3.1 预训练

首先进行预训练,在 ImageNet 1000-class competition dataset 上面进行,将前面的 20 层卷积拿出来,后面跟上一个平均方法的池化层 + 一个全连接层,来进行预训练(原论文表示大概训了一周)

后续 fine tune 的时候最后的四层卷积和两个全连接层都是随机初始化权重的,也就是说这里的预训练知识针对最前面的 20 层卷积

注意这里最后输出的五维向量中,对应的 x,y 和 w,h 都是 0-1 之间的值(标准化过的结果);

3.2 损失函数

至于损失函数部分,这里利用平方误差和(sum-squared error)来衡量(因为比较方便优化),先把这个巨大无敌的损失函数摆过来:

这里的

1

i

o

b

j

1_{i}^{obj}

1iobj 标记对于第 i 个小区域(共 S*S 个小区域)内是否出现了某一个目标的中心点;而

1

i

j

o

b

j

1_{ij}^{obj}

1ijobj 标记第 i 个小区域内的第 j 个预测框(共 B 个 预测框)是否框住了某一个目标

3.2.1 几个细节问题:

  • Q1:我们的目标是想要使得平均精度最佳,也就是既要分类分得准,同时预测框的标记也需要准,但是如果直接用最后输出的五维向量来处理,此时对于(预测框的标记是否准确 = localization error)和(分类是否准确 = classification error)是同等重要来衡量的,不太对()

    • A1:引入超参数

      λ

      c

      o

      o

      r

      d

      \lambda_{coord}

      λcoord 控制(预测框的标记是否准)和(分类的结果是否对)两个部分在损失函数中对应的权重,设置 > 1

  • Q2:同时注意到大部分的小区域都是不含有我想要检测的目标的,也就是说真实的 conf 应该为 0,这部分的区域过多,可能会导致那些含有目标的小区域对于损失函数的影响被吞掉(也就是说如果模型学会对所有的 conf 都预测为 0,则只是损失了几个少数的含有目标的小区域,但大部分的区域都是超准的;这种情况显然会导致模型跑走)

    • A2:引入超参数

      λ

      n

      o

      o

      b

      j

      \lambda_{noobj}

      λnoobj 控制不含有检测目标的框在损失函数中的贡献,设置 < 1

  • Q3:在衡量我的预测框和真实的框之间的误差的时候(针对框的大小,也就是 w 和 h 两个参数),注意到如果我本身框大小为 10 相差1,和本身框大小为 1 但相差 1 完全是两个不同的概念(后者会更加严重);也就是说对于相同的真实值与预测值之间的差值,如果对应的框越小,则对于损失函数的影响应该越大

    • A3:不用 真实值 - 预测值 来衡量,而是用 √真实值 - √预测值,(注意这里的方法解决这个问题的效果是很有限的 …)具体原理见下图:
      在这里插入图片描述
      注意这里的 x 轴为原值,y 轴为根号后的值,原来的 x 越小的时候,等距离的 x1 和 x2 对应的 y 轴的值 √x1 和 √x2 之间的差距会越大,也就对于损失函数的影响越大

3.2.2 解释损失函数

现在再回头来重新解释一下损失函数(再摆一遍
在这里插入图片描述
一行一行来:

  • ① 控制中心点 x 和 y 的预测,注意这里的 x 和 y 都是中心化到 0-1 之间的,不做上面的 Q3 的处理;注意如果示性函数 1 对应的为 0 ,也就是说当前的预测框里就没有物体,则对损失函数不影响;注意前面有 λcoord 存在,控制此时 localization error 的惩罚的权重;
  • ② 同理,控制框的大小的预测,这里按 Q3 的解释做开根处理后再相减,同理注意如果当前预测框内没有物体,则全部置为 0;同理存在 λcoord;
  • ③ 存在目标的预测框的 C 值(置信度)的误差惩罚;
  • ④ 不存在目标的预测框的 C 值(置信度)的误差惩罚,注意前面带有 λ noobj,这个超参数加入主要是因为进入 ④ 的框比进入 ③ 的框要多得多,对于单个的框来说没有哪个更重要的说法;
  • ⑤ 对于分类准确性的惩罚,注意这里是基于小区域(S*S 个)进行的,不是针对每一个预测框(否则三连乘会超多);只集中于存在目标的小区域;

同时注意,假设一个小区域内同时存在目标 ABC,对应它有预测框 abc,可能一开始 a 预测框就是离 A 目标最近(也就是 IOU 最大),则后续梯度下降的时候,它比起去贴本来离得远的 B 目标,a 预测框会越来越贴近 A 目标;也就是说随着训练的进行会出现某一个预测框就针对某一个目标开始优化的情况,算是一定程度上的专门性

3.3 训练参数设置

几个原论文给出的炼丹参考:

学习率处理:

  • 第一个 epoch 先从

    1

    0

    3

    10^{-3}

    103 逐渐上升到

    1

    0

    2

    10^{-2}

    102,注意不是一开始用大学习率,会很容易一把子发散

  • 原论文保持

    1

    0

    2

    10^{-2}

    102 又训了 75 epoch,再

    1

    0

    3

    10^{-3}

    103 30 epoch,再

    1

    0

    4

    10^{-4}

    104 30 epoch

  • ※ 原论文手动调了学习率可能还是有一定影响的,可能后续炼丹的时候也可以试试不要直接交给 decay 而是手动一下

缓解过拟合

这里为了缓解过拟合用了 dropout,参数打 0.5

同时可以配合数据增强的方法,原论文用了 random scaling and translations (大概到 20% 的原图大小)


4 Inference 推理

4.1 模型推理

和训练的部分同理,推理的时候也只需要走一次模型。具体会给出 S*S*B 每一个框的对应的置信度 conf,同时通过 (x,y,w,h) 标记好框的位置

注意到会一并计算每一个小区域的对应的各个类别的概率(同上所述,注意这里作者假设了每一个小区域负责检测到的目标 = 中心点落在该小区域内的目标都是属于同一个类别的;则也可以得到对应的每一个预测框的预测的类别

最后输出的时候可以通过控制阈值的方法输出(后续在源码部分详细说说),比如最简单的就是控制置信度,大于 xx 的预测框才能够输出

4.2 NMS 方法(Non-Maximal Suppression / 非极大值抑制)

※原文表示是可以用这个,但是感觉为了好点的效果是必要组成部分(?)

考虑有些很大的物品 / 或者这个目标的中心值刚好在边界上,则可能会导致多个小区域都给出了比较好的预测框,也就是说对于同一个目标,会出现几个较好的预测框。此时需要从它们中选择一个,否则会出现冗余

这里使用 NMS 方法 = Non-Maximal Suppression / 非极大值抑制,将多余的 / 冗余的预测框去掉。本身这个方法从 R-CNN 开始就已经用起来了(不如说对于滑动窗的方法反而是最容易出现这样的重复的冗余预测框的),简单来说步骤如下:

  • 将可能在定位同一个目标的所有候选框搞出来 → 设定为备选框
  • 按照置信度从大大小排序备选框
  • 取置信度最大的框作为基准,计算和其他余下的框的 IOU,对应大于某一个阈值的其他框都全部扔掉
  • 重复步骤直到筛选结束

也就是说 NMS 本身是一个局部最大的搜索方法。注意在实现的时候是必须一张图一张图来进行的,也就是说会出现在当前 batch 内遍历每一张图再一个一个来 NMS 的情况(源码里再说)
对于 YOLO 来说,一般是先根据置信度扔掉大部分的框(也就是设定阈值,conf < 阈值的预测框直接 pass),再进行 NMS 进行进一步的缩减。注意这里 NMS 的候选框也就是所有被留下的预测框,这里的 IOU 的计算量是

n

2

n^2

n2 级别的,所以一开始先根据置信度把大部分扔掉。


5 summary

5.1 YOLO 步骤总结

细节的东西比较多,以下来整体梳理一下 YOLO 的思路:

  • 固定图像输入大小,这里假设为 448*448*3;设定存在 C = 20 种不同类别的目标
  • 将整张图片分为 S*S 的小区域(grid cell),假设 S = 7
  • 每一个小区域设定搜索 B 个预测框(bounding box),假设 B = 2
    • 每一个预测框给出一个五维向量

      (

      x

      ,

      y

      ,

      w

      ,

      h

      ,

      c

      o

      n

      f

      )

      (x,y,w,h,conf)

      (x,y,w,h,conf) 作为预测输出

      • xy 表示预测框中心点相对于当前的小区域(grid cell)的位置
      • wh 表示预测框的宽高相对于整张图片大小的比例
      • conf 为该搜索框的置信度,由 Pr(是否包含 obj) * IOU(预测框和真实框的交并比)计算
        • 多啰嗦一句 … 一个预测框的置信度是通过模型输出的,通过全连接层劈里啪啦一顿操作预测出一个值;而我的 ground truth = 该预测框的真实的置信度 → 是通过上面的式子计算的,此时真实的 bonding box 的坐标都有,则中心位置可以计算 → 若中心位置在这个小区域内,则 Pr(是否包含 obj) = 1;得到 ground truth 后就是训练模型劈里啪啦出来的那个值不断接近我计算的真实值;
    • 所以这里最后的输出大小为 S*S*(B*5 + C) = 7*7*30 ,注意是三维的
  • 每一个小区域(grid cell)都给定 C 个可能的概率,表示该小区域内的预测框对应的目标为第 c 类目标的概率;注意这里假设了中心落在同一个小区域内的目标都是同类别的。
  • 训练 training →
    • 通过上面的那个巨大无敌的损失函数,包括 localization error(也就是对目标框的 xywh 的惩罚)+ 对每一个预测框的 C 置信度的惩罚 + 对当前小区域的 classification error 分类
  • 推理 inference →
    • 计算得到 S*S*B 个候选框的位置大小 + 置信度(直接通过模型吐出来的,含义 = Pr*IOU),先设定置信度阈值将特别小的框扔掉,再通过 NMS 去掉冗余,对应框住的东西的分类 = 该框所在的小区域(grid cell)对应的各类概率最大的那个分类,也就是说每一个小区域内的框都是同一类的东西;

5.2 YOLO 的优缺点

优点

  • 快,YOLO 的检测速度比往常的模型快很多,这也是 YOLO 最大的优点之一,使得它在实时监测上基本能把别的模型按着打(比如输入是实时的视频流)。实验表示即使是精简版的 YOLO fast 在 FPS155 的速度下也能达到不错的精度;
  • 更少出现背景误检的问题,也就是更低的 background error;也就是说 YOLO 更少将啥也没有的背景误检测出来作为目标。前面也提到,因为 YOLO 的输入是整张图直接扔进去,也就是说会有更多的上下文信息,故相较于其他模型不容易从局部上将背景作误判;
  • **泛化能力比往常的模型要好。**原文用的是Picasso Dataset 和 People-Art Dataset 来作(艺术作品种的人的检测)的实验,YOLO 的效果会好很多,展现出一定的泛化能力。

缺点

  • 假设强,此时假设了每一个小区域内的目标不超过 B 个(原文 B = 2),同时假设了中心点落在同一个小区域内的所有目标都是同一类的物体
    • 也就是说如果出现很多的目标密集挤在一起,此时 YOLO 的效果不一定会很好(会识别不全)算是 YOLO 不擅长的一个场景;
  • 泛化能力还是有限,主要对于长宽比不太一样的情况会表现不佳 → 比如2:1的瘦狗看多了会认不出1:1的胖狗;原作者将原因归结于提取的用于预测的特征还是比较粗糙,因为本身存在对原图像多次下采样的结构;
  • 损失函数部分不同大小的框对于损失函数的贡献的区分不明显。相同的差值,大小不同的框对于损失函数的贡献应当是不同的 → 也就是前面提到了在 localization error 的部分(针对 w 和 h),如果是一个大小为 10 的框预测误差为 1 还好,但是大小为 1 的框预测误差为 1 要出事,上述操作是开根号后再进行差值计算,但是实验表示这样的处理效果还是有限。


阅读仓促,存在错误 / 不足欢迎指出!期待进一步讨论~
转载请注明出处。知识见解与想法理应自由共享交流,禁止任何商用行为!

版权声明:本文为CSDN博主「HicSuntLeones」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46522688/article/details/122830770

HicSuntLeones

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐