com 目标不会实现 idispatch_目标检测——从简单的开始!进击的YOLO!

  • 目标检测——从简单的开始!进击的YOLO!
  • 目标检测——Backbone与Detection head
  • 目标检测——搭建更好更快的YOLO!
  • 目标检测——制作GroundTruth!开始训练!
  • 目标检测——YOLOv2!
  • 目标检测——YOLOv3!
  • 目标检测——SlimYOLOv2
  • 目标检测——TinyYOLOv3
  • 目标检测——CenterNet-Lite
  • 目标检测——尾声

OD是一个发展很快的领域,从15年的YOLO-v1到现在的TridentNet,无论是PASCAL VOC还是MSCOCO,mAP这个指标都被不停地往上刷,以至于VOC这个数据集几乎不会再用来证明自己工作的sota,而COCO似乎也快要趋于某种饱和了(但远没到顶,毕竟COCO上的mAP连70都没有)。但这个领域对于新手来说,还是有难度的,这一点我自己深有体会,所以,我想写一个尽可能实用的教程,把一些基础必要的东西拿出来分享,用这些东西咱们一起搭建个简单的目标检测网络,帮助新手入门这个领域,能够做到这一点,我就觉得这个教程值了。

当然,我并不是OD这个领域的大佬,所以,我分享的东西必然有瑕疵在其中,可能我看不到,但我想大家一定会看得到,所以分享出来,也是为了和大家一起交流,在交流中学习,在交流中共同进步,这也是我的目的之一。


计算机视觉(Computer Vision)是一种古老的学科,是当下人工智能领域中最火热的研究点之一。无论是控制专业的,机械专业的,宇航专业的,材料专业的等等,都会有很多人乐此不疲地转入CV这一坑中,比如我。

那么CV要解决什么样的问题呢?

太多太多了,即使是写一本大头书,怕是也难详尽。所以,我们只聚焦其中一点——目标检测(object detection,OD)。于是,我们可以问“目标检测”究竟是干嘛的呢?回答也很简单:就是要用矩形框把图片中感兴趣的物体框选出来,比如下面这张图:

3ef300e6a0cc59cbb0946ad7f2cb8a37.png
图一. 示例。此图摘自YOLO-v2原文

听起来,OD是一个很简单的问题,似乎没什么难度。但就是这么一个看似简单的问题,却在深度学习出现之前,一直没有得到什么好的发展。在以前,学者们基本上是用视觉特征(如HOG)+分类器(如SVM)来做的,其结果并不理想,虽然在行人检测这一块基本能够实现实际部署,但通用的检测器,仍然做不到。

2014年,R-CNN工作的问世,意味着深度学习技术正式进军OD领域。但此工作其本身,存在很多的问题,这点我们暂且不提,随后的2015年,著名的YOLO-v1工作被提了出来,从此,OD技术的一大分支:One-Stage形成了。

One-Stage工作的最大特点就是:仅使用单一的网络,端到端地给出输入图像中物体的位置和类别。这一特点就决定了这一类工作在速度上的优势,现在基本上提到实时性,大多数人都先想到这一类的工作。而这一类工作中,我想,YOLO肯定是被最先想到的(当然SSD也不错啊,只是,YOLO太经典了!)。

YOLO,You Only Look Once,从名字上就能够看到其注重“速度”这一特点。并且,YOLO的网络结构和检测的原理方法也是非常简单明了的。因此,我认为拿YOLO来作为OD的入门实在是再适合不过了!

从一开始,我就声明过,本教程不会去科普OD的发展史和研究现状,所以,关于OD的发展,上面那一段就够了,这里就默认看此教程的读者已经对OD具备了基本的了解和认识。接下来,我们以YOLO-v1为出发点,开始我们的实践之路。


一、YOLO-v1的网络架构

YOLO-v1仅使用一个卷积神经网络来实现检测物体的目的。其网络整体的结构如图二所示:

68d4435b8a27a659f06bb68ed04d514e.png
图二. YOLO-v1网络整体结构图

