目标检测(Object Detection)的前世与今生(一)
首先说点题外话,上一篇的实时人脸识别
中我说要把mtcnn
和facenet
的论文和代码好好解释解释,并谈谈自己的理解,但是当我准备写的时候,发现还是我太年轻了,我发现如果想要将其解释的通俗易懂,并且能在以后的项目中用的得心应手的话,那么它的发展历程就不得不说说了,不然会觉得好多东西都很突兀,本次就说说这object detection
,那么各位老爷瞧好吧。
简介
Object Detection与Target Recognition是两个不同的概念,这个各位老爷应该都知道。Object Detection的目的是在目标图中将目标用一个框框框出来,并且识别出这个框中的是啥,而且最好的话是能够将图片的所有物体都框出来,这样做的目的是为了下一步的Target Recognition。所以了,我们接下来要做的就是用一些好办法将这个框框找出来(其实就是找出来这个框的坐标位置了),而在这个过程中技术和方法也是在不断的进步拉,从RCNN->SppNET->Fast-RCNN->Faster-RCNN,当然现在还有更棒的,但是我现在不写,准备留在下一篇再写(我也还没学...),但是如果不搞定这个技术演进,后面技术中的各种新东西会让人痛不欲生的
神经网络是如何工作的
答案是:我也不知道
这个问题太大,但是对于不仅仅是追求运用的人来说,这其实是一个挺让人困惑的问题(至少我是如此) 说一些各位爷都知道的,神经网络通过一系列的节点将数据中最直接的特征
==>抽象的特征
,使得抽象后的数据逼近目标,从而才有的可比性(衡量的尺度是loss)
举个例子,卷积网络奏效的过程(好像容易理解一点),通过不同的卷积核,提取图像不同的特征(抽象),再经过组合(进一步抽象),最终达到得到一系列的高纬度的抽象特征,当输入的图片符合的时候,才能够从其中抽取出类似的高纬度特征,从而达到了目的(网上一大堆的图,也不知道贴啥好,下面是随便找的图)
可以看出来,一开始提取出来的是一些不同方向的线条特征,接下来继续抽象组合,最后达到目标要求,这就是一个朝着目标不断抽象出来更高级特征的过程
,这个看着很好理解,是因为符合人类的认知,而以前的研究人员也是这样做的,他们各种办法寻找应该抽取的特征,从而能达到更好的效果,但是效率低小,很多时候效果也不好。 别急,让我再举一个例子,如果看过吴恩达老师的机器学习课程,应该知道其中有一节课是识别手写数字
,当时用的不是卷积,而是直接将28*28的手写数字图片展成一维,每一个像素都当成输入的特征,最后也达到了预期效果。这里不禁该思考了,神经网络起初看到的东西是一堆“在人类看来”毫无关系的像素值,处理的手段也是让人看不懂了,所以又回到了最开始的问题了,我们并不了解神经网络的行为,我们知道的只是其在进行特征提取,提取不同的特征,提取更高维度的特征,并且这种特征早已超出了人类的认知,所以它才可以高效的工作,完成一些人类无法完成的工作,比如刚才说的早期人工设定卷积核,寻找更好的目标特征,这些目前都已经被深度神经网络取代了,因为网络可以寻找到更高层次,更抽象(抽象到人类无法理解)的特征
说到这里,有时候又会感慨,这是否有些太玄学了,好像机器跳出了人类因为多年的自然进化和社会阅历的固有认知,寻找到了最直接的 现象与结果之间的联系,就好像如果占卜是正确的话,那么是不是其方法是以一种人类不理解的方式寻找到了因雨果的联系,当然我说这些不是为了玄学,而是为了让各位爷认识到这个问题,很多事情因束缚于人类的躯壳而无法去理解,如四维空间或者更高维度的空间是不可想象一般,祖母悖论等各种问题,都是认识论与真理论的不统一而导致的,生而为人是渴望追求真理的,但很多我们做不到,所以这也是我喜欢深度神经网络的原因,它有机会让我领略到更多的东西,好,废话讲完
RCNN->SppNET->Fast-RCNN->Faster-RCNN
在Object Recognition之前进行Object Detection的目的是为了减少不必要因素的干扰(比如从背景很复杂的图片识别出一个小动物,那样准确率会大大的降低),此外还能同时得到目标在图片中的位置(还包括宽度,高度)。
当决定要进行Object Detection的时候,大家想法都是差不多的,窗口扫描
嘛,不同大小的窗口从左到右,从上到下的,不用想,这样是超级浪费时间的,绝大部分的扫描都是没有用的,因为框住的根木不是目标,所以继续想,要是我能直接框住图片中的目标,而不框那些无关的背景,而且也不要框的特别准确,就好啦。 当年绝对有很多人有这样的想法,大家都知道目前的窗口扫描办法很多扫描是完全没有意义的,但是要怎么做哦,这种感觉有点像做题目的时候,有了一点思路,但是却想不到好办法,解决办法是什么呢?在RCNN里就用到了
RCNN(regions with CNN)
SS(selective search)
在RCNN中使用了一个叫做SS(selective search 选择性搜索)的方法,这个算法也算是为Object Recognition打开了一个新的大门(同时也要吐槽在此算法上太多的博文都是在水,啥也说,贴个论文截图就完事,当然也可能是我太水,理解不了其中的深邃思想,但我就是要说)
我来简单说说这个算法,在遇到上一段所说的问题,该论文作者发现,图片中的目标(比如人,汽车,小猫...)与背景是有区别的,比如颜色区别,纹理区别、大小区别等
如上图所示(截自原论文),图片中的大量天空背景是无效的,而我们想要检测的奶牛在颜色
、纹理
方面很相似,可以与背景区分开来
论文的思想是
- 首先通过利用颜色的相似性(毕竟如果颜色很相似,那么极有可能是一个整体),形成一些小的区域(上图左边最下面一层),具体算法是将整张图看成一个
无向图
,节点之间的距离就是像素的距离(在这里使用RGB计算距离并不好,最好转换以下色彩空间,比如HSV等),然后设定一个阈值,从其中寻找最小生成树
,形成最初的感兴趣区域(region of interest ROI)(如果没有学过离散,可以看以下这篇文章基于图的图像分割) -
然后对ROl进行再次的合并(如上图),但是合并要遵循一些规则--相邻区域的相似度
- 颜色相似度(color similarity):比较两个区域的颜色直方图
- 纹理相似度(texture similarity):比较两个区域的
梯度直方图
(这个会有点难理解,其实纹理的形状表现在其轮廓上,所有用梯度直方图可以很好的表示出纹理之间的差异) - 尺寸相似度(size similarity):防止大的区域和小的区域合并,要遵循先小的合并(因为图片中存在包含关系,比如轮子和汽车都很容易被框选出来,而轮子是属于汽车的,如果直接大的和小的合并,那么很多细节会被丢失掉)
- 交叠相似度(shape compatibility measure):这个不太好描述(见下图),当两个区域合并后,合并形成的新图形占其边框矩形面积的多少 代表着这样合并的合理性,比如图中的右侧,合并后它们只占了框定他们矩形的很小的一部分,当我们把这样的一个区域投入cnn中识别的时候,效果依然很差,还是存在大量的背景信息,所以这样是不合理的
- 相似度是上一步骤的计算得到的各种相似度的加权和,然后利用这个相似度作为合并的标准,然后重复这个步骤,直到最终合并为一个区域,而在这个合并过程中,得到的大大小小的区域的边界框,都将作为我们的侯选框
更多具体的算法细节可以看选择性搜索这篇文章(我也用了博主的一张图...)
R-CNN
(详情参看https://www.cnblogs.com/skyfs...,我下面的内容将会有很多都是这篇文章的,会穿插说一些自己的理解)
-
使用ss选出2000个侯选框,将候选框拉伸为227*227统一大小(拉伸方式为padding=16,直接拉伸,经过实验这样效果最好),再选用一个分类CNN(比如AlexNet或者其他),将分类数从1000改为20,并作fine-tuning
其实我觉得上面的这个图画得有点不太直观,AlexNet的网络结构为
5个卷积层(conv1+conv2+conv3+conv4+conv5) + 3全连接(fc6+fc7+fc8)
(所以上面这张图中最后一层就是softmax loss,而不是什么全连接层)
这里要说一下fine-tuning,大家都知道一般的图片分类训练,人工在进行数据标注时候较容易,所以训练数据很多,而目标检测的gt(ground truth)框标注起来很费事,所以训练数据很少,这种大型的网络训练是很浪费时间的,因为使用的CNN,其中大部分做的工作都是将图像中的特征抽象出来,所以其中的大部分参数是可以直接拿来使用的(至少是很接近我们预期的目标的),在这里使用的的AlexNet,其已经实现了1000对象的分类,而RCNN中要实现检测的20个类别也在其中,这时候肯定有人会想,既然这样,还不如不要做fine-tuning了,又不是不能识别(不断的质疑、思考将会促使我们进步),RCNN作者RBG大神对此进行了研究测试,发现效果并不好,具体的原因我先卖个官子。
这时候停下来思考一下整个目标检测步骤该是怎么样的
- ss得到侯选框
- 检测侯选框中的是否是目标的得分情况
- 按照得分情况对侯选框进行排序,然后按照某种规则筛除一些框
- 对最后剩下的框做一个边框回归(将框位置和大小微调一下))
乍看好像挺合理的,直接用AlexNet计算预选框为目标的概率(softmax输出为概率)就好了啊,然后按照上面步骤进行下去,那么这样的话,最终的准确率会让你大大的失望了,研究人员的一直在做的事情就是想不断的提高正确率以至于想出了各种巧妙的办法,而我们这里的做法不觉得太粗鲁了吗?为什么呢?这和我们的数据有很大的关系,AlexNet训练用的数据或者说很多其他的图片分类网络使用的训练图片往往是图片中间是事物的主体,而且几乎没什么噪音,而我们这里使用ss得到的2000个预选框情况真的是惨不忍睹,绝大部分都是背景不说,就算框中有主体存在,那也往往是残缺不全的(只框到了部分),所以这样的网络是不能直接用的,我们要用自己的数据fine-tuning一下(训练一下CNN)
-
fine-tuning
首先我们标注数据,用于训练CNN,使用SS获得的2000个预选框,IoU(不懂的自己查下吧,10s就懂)>0.5的标记为正样本,反之为副样本,之前说过去掉最后一层(去掉fc8,其原来为1000),改为20,然后随机初始化这一层的参数,其他层参数不变,采用SGD,学习速率设置为0.001(因为原AlexNet使用的是0.01,这样设置的好处是不会为原来网络的参数造成大的影响,只是在微调),batch size为128(32个正样本,96个副样本),你可能还会想,使用这样的数据进行训练,最后得到的结果会好吗
其实这样有点像是被牵着鼻子走的感觉,但是不要着急,学习的过程本来就是会有好多忽然想不明白的地方,毕竟是在用短短几天的时间去感悟别人辣么久的研究成果
-
训练SVM
在做完上一步的fine-tuning后,我们并不是要使用其来预测预选框中内容为目标的概率,而是要使用fc7层(20分类的softmax前一层)的特征来训练SVM(因为是20分类,所以训练20个SVM),负样本为IoU<0.3(包含完全没框住目标的,比如背景,以及框住了目标一点点部分的,这样的预选框并没有意义,所以将其认定为负样本),正样本为将目标完全框住的预选框
那么先使用CNN+softmax进行fine-tuning,然后再使用SVM的意义在哪里呢?为什么不直接单独使用softmax进行预测,或者单独使用SVM进行训练预测呢?为什么要使用不同的定义正负样本的策略呢?其实这一切的原因其实都是由于我们的训练数据导致的。 首先我们知道CNN+softmax训练是十分容易过拟合的,因为softmax loss计算的是概率,这样的损失函数对于精度的追求是无止境的,只要继续训练,很容易就会产生过拟合的情况,往往的解决办法是使用大量的数据,而目标检测缺少的就是大量的数据。SVM使用的是打分策略,一旦分数超过那个delta,就不会再继续调整了,所以其使用小样本训练效果也会很好。所以我们自然而然的就想到了直接使用SVM(不进行fine-tuning,直接抽取fc7的特征进行训练),但是效果惨不忍睹,原因是什么我上面也解释过,因为不合适,事实上RBG大神在训练的时候,试过直接使用conv5、fc6、fc7进行SVM训练,但是准确度实在是太低(精度上不去),甚至其中结果最好的是使用conv5,所以他想到了还是必须要进行fine-tuning,于是便使用CNN+softmax测试了一下,而且为了防止过拟合的问题,特意的将loU设置为0.5,达到了没有‘’过拟合‘’,然后使用fine-tuning后的conv5,fc6,fc7进行了SVM测试,发现fc7的准确率爆棚。
那么为什么SVM的正负样本阈值要那样设置呢? 关于负样本的阈值设定,作者测试了IoU阈值各种方案数值0,0.1,0.2,0.3,0.4,0.5。最后通过训练发现,如果选择IoU阈值为0.3效果最好(选择为0精度下降了4个百分点,选择0.5精度下降了5个百分点),即当重叠度小于0.3的时候,我们就把它标注为负样本。而正样本肯定是要设定为将目标完全框住的预选框了,这样训练后的结果是,能够非常逼近目标的预选框将会得到高分。
-
NMS(Non-Maximum Suppression 非极大值抑制)
当SVM训练完毕后,我们将一张图片的2000个预选框输入,最终得到2000*20的矩阵(2000代表预选框的数量,20代表每个预选框在每个类别的得分(置信度)),然后使用NMS筛除绝大部分的多余的预选框,具体做法如下
- 首先从每个预选框中找出最高得分类,确定预选框的预测结果
-
一共20个类别,从第一个类别开始,将所有属于这个类别的预选框放到一个集合Bi(i代表第几个类别)中,按照分数进行排序,从高到低,使用最高分以下的所有预选框和最高分预选框计算IoU,如果IoU大于设定的阈值,则将这些符合的条件的预选框删除(目的是对于同一个目标只保留一个得分最高的预选框),然后将最高分预选框放入目标集合Di中,剩下的预选框继续重复这个过程,直到这个集合为空。
举栗:当前排序为 A B C D E F G,A得分最高,使用 B C D E F G和A计算IoU,结果B D E都符合,则从集合中去掉B D E,此外将A放入另一个目标集合中,这时候当前集合只剩下C F G,F和C的IoU值符合,去掉F,C加入目标集合,此时集合中只剩下G,将G放入目标集合,当前集合为空,然后进行下一个类别的判断
-
Bounding box regression(边框回归)
(边框回归终于来啦,此真乃神来之笔,以前从来没想过回归还能这么用,真的是长见识了,也希望各位能感受到其精髓之处,还有就是边框回归在后面还会一直使用,一定要搞懂了)
网上关于边框回归的介绍少之又少,我也不知道我的解释会不会让大伙满意,先看着吧,有什么不理解的留言就好了
在上一步NMS后,我们得到了一些预选框(如下图所示,图是盗来的...)
我们得到的筛选后的预选框多数情况是如图中红框所示,虽然框住了主体部分,但是和gt依然有些出入,我们需要使用边框回归将其微调一下,具体做法如下所示
* p为筛选后的预选框
* G^为我们进行边框回归后的目标
* G为gt
边框回归想做的事情很简单也很容易想到,描述一个预选框的信息有 (x,y,w,h),x,y代表其中心点的坐标,w代表宽,h代表高,想要实现预选框与gt之间的变换,我们只要能够将(x,y)平移到gt的中心,然后对w和h进行伸缩变换就好了(即进行一个平移变换和一个伸缩变换)
先看论文给出的公式(markdown不知道怎么打这公式,我就截图了截图来源,侵删)
从上面公式中可以看出,在进行回归训练的时候,我们输入的是预选框的pool5层的特征(AlexNet的第五个卷积层后跟着一个max pooling,就是这里的我们预选框的输入,pool5的特征信息中包含了预选框抽象后的一些特征),gt的(x,y,w,h)作为‘’标签‘’来进行监督训练,下面我来说一下自己对这些的理解
首先我第一次看到这里的时候觉得很诧异,一个回归是如何做到 仅仅输入一个预选框的信息 就能得到校正信息的?要知道我们在测试的时候,仅仅只输入预选框的数据,整个回归是对全图毫不知情的,感觉这样的过程很不可思议,于是对其特别感兴趣每当我遇到自己无法理解的东西时候,都会提醒自己是不是陷入思维误区了,而且这仅仅是一个线性回归,这不像是深度神经网络这样的黑盒子,让人完全摸不到头脑。试想一下,人类在见到半个小猫的身体的时候,是大概能够猜测出来小猫头的位置的,这里应该也是类似的,我们通过对预选框pool5层数据进行训练,让其对一个目标的‘’整体‘’敏感,从而当我们输入的预选框没有完全框中目标的时候,它知道这个预选框与真是的目标相差了多少,从而给我们以反馈
我们希望学习到平移量和伸缩量,有的人会想,既然已经做的是回归了,为什么不直接返回具体的平移量和伸缩量,使得Px ,Py直接加上,Pw Ph直接乘上,这当然是不行的,想象一下归一化,因为输入的图片大小是不一样的,所以平移的值有大有小,当我们不想让网络学习到大小差异的时候,一般做法都是归一化(即将有量纲转为无量纲),所以我们这里除以Pw,Ph
而至于为什么在进行伸缩计算处理的时候要加上log形式,我认为是因为在Loss函数中,tx,ty是有正负之分的,所以也要将其处理为相同的形式,将原来的(0,+无穷)映射到(-无穷,正无穷)(当然不会无穷这个夸张了...)
上面的优化函数大家应该都看得懂,最后加入了L2正则
最后训练完毕后,按照上面式子即可得到结果(d(P)代表pool5特征经过变换后)
哇,RCNN终于说完啦,不得不说,RCNN想法巧妙,作者真的奇思妙想,但是确实是太复杂了,完全没有端到端
的那种爽感,像是在东拼西凑,不过有了这些基础打底,后面的看起来会很轻松的,如果觉得这里有哪些不懂的或者一时间难以接受的,不要着急,慢慢理解嘛或者留言,毕竟我光写就写了好久的了,拜了个拜~
Fast R-CNN
在谈Fast RCNN之前,先介绍在RCNN后的新技术
SPP Net
SPP Net由以下两部分组成
SPP (Spatial Pyramid Pooling 空间金字塔池化)
在RCNN中,预选框大小不一,而图片输入CNN后经过卷积,还需要进行全连接,很显然输入不同大小的图片将会导致全连接层无法工作,所以所有的预选框在输入CNN之前都经过了crop(剪裁)或者warp(拉伸扭曲),以固定的大小输入,虽然RCNN作者尝试了使用不同的变形操作从而使得精度较高,但不管怎样都不可否认的是图片确实变形了,在一定程度上使得图片失真,从而影响到了最终的效果,而SPP的思想便是无论你输入的图片大小是多少,使用不同尺度的池化层将其变为固定大小的特征(详情见下图)
假设我输入的图片经层层卷积处理后,到达SSP层,当前大小为40*60*256
-
金字塔第一池化层
,将输入特征切分为1
个40*60*256
特征,对其池化,得到1
个256维度特征 -
金字塔第二池化层
,将输入特征切分为4
个20*30*256
特征,对其池化,得到4
个256维度特征 -
金字塔第三池化层
,将输入特征切分为16
个10*15*256
特征,对其池化,得到16
个256维度特征
将上面的到的256+4*256+16*256
特征叠加起来,作为全连接层的输入,就是这么简单啦,但是效果是出奇的好,这个算法也是何凯明
大神提出的
ROI映射到feature map
ROI(region of interest)即我们之前提到的预选框,这个想法的具体内容是,通过SS选择出来的2000个预选框输入CNN计算特征速度太慢,为什么不把整张图直接输入CNN,得到一整张图的特征,然后根据各个预选框的位置从那个一整张图的特征中crop对应的特征,再输入SPP进行运算呢,后来经过这般改进后,准确度没有受影响,而速度提高了好多好多(示意图在下面)
在RCNN的基础上加上以上两项技术,即组成了SPP Net,但是即便这样,依然是存在些许问题的,而Fast RCNN即解决了很多问题
ok,下面说一下Fast RCNN的改进之处
上图便是Fast RCNN的网络结构了,其相对于RCNN的更改之处在于,将原来的pool5层替换为Rol池化层
,在原来的全连接层后又加上了一个bbox回归
Rol池化层是简化版的SPP,它只进行一次池化,即将输入的预选框的映射特征分割为r*r块区域,再进行池化分类不在是以前的先softmax分类进行fine tuning,然后svm再使用分类,然后再bbox回归,现在而是
分类
和bbox回归
同时进行,即完成了端到端
如果是一直看下来的同学,肯定会有疑惑,大概的疑惑应该是以下几点
- RCNN中说如果不fine tuning准确度会大大下降,这里这样做效果会好吗
- RCNN中说因为数据少,直接使用softmax分类会导致过拟合,那为什么还要用softmax呢,svm为什么不用了呢?
- 不进行fine-tuning而直接进行bbox回归,准确率会高吗?
上面应该是一些直观的问题,我说一下自己的理解,具体的分析推荐大家看一篇博文,里面说的已经很详细了
先说说作者为什么不再使用原来的RCNN和SPP那种结合模式,其一,分步的训练很繁琐,一个环节出问题,步步出问题,前面步骤一旦确定就不再改动了,很死板。 其二,无论是训练还是测试的时候,因为要使用到pool5和fc7的特征,需要占用磁盘存储空间,导致速度变慢,其三,因为训练是分步骤的,使得后面svm的训练和bbox回归的反馈无法传递回CNN,也就无法进行训练调整,阻碍了准确率的进一步的提升,其四,spp因为使用的是金字塔池化,导致反向传播的时候效率低下,或者说很难反向传播
说到这里,大概应该能有一点感觉,Fast RCNN的这种采用multi-task loss将会相辅相成的训练网络,而且训练的数据也要按照要求处理,具体的细节请看下面博文,遇到不理解的地方,可以留言
Faster RCNN
哇,终于写到Faster ECNN了,本来以为学习目标检测的演进
会是一件很快的事情,结果拖了那么久了...想玩完全理解真的是一件很费时的事情啊
在这篇中,我还写写如何在caffe下训练Faster RCNN以及对代码做一些注释说明,还会再做一个基于Faster RCNN的小项目吧,let's begin
(aaaaaaaaaa,今天写的一天的东西丢掉了。。。。。。。。好难受啊,我以后写东西的时候再也不走神了,我决定直接代码开始了,今晚要是让我再写一遍,我会崩溃了,等那天心情好了再重新写好了,说不定那时候会有更深刻的认识呢)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。