YOLO

Rgb大神关于物体检测的新作YOLO,论文You Only Look Once: Unified, Real-Time Object Detection

Introduction

对比人类的视觉系统,现存的物体检测模型:

  • 要不就是准确度不咋的(DPM速度还行,准确率很差,实用不现实)
  • 要不就是速度跟不上(Faster R-CNN 准确度还可以,3FPS的速度不能实时监测啊~)

这里写图片描述

这一堆物体检测模型,无论在学术界还是工程界,都不算令人满意。为此需要注入新的血液(重新挖坑),那么从哪里开始扎针呢?

作者在论文内主要对比R-CNN系列,指出了R-CNN系列速度慢的原因是: 模型把物体检测任务分为了多个阶段,而这几个阶段需要分开训练,难以优化(虽然Faster R-CNN是一个整体的网络,但是训练的时候还是需要交替训练)。

为什么非要分为多个阶段?
这是因为基于RPN(region proposal networks)在设计时已经把object detection问题分为多个pipeline,如果要改,就要把RPN方案砍掉。

YOLO在此基础上重建了整个模型框架,将原先的Region Proposal一套方案抛弃掉,将object detection作为回归问题来处理,模型能够接收原始像素直接输出object的bbox和类别categories,也就是end-to-end模型.


Detection System

YOLO工作的流程图如下:

这里写图片描述

大致步骤为:

  • 整个图片resize到指定大小,得到图片 Inputrs <script type="math/tex" id="MathJax-Element-1">Input_{rs}</script>
  • Inputrs <script type="math/tex" id="MathJax-Element-2">Input_{rs}</script>塞给CNN
  • 使用NMS(非极大值抑制)去除多余框,得到最后预测结果

总的步骤很简单,下面具体看看图片塞给CNN时是怎么整的。

分成单元格

首先会把原始图片resize到 448×448 <script type="math/tex" id="MathJax-Element-3">448×448</script>,放缩到这个尺寸是为了后面整除来的方便。再把整个图片分成 S×S(:7×7) <script type="math/tex" id="MathJax-Element-4">S×S(例:7×7)</script>个单元格,此后以每个单元格为单位进行预测分析。

这里写图片描述


每个单元格需要做三件事:

  1. 如果一个object的中心落在某个单元格上,那么这个单元格负责预测这个物体(论文的思想是让每个单元格单独干活)。

  2. 每个单元格需要预测 B <script type="math/tex" id="MathJax-Element-5">B</script>个bbox值(bbox值包括坐标和宽高),同时为每个bbox值预测一个置信度(confidence scores)。也就是每个单元格需要预测B×(4+1)<script type="math/tex" id="MathJax-Element-6">B×(4+1)</script>个值。

  3. 每个单元格需要预测 C <script type="math/tex" id="MathJax-Element-7">C</script>(物体种类个数)个条件概率值.

注意到:每个单元格只能预测一种物体,并且直接预测物体的概率值。但是每个单元格可以预测多个bbox值(包括置信度)。


单元格数据

我们细致的分析一下每个单元格预测的B<script type="math/tex" id="MathJax-Element-8">B</script>个 (x,y,w,h,confidence) <script type="math/tex" id="MathJax-Element-9">(x,y,w,h,confidence)</script>:

  • (x,y) <script type="math/tex" id="MathJax-Element-10">(x,y)</script>是bbox的中心相对于单元格的offset
  • (w,h) <script type="math/tex" id="MathJax-Element-11">(w,h)</script>是bbox相对于整个图片的比例
  • confidence <script type="math/tex" id="MathJax-Element-12">confidence</script>下面有详解

这里写图片描述

如上图,图片分成 S×S(7×7) <script type="math/tex" id="MathJax-Element-13">S×S(7×7)</script>个单元格。整张图片的长宽为 hi,wi <script type="math/tex" id="MathJax-Element-14">h_i,w_i</script>。

(x,y) <script type="math/tex" id="MathJax-Element-15">(x,y)</script>到底代表啥意思?

对于蓝色框的那个单元格(坐标为 (xcol=1,yrow=4) <script type="math/tex" id="MathJax-Element-16">(x_{col}=1,y_{row}=4)</script>),假设它预测的是红色框的bbox(即object是愚蠢的阿拉斯加),我们设bbox的中心坐标为 (xc,yc) <script type="math/tex" id="MathJax-Element-17">(x_c,y_c)</script>,那么最终预测出来的 (x,y) <script type="math/tex" id="MathJax-Element-18">(x,y)</script>是经过归一化处理的,表示的时中心相对于单元格的offset,计算公式如下:

x=xcwiSxcol , y=ychiSyrow
<script type="math/tex; mode=display" id="MathJax-Element-19"> x = \frac{x_c}{w_i}S-x_{col} \ , \ y = \frac{y_c}{h_i}S-y_{row}</script>

(w,h) <script type="math/tex" id="MathJax-Element-20">(w,h)</script>又是啥意思?