YOLO-v1的网络是仿照GoogLeNet搭建的,但并没有采用Inception模块,而是使用

卷积层来堆砌的,所以网络的结构是非常简单的。基本上,照葫芦画瓢,我们就能搭建出整体的网络。

由于在那个时候,分类任务中,网络最后会将卷积输出的feature map拉平(flatten),得到一个向量,然后再接全连接层做预测。YOLO-v1继承了这个思想,最后的

的feature map成
大小的向量,再接全连接层。但是,这里我们需要注意一点,如果只看图中的结构,是只有一个4096的全连接层,我们算一下这里的参数量:

仅仅这一层全连接,参数量就直接爆炸!

因此,原文作者实际是先用了一个256的全连接先缓一缓,然后再连接4096,从而避免参数爆炸,这样我们再算一下:

少了一个数量级,似乎也没有好到哪去。。。。。实际上,这里的问题并不在于全连接层的参数量上,而是在于flatten这种方式本身,基本上,对于”flatten方式会破坏特征的空间结构信息”的这一观点已经成为业界共识,当然,这一点,我们暂且搁在这,后续的实践中我们会进行改进的。

关于前面一系列的卷积层,由于那时候BatchNormalization(BN)技术还没有兴盛起来,所以YOLO-v1中并没有使用BN(后来在v2中添加了)。原文中在学习率一块,作者提到,如果使用较大的学习率开始训练的话,模型会在初期训练阶段表现得不稳定,因此先用很小的学习率预热一下。我想这个可能是因为没有使用BN的原因吧~

最后的输出是一个

的feature map。这里的通道数30的含义是:每个位置预测
两个bbox,每个bbox包含五个参数:置信度
矩形框参数
共10个参数再加上20个类别,一共就是30了。更一般的,我们可以用下面的公式来计算这个feature map的通道数:

其中

是每个位置预测的bbox数量,C是类别的数量(PASCAL VOC中有20个类别,MSCOCO中常用的是80个类别)。

那么,这个

的feature map到底是怎么来的呢?

首先,网络的输入是

的图片,经过网络64倍的
,最后的卷积输出是
的(
),在这里停一下,因为这里体现了作者的一个很好的idea。作者的idea很简单,这个
相当于把原来的
的图片进行了
等分,如下图所示:

6bb4c251b0a29cf42f811cee96a32d70.png
图三. YOLO-v1的网格等分思想

YOLO-v1的是想通过看这些网格来找到物体的中心点坐标,并确定其类别,具体来说,就是每一个网格都会输出

个bbox,每个bbox包含5个参数(框的置信度+框的坐标参数),
个类别的置信度,因此,每个网格都会给出
个预测参数。因此,网络最终输出的预测参数总量就是:

其中

,原文中,

因此,知道了最后输出的预测参数量后,在4096全连接层后面接多大的全连接层也就清楚了。于是,YOLO-v1经过这层最后的预测层输出一个

大小的向量后,再将其resize成一个
大小的feature map(这一步的resize没有任何特殊含义,仅仅是为了和上面的网格形式对应,处理起来方便,请读者不要多想。)

b2519159b0d99186e4f79c97310b553c.png
图四. YOLO-v1整体工作流程

那么,YOLO-v1的学习目标到底是什么样的呢?或者说,为了训练这个YOLO-v1,到底应该如何去设计groundtruth呢?本节我们只介绍了YOLO-v1的网络架构,对于如何实现对目标的位置和类别的预测没有谈及到。再下一节,我们回着重来讲解一下YOLO-v1是如何预测目标位置和类型,以及为了实现这一点,如何去制作训练所需要的label。

二、YOLO-v1的检测方法

众所周知,尽管无监督学习正在兴起,但目前来看,监督学习依旧是应用最广泛,整体表现最靠谱的,因此,正应了那句话:人工智能,没有人工,就没有智能。为了能够让网络实现预期目标,我们就需要为其制作可以用来学习的label。在此之前,我们先研究一下,YOLO-v1到底是如何实现预测目标位置和类别的,然后我们再去研究如何制作相应的label。

在最后的

