- 目标检测——从简单的开始!进击的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](https://i-blog.csdnimg.cn/blog_migrate/d1a9f49f890a9bed685b6aafa9282a10.jpeg)
听起来,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](https://i-blog.csdnimg.cn/blog_migrate/c52614481599d489bef70fccee93616e.png)
YOLO-v1的网络是仿照GoogLeNet搭建的,但并没有采用Inception模块,而是使用
由于在那个时候,分类任务中,网络最后会将卷积输出的feature map拉平(flatten),得到一个向量,然后再接全连接层做预测。YOLO-v1继承了这个思想,最后的
仅仅这一层全连接,参数量就直接爆炸!
因此,原文作者实际是先用了一个256的全连接先缓一缓,然后再连接4096,从而避免参数爆炸,这样我们再算一下:
少了一个数量级,似乎也没有好到哪去。。。。。实际上,这里的问题并不在于全连接层的参数量上,而是在于flatten这种方式本身,基本上,对于”flatten方式会破坏特征的空间结构信息”的这一观点已经成为业界共识,当然,这一点,我们暂且搁在这,后续的实践中我们会进行改进的。
关于前面一系列的卷积层,由于那时候BatchNormalization(BN)技术还没有兴盛起来,所以YOLO-v1中并没有使用BN(后来在v2中添加了)。原文中在学习率一块,作者提到,如果使用较大的学习率开始训练的话,模型会在初期训练阶段表现得不稳定,因此先用很小的学习率预热一下。我想这个可能是因为没有使用BN的原因吧~
最后的输出是一个
其中
那么,这个
首先,网络的输入是
![6bb4c251b0a29cf42f811cee96a32d70.png](https://i-blog.csdnimg.cn/blog_migrate/cb582a25b08b3148dfeea226f24bad42.jpeg)
YOLO-v1的是想通过看这些网格来找到物体的中心点坐标,并确定其类别,具体来说,就是每一个网格都会输出
其中
因此,知道了最后输出的预测参数量后,在4096全连接层后面接多大的全连接层也就清楚了。于是,YOLO-v1经过这层最后的预测层输出一个
![b2519159b0d99186e4f79c97310b553c.png](https://i-blog.csdnimg.cn/blog_migrate/561e64b57ce3f7dd09c0ad3e8949bb7a.jpeg)
那么,YOLO-v1的学习目标到底是什么样的呢?或者说,为了训练这个YOLO-v1,到底应该如何去设计groundtruth呢?本节我们只介绍了YOLO-v1的网络架构,对于如何实现对目标的位置和类别的预测没有谈及到。再下一节,我们回着重来讲解一下YOLO-v1是如何预测目标位置和类型,以及为了实现这一点,如何去制作训练所需要的label。
二、YOLO-v1的检测方法
众所周知,尽管无监督学习正在兴起,但目前来看,监督学习依旧是应用最广泛,整体表现最靠谱的,因此,正应了那句话:人工智能,没有人工,就没有智能。为了能够让网络实现预期目标,我们就需要为其制作可以用来学习的label。在此之前,我们先研究一下,YOLO-v1到底是如何实现预测目标位置和类别的,然后我们再去研究如何制作相应的label。
在最后的
由于YOLO-v1是去预测物体的中心点,并给出矩形框,因此,包含中心点的网格,我们认为这里是有物体的,即
![db710a22d5a17355fcedc24c8ba2a49b.png](https://i-blog.csdnimg.cn/blog_migrate/49a8d7eee3c9d752e2e61c30ce2a78d3.jpeg)
黄颜色代表这个网格有物体,
首先,对于给定的真实的bbox坐标
中心点坐标:
获得了中心点坐标后,我们就可以直接用下式就能确定出它落在了网格的哪个位置:
其中的
很明显,量化误差就出来了:
这里的
![b777c5fef000bea795fc52c292b704bd.png](https://i-blog.csdnimg.cn/blog_migrate/19f4dd0b8e3a0c05ca5f018b91ec228c.jpeg)
那么,我们如何从网络输出的
对于一个矩形框,中心点确定了它的位置,那么对于它的大小,则由宽和高来决定,那么关于bbox剩下的两个坐标参数就直接设定为
对于bbox的五个参数中的最后一个,框的置信度,YOLO-v1则采用了不是很直接的方式来赋予其学习目标。具体来说,在训练过程中,网络在网格中的某个位置预测了B个bbox,然后计算这些B个bbox与真实的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似乎,,,话点到为止,不戳破~
总结一下,网络的最后输出中,每个位置
由这些参数,计算出相应矩形框的位置和大小与所属类别:
在制作标签时,遵循如下步骤:
- 首先计算,中心点落入的网格位置:
2. 对于
关于标签怎么赋予,这就不用说了~
3. 完事~
最后,我们再说一下损失函数的设计,直接上图:
![de65e1e626376c10da1e26fdbc34f6dd.png](https://i-blog.csdnimg.cn/blog_migrate/2a25cbbd56c9357ed55076faa8b9d41f.jpeg)
图中的第一行关于
有物体的地方,我们让网络去学习,逼近它,而没有物体的地方,理论上应该让
这就是第三行和第四行的作用。第三行中,
最后的第五行,就是类别概率的损失计算,同样,我们也只考虑有物体的地方的损失,其他地方不管。
从上面的损失,我们发现,都是用MSE来计算的,这是因为YOLO-v1关于框的五个参数和类别都是用的是线性函数(全连接层不加激活函数)来做的预测,所以,关于类别的学习,我们就没看到交叉熵函数了,至于为什么YOLO-v1用线性函数来预测,而不是用
另外,这种线性输出的弊端就是输出没有上下界的限制,比如conf输出应该在01之间,以及
以上,便是有关于训练YOLO-v1的全部了。
那么,在测试的时候我们应该怎么做呢?
1.计算bbox和类别:
同时,网络还给除了对框的置信度的预测
用这个得分去做后续的非极大值抑制处理(NMS)。最后保留下来的结果,就是网络的最终预测输出。
到此,关于YOLO-v1,我们就全部讲完了~整体来看,YOLO-v1还是非常简单的,无论是groundtruth制作,网络预测,都非常简单,这也是我为什么会把它作为本教程的重点示例来讲解。后续的实践,我们会以YOLO-v1作为主要的参考,来实现一个简单的目标检测网络。
补充:
最后简单说一下什么是非极大值抑制吧。
事实上,如果我们把所有的预测结果都可视化出来,会发现有很多冗余,即多个box检测到了同一个物体,而我们对于每一个物体只需要一个框就够了。因此,我们有必要去剔除掉多余的结果。以下面的人间检测为例:
![332e78d8abac5e0c42ce3639a71853a5.png](https://i-blog.csdnimg.cn/blog_migrate/0d81e5b7e1946eeb7cc3c16ac262c428.jpeg)
左图中,是未经过处理的,我们可以看到有多个红框检测到了同一张脸,为了提出掉多余的框,采用如下步骤:
- 首先挑选出得分score最高的框;
2. 依次计算其他框与这个得分最高的框的
3. 对每一类别都进行以上的操作,直到无框可剔除为止。
NMS很简单吧~
第一章就在这收尾吧,下一章,我们就开始搭建我们自己的网络~