预测的bbox的宽高为 wb,hb <script type="math/tex" id="MathJax-Element-21">w_b,h_b</script>, (w,b) <script type="math/tex" id="MathJax-Element-22">(w,b)</script>表示的是bbox的是相对于整张图片的占比,计算公式如下:

w=wbwi , h=hbhi
<script type="math/tex; mode=display" id="MathJax-Element-23">w=\frac{w_b}{w_i} \ , \ h=\frac{h_b}{h_i}</script>

Confidence <script type="math/tex" id="MathJax-Element-24">Confidence</script>

这个置信度有两个含义:一是格子内是否有目标,二是bbox的准确度。

我们定义置信度为 Pr(Object)IOUtruthpred <script type="math/tex" id="MathJax-Element-25">Pr(Object)*IOU_{pred}^{truth}</script>.

  • 如果格子内有物体,则 Pr(Object)=1 <script type="math/tex" id="MathJax-Element-26">Pr(Object)=1</script>,此时置信度等于IoU
  • 如果格子内没有物体,则 Pr(Object)=0 <script type="math/tex" id="MathJax-Element-27">Pr(Object)=0</script>,此时置信度为0
C <script type="math/tex" id="MathJax-Element-28">C</script>个种类的概率值

每个网格在输出bbox值的同时要给出给个网格存在object的类型。记为:

Pr(Classi|Object)
<script type="math/tex; mode=display" id="MathJax-Element-29">Pr(Class_i|Object)</script>这是条件概率。

需要注意的是:输出的种类概率值是针对网格的,不是针对bbox的。所以一个网格只会输出 C <script type="math/tex" id="MathJax-Element-30">C</script>个种类信息。(这样就是默认为一个格子内只能预测一种类别的object了,简化了计算,但对于检测小object很不利)。

在检测目标时,我们把confidence<script type="math/tex" id="MathJax-Element-31">confidence</script>做处理:

Pr(Classi|Object)Pr(Object)IoUtruthpred=Pr(Classi)IoUtruthpred
<script type="math/tex; mode=display" id="MathJax-Element-32"> Pr(Class_i|Object) * Pr(Object)*IoU_{pred}^{truth}=Pr(Class_i)*IoU_{pred}^{truth} </script>

这就是每个单元格的class-specific confidence scores,这即包含了预测的类别信息,也包含了对bbox值的准确度。 我们可以设置一个阈值,把低分的class-specific confidence scores滤掉,剩下的塞给非极大值抑制,得到最终的标定框。
对于这部分可以看deepsystem.ai的PPT,讲的很详细,需要翻墙

单元格输出

每个网络一共会输出: B×(4+1)+C <script type="math/tex" id="MathJax-Element-33">B×(4+1)+C</script>个预测值.
故所有的单元格输出为: S×S×(B×5+C) <script type="math/tex" id="MathJax-Element-34">S×S×(B×5+C)</script>个预测值.

论文中每个单元格的输出如下图:

这里写图片描述

所有单元格输出为 7×7×(2×5+20) <script type="math/tex" id="MathJax-Element-35">7×7×(2×5+20)</script>,即最终的输出为 7×7×30 <script type="math/tex" id="MathJax-Element-36">7×7×30</script>的张量。

YOLO检测物体的流程

这里写图片描述

  • 分割成单元格
  • 预测bbox与类别信息,得到最终的 specificconfidence <script type="math/tex" id="MathJax-Element-57">specific confidence</script>
  • 设置阈值,滤掉低分的bbox
  • 非极大值抑制得到最终的bbox

YOLO的架构

上面说了YOLO的检测过程,那么中间关键的预测bbox和 confidence <script type="math/tex" id="MathJax-Element-38">confidence</script>该怎么实现?

当然是用CNN来整,整个网络框架如下:

这里写图片描述

网络架构受GoogleNet启发,共24个卷积层,后面接了2个FC层。

预训练

使用上图的前20个卷积层+平均池化+FC层在ImageNet上跑了一圈。(在ImageNet上跑是用的 224×224 <script type="math/tex" id="MathJax-Element-58">224×224</script>输入)。

预训练完事后,也就是get到了想要的前20个卷积层权重,在此基础上添加4个卷积层和2个FC层,得到最终模型(也就是上图)。同时将网络的输入尺寸从 224×224 <script type="math/tex" id="MathJax-Element-59">224×224</script>改成了 448×448 <script type="math/tex" id="MathJax-Element-60">448×448</script>。

这里写图片描述


YOLO的训练

整个YOLO在训练时,有很多处理的细节,我们主要讲一下网络损失函数的定义。

损失函数

这里我们把损失函数分为3个部分,每个部分都使用均方误差(为什么用均方,论文给出的原因是这样做简单啊):

先看一下整个损失函数:

这里写图片描述