的网格中,我们已经直到,每个网格会给出30个参数,包括两个bbox的5个参数(框的置信度+框的坐标参数)和20个类别置信度。首先,先说一下每个bbox的5个参数。

由于YOLO-v1是去预测物体的中心点,并给出矩形框,因此,包含中心点的网格,我们认为这里是有物体的,即

,如下图所示:

db710a22d5a17355fcedc24c8ba2a49b.png

黄颜色代表这个网格有物体,

也就意味着,物体的中心点落在了这个网格中,如图中的红点所示。但是,注意看图,我们会发现这个中心点相对于它所在的网格的四边是有偏距的,这其实就是由于降采样带来的量化误差,因此,我们只要获得了这个量化误差,就能获得中心点的坐标了,那么YOLO-v1中是怎么计算这个量化误差的呢?

首先,对于给定的真实的bbox坐标

,计算它的宽
和高

中心点坐标:

获得了中心点坐标后,我们就可以直接用下式就能确定出它落在了网格的哪个位置:

其中的

就是降采样的倍数,
表示向下取整。

很明显,量化误差就出来了:

这里的

便是YOLO-v1关于中心点坐标所要学习的目标,显然,
。可以参见下图:

b777c5fef000bea795fc52c292b704bd.png
图五. YOLO-v1关于中心点所要学习的目标

那么,我们如何从网络输出的

反解出
呢?很简单,在
的网格中,对于每个位置
,用下式即可计算出相应的中心点:

对于一个矩形框,中心点确定了它的位置,那么对于它的大小,则由宽和高来决定,那么关于bbox剩下的两个坐标参数就直接设定为

。不过,由于
,而
通常远大于1,所以,这会很容易造成loss分布的不均匀,因此,实际上,将
都除以了图像的大小:

对于bbox的五个参数中的最后一个,框的置信度,YOLO-v1则采用了不是很直接的方式来赋予其学习目标。具体来说,在训练过程中,网络在网格中的某个位置预测了B个bbox,然后计算这些B个bbox与真实的bbox的

,选择其中最大的值来作为置信度的学习目标,同时,bbox的学习中,也只让这个置信度最大的bbox去反向传播,其他B-1个bbox就忽略了,所以,B个bbox之间是有“竞争”关系的,尚不清楚这种方式的好处在哪里。

举例来说,当前预测的矩形框和真实的矩形框的最大

,那么网络就会将这个
作为置信度的学习目标,同时bbox的loss中,也只考虑这个0.28所对应的bbox预测,其他的则忽略不计。所以,网络预测的置信度可以直接衡量框的预测好坏。

但这种做法是否好呢?

我觉得还差那么一点意思,因为网络本身,并没有置信度conf和bbox之间的耦合关系,所以,“网络预测的置信度可以直接衡量框的预测好坏”这句话有点站不住脚,我觉得应该在设计网络结构的时候,就要显式地把conf和bbox之间的数学关系构建出来,而不是完全靠数据驱动来学习。

在yolo里,这叫“rescore”,你可以在它的配置文件中看到这个参数,默认为1,也就是使用这种动态IoU来设置,如果改为零,那就很简单了,正样本学习的conf的label就是1,负样本则为0,不需要根据IoU来动态设定。

既然官方都是默认为1,采用动态IoU,那咱们也不妨就这么做吧。

简单来说,这个置信度是衡量了预测框有多接近真实框,因此,在测试阶段,网络输出的置信度实际上是预测了它认为自己和真实的框有多接近

看到这里,我不禁想到了ECCV2018中的一篇工作:IoU-Net。在这篇工作中,其出发点是往往好的框,类别置信度不高;反之,类别置信度的框,位置预测得不太好。我们更关注的是框的位置好坏,毕竟0.7的类别置信度和0.8影响并不大,因此,IoU-Net便让网络学习预测IoU,然后用IoU得分去做NMS。而在YOLO-v1中,网络也会去学习对IoU的预测,只不过是用这个IoU的预测得分和类别置信度得分的乘积来做NMS,所以,2018年的IoU-Net的idea似乎,,,话点到为止,不戳破~

总结一下,网络的最后输出中,每个位置

的每个bbox都包含如下参数:

由这些参数,计算出相应矩形框的位置和大小与所属类别:

在制作标签时,遵循如下步骤:

  1. 首先计算,中心点落入的网格位置:

2. 对于

位置,我们认为此处有物体,因此
(关于这个东西有啥用,我们会在后面讲损失函数的时候会用到)。并计算量化误差与矩形框的宽和高:

关于标签怎么赋予,这就不用说了~

3. 完事~

最后,我们再说一下损失函数的设计,直接上图:

de65e1e626376c10da1e26fdbc34f6dd.png
图六. YOLO-v1中的损失函数

图中的第一行关于

的损失计算,原文中用的是
。第二行是关于
的损失计算。注意,这两行中都用一个
符号,这个符号表示,只有有物体的地方,即
处,才会参与损失计算,而其他地方的损失则不考虑。这就会带来一个问题:

有物体的地方,我们让网络去学习,逼近它,而没有物体的地方,理论上应该让

都是零,但是这些没有物体的地方的并没有考虑进来,因此不会被学习到。那怎么办?

这就是第三行第四行的作用。第三行中,

是预测框与真实框计算的
,预测的越准,
越趋近于
,那么网络预测的
也就越趋近于
,而没有物体的地方,也就是第四行,其中的
都是0(因为这些地方是不应该有框的,所以直接设为
即可),那么网络在这些地方预测的
也就会趋近于0,这就相当于让
趋近
(因为没物体,那么
就是
,在测试的时候,我们也就不会考虑这些地方了。)。另外,很明显,一张图中,有物体的网格数目是小于没有物体的网格数目的,因此,为了平衡他们两个的损失,需要赋予不同的权重,关于有物体的,直接给
就行,没有物体的,给

最后的第五行,就是类别概率的损失计算,同样,我们也只考虑有物体的地方的损失,其他地方不管。

从上面的损失,我们发现,都是用MSE来计算的,这是因为YOLO-v1关于框的五个参数和类别都是用的是线性函数(全连接层不加激活函数)来做的预测,所以,关于类别的学习,我们就没看到交叉熵函数了,至于为什么YOLO-v1用线性函数来预测,而不是用

,咱也不知道~

另外,这种线性输出的弊端就是输出没有上下界的限制,比如conf输出应该在01之间,以及

两个小增量也是在01之间。而在yolov2中,就修改了,置信度和两个中心点的偏移量都使用
来映射到01之间,使得训练更稳定。

以上,便是有关于训练YOLO-v1的全部了。

那么,在测试的时候我们应该怎么做呢?

1.计算bbox和类别:

同时,网络还给除了对框的置信度的预测

,然后计算每个框的得分:

用这个得分去做后续的非极大值抑制处理(NMS)。最后保留下来的结果,就是网络的最终预测输出。

到此,关于YOLO-v1,我们就全部讲完了~整体来看,YOLO-v1还是非常简单的,无论是groundtruth制作,网络预测,都非常简单,这也是我为什么会把它作为本教程的重点示例来讲解。后续的实践,我们会以YOLO-v1作为主要的参考,来实现一个简单的目标检测网络。

补充:

最后简单说一下什么是非极大值抑制吧。

事实上,如果我们把所有的预测结果都可视化出来,会发现有很多冗余,即多个box检测到了同一个物体,而我们对于每一个物体只需要一个框就够了。因此,我们有必要去剔除掉多余的结果。以下面的人间检测为例:

332e78d8abac5e0c42ce3639a71853a5.png

左图中,是未经过处理的,我们可以看到有多个红框检测到了同一张脸,为了提出掉多余的框,采用如下步骤:

  1. 首先挑选出得分score最高的框;

2. 依次计算其他框与这个得分最高的框的

,超过给定
阈值的框舍掉。

3. 对每一类别都进行以上的操作,直到无框可剔除为止。

NMS很简单吧~


第一章就在这收尾吧,下一章,我们就开始搭建我们自己的网络~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值