每个图片的每个单元格不一定都包含object,如果没有object,那么 confidence <script type="math/tex" id="MathJax-Element-42">confidence</script>就会变成0,这样在优化模型的时候可能会让梯度跨越太大,模型不稳定跑飞了。为了平衡这一点,在损失函数中,设置两个参数 λcorrd <script type="math/tex" id="MathJax-Element-43">\lambda_{corrd}</script>和 λnoobj <script type="math/tex" id="MathJax-Element-44">\lambda_{noobj}</script>,其中 λcorrd <script type="math/tex" id="MathJax-Element-45">\lambda_{corrd}</script>控制bbox预测位置的损失, λnoobj <script type="math/tex" id="MathJax-Element-46">\lambda_{noobj}</script>控制单个格内没有目标的损失。

对三个损失函数有细节上的调整:

  • bbox
    对于预测的bbox框,大的bbox预测有点偏差可以接受,而小的bbox预测有点偏差就比较受影响了,如下图:
    这里写图片描述
    对于这种情况,使用先平方根再求均方误差,尽可能的缩小小偏差下的影响
    bbox的损失记为:

    :λcorrdi=0S2j=0BIobjij[(xixi^)2+(yiyi^)2]
    <script type="math/tex; mode=display" id="MathJax-Element-47">中心点损失:\lambda_{corrd}\sum_{i=0}^{S^2}\sum_{j=0}^B\mathbb{I}_{ij}^{obj}\left [ (x_i-\hat{x_i})^2+(y_i-\hat{y_i})^2 \right ] </script>
    :+λcorrdi=0S2j=0BIobjij[(wiwi^)2+(hihi^)2]
    <script type="math/tex; mode=display" id="MathJax-Element-48">宽高损失:+\lambda_{corrd}\sum_{i=0}^{S^2}\sum_{j=0}^B\mathbb{I}_{ij}^{obj}\left [ (\sqrt{w_i}-\sqrt{\hat{w_i}})^2+(\sqrt{h_i}-\sqrt{\hat{h_i}})^2 \right ]</script>
    Iobjij <script type="math/tex" id="MathJax-Element-49">\mathbb{I}_{ij}^{obj}</script>表示第i个单元格内预测的第j个bbox是否负责这个object:在计算损失过程中,bbox与ground truth的IoU值最大的负责object。

  • confidence
    对于置信度的损失,是按照是否含有object情况下分成两部分,对于不包含object的单元格,我们使用 λnoobj <script type="math/tex" id="MathJax-Element-50">\lambda_{noobj}</script>调整比例,防止这部分overpowering。

    i=0S2j=0BIobjij(CiCi^)2+λnoobji=0S2j=0BIobjij(CiCi^)2
    <script type="math/tex; mode=display" id="MathJax-Element-51">\sum_{i=0}^{S^2}\sum_{j=0}^B\mathbb{I}_{ij}^{obj}(C_i-\hat{C_i})^2+\lambda_{noobj}\sum_{i=0}^{S^2}\sum_{j=0}^B\mathbb{I}_{ij}^{obj}(C_i-\hat{C_i})^2</script>

  • categories
    对于种类预测,前面说了,这里设定每个单元格只负责一个object的预测,所以我们不用考虑多个bbox了。故损失函数为:

    i=0S2Iobji(pi(c)pi^(c))2
    <script type="math/tex; mode=display" id="MathJax-Element-52">\sum_{i=0}^{S^2}\mathbb{I}_{i}^{obj}(p_i(c)-\hat{p_i}(c))^2</script>

训练细节

  • 在激活函数上:
    最后一层使用的是标准的线性激活函数,其他的层都使用leaky rectified linear activation:

    ϕ(x)={ x,   if x>00.1x ,  otherelse
    <script type="math/tex; mode=display" id="MathJax-Element-61"> \phi(x)= \begin{cases}  x ,    if   x>0\\ 0.1x   ,   otherelse \end{cases} </script>

  • 在学习率上:

    • 前75个epoch设置为 102 <script type="math/tex" id="MathJax-Element-62">10^{-2}</script>
    • 再30个epoch设置为 103 <script type="math/tex" id="MathJax-Element-63">10^{-3}</script>
    • 最后30个epoch设置为 104 <script type="math/tex" id="MathJax-Element-64">10^{-4}</script>
  • 其他的训练细节:

    • batch=64
    • 动量0.9,衰减为0.0005
    • 使用dropout,设置为0.5,接在第一个FC层后
    • 对样本做了数据增强

总结

优点

YOLO有如下特点:

  • 速度快。YOLO将物体检测作为回归问题进行求解,使用单个网络完成整个检测过程。
  • 召回率低,表现为背景误检率低。YOLO可以get到图像的整体信息,相比于region proposal等方法,有着更广阔的“视野”。
  • 泛化能力强,对其他类的东西,训练后效果也是挺好的。

缺点

论文给出了YOLO与Fast RCNN的对比图,YOLO的定位准确率相对于fast rcnn比较差。但是YOLO对背景的误判率比Fast RCNN的误判率低很多。这说明了YOLO中把物体检测的思路转成回归问题的思路有较好的准确率,但是bounding box的定位不是很好。

这里写图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