之前总结了一下卷积网络在分类方面的一些网络演变,但是自己做的是语义SLAM,所以对于目标检测和语义分割甚至实例分割算法都要有所了解,毕竟以后要拿来用,不了解那根本没法用。这个也是结合深度学习大讲坛的课程和我自己的总结,个人觉得这个课程还是比较不错的,把整个算法脉络给我们讲清楚了,只要自己去梳理,也就能够比较快速的了解。自从2012年深度学习在ImageNet上面大放异彩之后,大家关注到了深度学习在计算机视觉领域的巨大潜力。首先来对比一下传统的目标检测算法和基于深度学习的目标检测算法之间的不同点:
深度学习用于目标检测的算法从思路上来看,可以分为两大类,一类是two stage的方法,也就是把整个分为两部分,生成候选框和识别框内物体;另一类是one stage的方法,把整个流程统一在一起,直接给出检测结果,主要包含SSD,YOLO系列。首先介绍两阶段的检测算法,其实这条路线基本就是R-CNN SPP Net Fast R-CNN faster RCNN R-FCN FPN,然后集大成者Mask RCNN。
预备知识
先讲一下目标检测里面都会用到的一些基本知识IOU,非极大值抑制。
IOU其实就是交并比,具体定义如下:
计算框A和框B的重合率:
这个是用来判断定位的准确度的。
非极大值抑制
所谓非极大值抑制,说白了就是取最大值,这个过程是一个迭代-遍历-消除的过程。第一步,对所有的框根据置信度进行排序,从低到高放到一个列表里面,从列表中取出当前置信度最高的,作为目标,把还在列表内的框与目标框进行比较,如果重合度大于阈值,就将该框从列表内删去,遍历整个列表。然后再取出当前置信度最高的,重复上述操作,知道这个列表最终变空。
Two stage
1.RCNN
RCNN是把深度学习用到目标检测领域的先驱,开创了一个时代!先了解一下这个方法的整体思路:
首先用Selective Search的方法,获得一些可能的候选框(这些框可能包含有需要检测的物体),随后将这些产生的框送到CNN里面进行特征的提取,最后利用支持向量机进行分类。
候选框生成(Selective Search算法)
下面来了解一下候选框的搜索过程,这个算法借鉴了层次聚类的思想,把这种思想用到了可能区域的合并中来。这个算法是基于2004年Felzenszwalb在论文《Efficient Graph-Based Image Segmentation 》上的一个改进,那么先来介绍一下这一篇论文。
这篇论文提出的是一种基于贪心选择的图像分割算法,论文中把图像中的每个像素表示图上的一个节点,每一条连接节点的无向边都具有一个权重(weights),以衡量其连接的两个节点之间的不相似度,这篇论文的创新点在于该算法能够根据相邻区域在特征值上变化速度的大小动态调整分割阈值。这个特征值就是类间距离和类内距离,如果类间距离大于类内距离就认为是两个区域。
定义类间距离为对应区域的最小生成树(因为把图像看做一个连接图,所以每个区域可以用最小生成树来表示)中权重最大的边的权重值,类间距离定义为两个区域内相邻点的最小权重边,如果两个区域没有相邻边则取无穷大。但是这样其实还是有问题,比如一个类中只有一个点的时候,它的类内距离为0,这样就没法搞了(每个点都变成了一类),所以作者又引入了一个阈值函数,用来表示两个区域的区域的类间距离至少要比类内距离大多少才能认为是两个区域。用公式可以表达如下:
其中Dif表示类间距离,Mint的表达式如下:
这里的τ就是用来控制最短距离的,一般取为C的负相关函数,k为一个常数。
算法实现分为以下步骤:
1.首先对所有的边进行非递减排序。
2.把每个节点都作为一个区域,记为S(0)。
3. 按照以下规则有S(q-1)生成 ,也就是第q条边连接和 两个节点,如果在S(q-1)中和 是分别属于两个区域并且第q条边的权重小于两个区域的类内距离,则合并两个区域。否则令S(q) = S(q-1)。
4.对q=1…m重复步骤3,最终获得需要的区域分割。论文在后面基于这个思想实现了两个具体的算法,一个是直接基于像素的,另一个是把每个像素映射到特征空间,再使用该算法,后者效果会好一些。
接下来介绍Selective Search算法,该算法利用上面的图分割算法获得的分割区域结果,再一次根据一些搜索策略(相似度)做了一个聚类。也是和上面的思路一致,首先根据获得的区域,算出每个区域和其他区域的相似度,不相邻的和自身与自身的相似度都设置为0,得到一个N*N的矩阵,然后将相似度最大的合并,再次计算相似度矩阵(这里是增量更新,只需要计算新生成的区域和其他区域的相似度就可以了),这样合并一次较少一个区域,对于N个区域需要执行N-1次合并,最终得到一个区域。
对于相似度的度量,作者主要选取了颜色和区域两大块,颜色作者比较了8中模型,最终选择了HSV,区域主要考量大小、纹理和吻合度(相交包含关系)这三个因素。简单介绍一下这四个是怎么计算的:
颜色相似度计算
颜色相似度计算以图像直方图的形式来进行的,每个通道分成25个bin(这是他们做了是呀发现效果不错),这样3个通道一共75个bin,这里需要注意的是,要对每个直方图进行归一化处理,以便于我们后面计算分数,分数计算如下:
对更新之后的区域,它的计算颜色分布直方图可以根据下式进行计算:
纹理相似度计算:
这里使用的是一种类似于SIFT的算法来描述空间的纹理特性,这里使用的是描述子,利用SIFT识别材料特性参考这篇论文《Exploring features in a bayesian framework for material recognition》。这里取了8个方向,方差为1的高斯滤波器(也就是计算加权)对每个通道进行了滤波,然后将得到的结果分到10个bin当中,如果是个3通道的图像,那么就一共有3*8*10=240个bin,然后对这些bin做归一化处理,计算方法如下:
合并后的更新方式也和颜色的更新方式一样。
大小相似度的计算:
这个其实就是鼓励小的区域进行合并,也就是把周边的小区域都合并了:
这里的size(im)表示整张图的像素总数。
吻合相似度计算:
这个就是用来填空白的,也就是说如果两个区域的面积之和与包含他们最小面积相差越小,分数也就越高。
这里的用来表示包含两个区域的最小区域。
最后考虑以上这些因素,得到一个相似度的分数计算:
中这里的取值只要在[0,1]就可以,这里作者强调的是多元化的策略,而不是一个优化,所以这里作者并没有进一步的讨论。
这样根据这种相似度的策略,我们就可以获得一系列的候选框了。(之前也看RCNN,基本就没去管这个候选框的产生,原来这里面还这么复杂!!!!)
这里虽然产生了候选框,但是候选框的大小不一致,对于卷积网络来说,必须输入尺寸一致,所以这里需要对生成的候选框做预处理。
作者在这里提到了两大类三种处理办法,第一类是各向异性缩放,其实也就是直接resize到目标尺寸。第二类是各项同性缩放,这里有两种办法,先扩充然后再裁剪或者是先裁剪再扩充,经过试验发现第一类直接缩放到目标尺寸效果最好。然后作者还发现如何对获得的框进行选取也有一些讲究,直接取出来的效果不是padding一下效果好,经过试验发现了padding=16 的效果最好。
CNN提取特征
提取特征的架构选择的是AlexNet,AlexNet的具体介绍可以参考我之前的一篇文章,里面有介绍。通过五个卷积层和两个全连接层来对每张图片提取4096维的特征,作者这里使用了在ILSVRC2012数据集上训练好的分类器模型参数来初始化作者的CNN模型参数,然后在PASCAL VOC训练集上进行微调。 作者最后根据每张图片获得的4096维向量,用支持向量机对图像进行了分类,这样出来的可能会出现框重叠的情况,通过非极大值抑制就可以解决这个问题了。
SVM分类
在微调之后,再送到SVM里面进行分类,在SVM分类里面,我们需要注意一个问题,SVM是适合于小样本训练数据的,所以作者在这里根据实验发现把IOU值低于0.7的都当做负样本来处理,这样效果会比直接用softmax的效果更好(这里是经过实验测出来的,作者也只是给了一些推测,所以神经网络这东西,有时候真的是玄学)。
SVM是一个二分类的问题,如何把它做成多分类问题呢?这里作者是通过给,21类物体,每一类物体都训练一个分类器,然后把这些分类器构成一个矩阵的4096*21的矩阵,然后与CNN提取的特征相乘即可(比如每张图片提取2000个可能的框,那么一张图片训练下来,到最后一层就是2000*4096),这样就能获得分类结果。
预测框回归
获得了分类结果之后,我们还需要对预测框进行回归。这里需要去学习一个回归映射,对于所有两个框之间的不一致,其实我们都可以通过平移和尺度缩放去变换到一起,于是作者就定义了四个函数,分别表示两个方向的平移和两个方向的缩放。
现在我们就是要去学这个变换参数,这里需要注意的是:只有预测框和真实框两者重叠程度较大的时候(IOU>0.6)才能认为这个是成立的,因为这其实是一种线性变换,要是距离太远,肯定就不能当做一个线性问题来处理。
这个学习的输入是P,输出的是平移变换和尺度缩放的四个值,而不是真实的预测边框。这四个值时通过pool5层的特征给学出来的,这个学习可以表示为:
对于训练样本,它给出的值可以通过下式求出来:
这样根据样本给的尺度变换和预测的尺度变换,损失函数设置如下:
这里肯定有很多小伙伴会有疑问,为什么这里要写成指数的形式,x,y坐标为什么要除以宽和高?这里我的理解这里使用的是相对尺度,因为远近观测不同,那么他们的中心距离边界的偏移肯定是不同的,那直接做一个除法,其实就能够把这种绝对尺度变成了相对尺度。写成指数形式是因为限制必须要大于0,所以就用了指数。最后这个正则化参数经过试验,选择了1000.至此,整个RCNN的东西基本就讲完了。
2.SPP Net
这篇论文打开了一个新的思路,我个人认为RCNN其实就是一个组装,把各种方法组装到了一起。SPPNet提出了共用特征卷积图,这样一张图片只用卷一次,速度肯定比你卷2000次要快得多。其次SPPnet引入空间金字塔池化,有效的解决了不同尺度的图片在全连接层输出不一致的问题。SPPnet其实就是解决了这两个问题,步骤还是和RCNN一样的,先采取一些算法生成候选框,这里只对一张图片卷积一次获得特征图,然后把这些候选框的坐标映射到特征图上面,最后分类和回归。下面仔细介绍一下这个过程:
候选框生成
候选框生成算法作者既用了Selective Search算法去与RCNN做对比,发现速度会比RCNN快,精度高。同时作者这里也使用了一个微软在2014年ECCV提出的EdgeBoxes算法,速度会更快。这个方法的主要思路在于利用边缘信息确定框内的轮廓数和与边缘重叠的轮廓数。这个算法的思路步骤可以有下图给出
第一行是原图,第二行是经过结构化边缘提取算法处理之后得到的边缘,第三行是经过Edge group处理之后的边缘,第四行是获得的正确框,第五行是一些错误的框。接下来就j讲一下获得第三行以及第四行的操作。
Edge group顾名思义就是一个边缘组,作者在每个点上通过不断寻找8连通点直到边缘与边缘之间的角度差值大于90度,以这种方式对边缘处理之后便获得了n个Edge group。作者获得了不同的Edge group之后,会对所有的组与组之间进行相似度评价,它以每个组的平均位置(中心点)作为评价依据,评价函数如下:
在这其中是两组的平均方向,θ_ij是平均位置x_i,x_j上的夹角,γ是一个超参数,作者在文中选择的是2。如果两个组之间的距离超过了两个像素,直接将相似度设置为0,同时为了提高计算效率,相似度小于0.05的也直接设置为0.
现在给定了每一个边缘组以及各个边缘组之间的相似度,我们先假定已知边框,就可以计算边对框的贡献,也就是权值,把权值为1的组算作该框内部,权值为0的就作为外部处理。对于所有的组计算权值公式如下
这里T是一个序列,它表示从边框重叠区域的一个边缘组到边框内的一个边缘组的序列(这里面每个序列之间的相似度都要大于0),如果一个边缘组不存在于重叠区域连通的路径,则权值为1,因为其实这里会有很多0,所以计算效率是比较快的。获得了每个组的权值,我们就可以计算一个边框的得分,计算公式如下:
这里的表示一个组内的所有点的数目,分别表示框的宽和高,k是一个超参数,这里取的是1.5,用来抵消一些偏差较大的边框具有更多边缘的情况。在实际计算中可以通过对图像积分来加速计算,具体的可以看论文以及代码。
最后,我们都知道对于一个边框而言,边框内部的组应该不如边框边缘的组重要,所以对于边框内部的组,其实就是把这边框内部的给减去,具体计算如下:
这里减掉的是以框为中心点,长宽各为整体的1/2的小框。在后面发现以这个作为分数,效果会更好一点。
那么如何获得这个重叠区域呢?首先分别对水平边界和垂直边界建立两个矩阵,每个矩阵当中只有边缘组才存储索引值,比如沿着每一行先创建一个列表,这里面存储的是两个边缘组之间的转变,如果存在连接,就存储下值,否则记为0,这样这个矩阵里面只有有边缘的地方才会有值。由于绝大部分位置都不属于边缘,所以这个数据结构会很方便查找,所以很快就能够得到一些重叠的区域(具体的建议看看代码)。建立好了这种存储结构之后,作者就根据上述的得分情况用贪心算法搜索得到一些可能存在的框。这就是edge boxes算法的大体思路。
卷积层提取特征
这是SPPnet的改进之处了,原来RCNN是对每一个候选框都进行卷积,提特征,SPPnet通过一次卷积的方式避免了重复计算问题。要一次卷积的话,就需要解决点与点之间的匹配,也就是说原图像的坐标经过映射之后到特征图上的坐标。这个其实是很容易想到的,对于卷积网络而言,只有stride才会改变网络的尺寸,所以对于左上角和右下角的坐标计算的方法如下:
这里的s是所有stride的乘积。
这样一幅图片经过卷积之后,对应的特征位置就能够找到,但是由于各个框的大小不一致,而神经网络则是要求输入的大小要相同,为了解决这个问题RCNN通过裁剪缩放的办法来解决这个问题,但是这样会带来精度的损失,你看,好好一幅图,左右两边明显看着就不一样。于是作者就提出了空间池化层来改善这个问题。
作者通过分析,之前通过卷积好之后,把每个区域取出来再送到全连接层里面去训练,只要保证输入到全连接层的数目保证相同,那么久没什么问题了,于是作者对RCNN进行了改进,流程如下:
上面的步骤是RCNN的,下面是作者提出来的空间池化层。这个空间池化层其实思想也分简单,把每一个边框,分成3个层次去池化,也就是说将图片划分为4*4的小格,每个小格取一个数,2*2的小格每个小格进行池化和对整张图像进行全局池化,然后在合并起来,这样得到的输出就是固定的,具体见下图
空间池化层实际就是一种自适应的层,这样无论你的输入是什么尺寸,输出都是固定的。SPPNet改变了卷积的顺序,提出了自适应的池化层,避免了预测框大小不一致所带来的问题。从这个结构设计上来看,整体也非常巧妙,不像RCNN那样蛮力求解。
SVM分类+边框回归
这里也是延续了RCNN的思路,没有什么特别的改进,所以也就不再介绍了。
3.Fast RCNN
这篇论文是Rbg大神的作品,也就是RCNN的作者,这篇论文是他在去了微软之后做出来,当时何凯明也在微软,所以这篇论文是借鉴了何凯明的SPP Net的思想的,这篇论文做了一个多任务学习,就是网络同时学了边框预测和分类两件事,而不是像以前一样物体分类归分类,边框预测归边框预测,因为分别学两件事其实由于样本的不同,会变得比较麻烦,占用存储空间比较大;同时引入了一个ROI pooling的操作来解决不同边框大小不一的问题,这个ROI pooling其实就是单层的SPP layer,这就是本文的两个创新点。
这篇论文还是需要进行预先的产生一些候选框位置,这里用的是Selective Search算法产生一些候选框,也就是ROI区域。然后还是对图片只做一次卷积,获得特征图,然后通过ROI pooling对每个区域获得一个固定的输入,经过全连接层之后,分别送到分类的子任务和回归的子任务当中,然后再通过损失函数对网络参数进行调整。(注意SPP和RCNN之前都是没有办法做到一体化调整参数的,他们的都是单任务调整)作者这里也分析了为什么SPPnet没有办法进行整改网络参数调整,主要是因为是SPPNet在训练的时候样本批次都不是来自同一副图像,这样反向传播的时候需要的跨度就会非常的大,这样就会导致异常低效。作者这里使用SGD优化的时候,用的是一种分层次小批量采样的办法,每一次用N幅图来更新参数,但是每张图就取R/N个感兴趣区域(这里的R是指批量的大小),这样只要N取的小一点,那么更新参数也是可以实现的(因为这样你更新参数所需要的其实也就是几张图片,而不是像SPP Net那样需要去更新很多张图片,其实就是把原来的随机给固定了一下,固定了只能来自N张图片,然后在ROI区域上面去随机采样),这里训练数据保证保证25%的正样本,75%的负样本。
ROI区域采样,其实就是单层的SPP Layer,SPP Layer把每个框划分为了不同的层级,4*4,2*2,1*1,这里只保留了一层,也就是每个框经过ROI pooling之后固定输出H*W,就是将一个款平均划分成H*W个小格,每个小格内采用最大池化。
网络结构,可以利用经典的网络如VGG等,VGG的介绍可以看我之前的一篇介绍,然后对VGG进行一下小改造,把最后的一层池化换成ROI pooling(这个ROI的位置是根据SPP Net当中的计算图片到特征图映射获得的,具体公式可以看SPP Net),然后再接全连接层,然后在跟两个子任务,回归和分类。
多任务网络,对于一个多任务网络而言,最重要的就是损失函数的设定,这里的分类采用的是softmax损失函数,定位采用的是平滑L1损失函数,不过训练的时候需要注意,背景区域不计入定位损失函数。具体表达式如下:
这里的u>1表示背景的定位损失函数不计入。
同时作者用了两种方法对网络进行了测试,一种就是单一的图片,另一种就是对每张图片进行尺度变换,经过测试虽然多尺度精度高1个百分点左右,但是速度却更低,这也间接证明了神经网络可以自己学到尺度不变性。
最后作者利用SVD分解来加速全连接层的计算,因为我们通过共享了卷积特征之后,整个计算量主要就集中在了全连接层的计算上面。(这里是在测试的时候,训练的时候不能分解,不然这个矩阵都还没有得到,我们就没法做这个分解啊!)简单介绍一下SVD分解,对于任意一个实数矩阵 ,SVD分解就是要找到它的左奇异向量
,右奇异向量 和奇异值矩阵 (特征值):
这里的U,V都是正交矩阵,也就是 。如何构成的呢?这其中U的列是由 的归一化特征向量按特征值降序排列组成的,V的列是由
的归一化特征向量按特征值降序排列组成的,Σ对角上的值由或在的特征值降序组成,其余为0。
作者在这里对权值矩阵进行了SVD分解,用前t个最大特征值来近似矩阵,相当于用两个小的全连接层去替代了大的全连接层,这样可以有效的降低计算时间(时间复杂度从O(uv)降到了O(t(u+v)),而不会损失太多的精度。
4.Faster RCNN
Fast RCNN虽然采用了多任务学习把回归和分类和卷积特征提取统一了,但是对于产生候选框还是单独的,于是任少卿在微软的时候受到何凯明、孙剑的指导,终于把候选框的提取也换成了一个网络,这样整个四步全部统一到了网络架构,大一统,所以效果也好!简单来说,可以把Faster RCNN=Fast RCNN+RPN,先看一下整个网络的构成
因为Faster RCNN是一个统一的网络,所以这个区域生成网络也能够共享前面的卷积特征,需要注意的是这里的区域生成网络其实包括两个任务,第一个是获得边框的坐标(回归4个值),另外一个是这个框内是背景还是前景(二分类)。
这里作者通过在特征图上面滑动生成一些框,注意:这里每个点都会生成9个框(3种长宽比例和3中尺寸的自由组合,3*3=9,这里的尺寸是基于原图而不是特征图),然后这些初步的框会去进一步学习一个线性变换,这个与RCNN里面的框回归是一样的,都是去学习尺度的变换和平移变换4个参数。注意:上图只是针对每一个3*3的滑窗,而不是整个特征图都只变为了一个256维的数组。接下来我们都只针对一个滑窗进行讨论,每个3*3的滑窗变为了1*1*256维(实际上从这个层来看是W*H*256)的数组,对于判断前景和背景,我们需要做一个二分类判断,同时因为有9个尺度大小不同的框,所以我们输出应该是18维的结果(2*9,用一个1*1*256*18的卷积核即可),同理针对每一个回归边框也是输出36个结果(4*9,用一个1*1*256*36的卷积核)。如果去看caffe的源码会发现在softmax分类之前和之后都有一个reshape层,这个是与caffe的代码实现本身有关系,具体可以参考softmax_loss_layer.cpp。
损失函数,这里RPN网络是有两个任务,所以这里的损失函数也是有两部分组成,一部分是分类,一部分是回归。在定义损失函数之前,需要先定义什么是正例,什么是负例。作者在这里定义了两种情况的正例:第一种,与每个真实的框重叠比例最大的是正例,第二,与真实框的IOU值大于0.7的是正例;负例:与任意一个真实框的IOU值都小于0.3的。其余的框都不计入损失。损失函数的具体表达形式如下:
这里的回归框损失函数使用的是L1平滑损失函数。在给出了损失函数和网络结构之后,开始训练网络,作者在论文中提到了三种训练方式:交替训练、近似联合训练、非近似联合训练。这里作者用的是交替训练方式,具体而言分为4步:1.先基于ImageNet训练好的模型去训练RPN,2.基于训练好的RPN和预训练模型去训练Fast RCNN,3.把共享的卷积层固定,微调RPN,4.固定共享的卷积层,微调Fast RCNN.这4步交替进行训练整个网络。
最后,为了消除一些冗余,在生成ROI区域的时候,针对重叠框采用了非极大值抑制(根据二分类输出的概率)的办法,减少了一些候选区域,最后得到了候选的区域。
这样获得了候选区域,就再把这个送到Fast RCNN网络当中去检测就可以了。这是一个影响非常深远的工作,因为第一次把整个目标检测全部纳入到一个网络当中了,而且检测速度和准确率明显上升,其实我们这里可以看到多任务带来了一系列的好处。
5.R-FCN
这篇论文也是微软亚洲研究院何凯明孙剑团队所做的工作,作者通过分析目标分类任务和检测任务之间的异同,发现对于分类网络而言,要求对位置不敏感,而对于检测网络而言,对物体的位置是有要求的(因为要把物体定位出来),而当前工作基本都是基于CNN来做抽取特征,池化会损失位置精度,所以作者提出来了一个位置敏感层,就是说要把这个位置的信息加进去。这是这篇论文的主要思想,就是为当前的检测网络加入一个位置敏感层。
这个位置敏感层的设计非常的巧妙,先来看看整体的结构框架(我觉得深度学习网络架构非常棒的就是很多东西只要给出了网络的架构,就很容易理解,看论文形象生动)
首先整体架构还是与Faster RCNN差不多还是由一个卷积网络提取特征,然后用一个RPN来生成一些候选框,最后进行分类和修整候选框的位置。但是这里需要注意到作者在feature map之后引入了一个卷积操作,得到了一个k*k*(c+1)通道的特征图,看下图更清楚一点。
这个K*K*(C+1)通道的特征图是用来干啥的呢?这个就是作者思路的关键点了,作者将ROI区域划分成k*k的格子(用来池化),每个格子的池化数据都来自于固定的单个通道所对应的区域,这样其实就能强迫某一个通道只去学习对应格子的特征。这里使用了一个平均池化,经过这样的一个操作之后,获得的其实就是c+1个通道,每个通道k*k。(这里其实就是对通道下的功夫)最后把这个k*k个值相加,就能够获得c+1个分数,然后用softmax函数就能够输出当前区域的预测类别。
在回归框的设计上也是类似于分类的思路,对每个小框进行估计偏移量和缩放量,这样就能够获得4*k*k个值,然后对着k*k个值进行求和,最终得到回归框的4个值。
损失函数这里也是由交叉熵损失函数和平滑L1损失函数构成,对于负例不计算边框损失函数。训练的时候还是需要预先训练边框生成网络,随后再进行端到端的训练。
6.FPN
特征金字塔网络,这个方法对不同的语义层级都进行了预测,因为对于底层的信息来说,位置精度相对更高,高层语义信息的语义特征更为抽象,所以本文就将两者进行了结合。(这篇论文是何凯明去Facebook之后的工作)
这是四种常见的多尺度融合的操作,第一种就是把一副图片缩放成不同尺寸,然后去对每张图进行预测,第二种则经神经网络处理后直接对最后的一层做预测,这是SPP Net ,Fast RCNN, Faster RCNN的操作,第三种则是直接从神经网络当中拿出不同尺度拿出来做预测,这是SSS所采用的多层次信息融合,第四种就是本文所使用的多尺度融合,把神经网络中的层拿出来,然后特征图进行上采样,得到与上一个尺度相同的图像,两者相加,然后通过一个3*3的卷积核来融合一下,最后再进行预测。(这里1*1的conv是为了消除通道不一致)
这就是本文的核心思路,非常的简单,现在作者就用这个网络去替换Faster RCNN当中的RPN网络。原来的RPN网络在一个尺度上面生成不同大小不同长宽比的边框,这样并不能利用到多个尺度的信息。作者把从神经网络拿出来的特征图称为C,通过上采样加融合的特征图称为P,现在把原先的RPN网络在单尺度上生成多尺度的边框替换为了在不同的P层生成边框,因为每个P的尺度是不一样的,所以在每个P层只需要生成一种尺度的边框(当然长宽比还是要保持不同)。
这样产生了一些边框之后,就要进行ROI pooling,因为你这个区域是多个尺度产生的,那么很自然的就想到在pooling的时候应该要在不同的尺度上pooling,由于你大尺度的边框是在靠后的层产生的,于是作者给出了一个取特征层的公式:
这里作者借鉴了ResNet做目标检测任务时的取的第4层作为特征层,所以这里k_0取的是4。这里的224是ImageNet中图像的标准长宽。
接下来的其余部分和Faster RCNN一致,共享网络,后面接分类和回归。
7.Mask RCNN
这是一篇引入了分割的目标检测,其实就是实例分割,这样就完成了计算机视觉的分类、检测、分割三个任务,集大成者,目前很多工作都是基于Mask RCNN来开展的。简单的来说Mask RCNN就是在Faster RCNN的基础之上又添加了一个语义分割网络(FCN),然后在对ROI Pooling的取整改为了双线性插值(ROI Align)。
ROI Align是指像素对齐,什么叫做对齐,也就是说物体怎么移动,我们检测结果就怎么移动,这是因为我们引入了分割网络,分割要求点对点,所以必须要对齐。原来的ROI pooling有两个操作会损坏位置信息:在候选框映射到特征图层的时候,这里需要取整(因为我们做检测任务对这个要求精度并不高)第二个是在ROI Pooling的时候,要对特征层划分bin,每个bin划分的时候也是取整。所以引入这个ROI Align其实就是为了解决这两个问题,那么其实就很简单了啊,这两步我都不取整,取浮点数。首先把边框从原图映射到特征图的时候,取浮点数,然后对于取每一bin的时候,我们同样按浮点数来取,最后我们在每一个bin内都取4个点,这4个点均匀分布(他们的位置还是浮点数),这个时候通过双线性插值来确定浮点数所对应的像素值,然后每个bin对这4个点取max pooling。
这样我们获得了每个ROI Align的输出值之后,我们再引出一条网络,用来做分割,这里使用的是FCN,下图是分别以ResNet和FPN为基础架构的网络结构。
从这个结构图我们可以看到最后有一个14*14*80和28*28*80输出,这里的80是类别,也就是说,这里我们是在不同的通道上去预测的类别,那么其实我们在每个通道执行的是一个二分类过程,即前景和背景。这里和传统的FCN不同,传统的FCN是去预测每个像素属于哪一类,是一个多分类问题。这种方式可以有效的避免类间竞争,这里的类别信息我们可以通过检测网络获得。
对于多任务网络,损失函数是非常关键的,我们可以很直观的判断损失函数肯定是由3部分组成,框回归、目标类别、掩码。函数表达式如下:
前两项和Faster RCNN当中的定义一样,第三项,由于我们是二分类的问题,所以这里使用平均二值交叉熵损失函数(注意,这里每个通道的损失仅与其对应的类别的ground-truth有关,与其他类别之间无关)。最后一层使用的激活函数是sigmoid激活函数。训练的时候,还是两阶段训练,先训练候选框生成网络再训练剩下的检测分割网络。
这篇论文的关键点在于,所有组件都是灵活,可替换的,主体网络、检测网络、分割网络都可替换,针对不同任务需求可以进行个性化指定方案。到目前为止两阶段的目标检测算法R-CNN, SPP Net, Fast R-CNN, Faster R-CNN,R-FCN, FPN, Mask R-CNN基本介绍完了,从这个算法演变过程可以看到,先从分散的组件组建演变为多任务一体化网络,加强多层次特征融合,挖掘卷积通道的潜力以及多任务组合可以不断的提升网络的精度。这个其实在分类网络里面也有体现,感兴趣可以看看我之前关于卷积网络结构演变的相关介绍。
One Stage
1. YOLO
YOLO是you only look once的缩写,从这个名字就可以看出,YOLO的特点就一个字快,其次YOLO可以对整张图片进行操作,这与RCNN系列不一样,只针对一个ROI区域。这篇文章的创新点在于,把候选框的生成和检测一起融合到了一个网络当中实现了实时的目标检测。YOLO的整体思想是将整个流程放到网络里面,将整个过程视为一个由网络自动学习的过程(其实从思路上看,更接近于深度学习的本质:让网络自己去学习一切)而R-CNN系列是将这个过程拆分为两步,生成候选框、框内检测。
首先还是来看看YOLO的整体流程:
YOLO整体分三步,第一步将图片resize为448*448大小,并且每幅图片分成7*7的格子第二步,通过卷积网络对图像进行抽取特征,然后全连接层负责对每个框进行位置的回归以及每个框包含检测目标的概率和类别的判断;第三步,非极大值抑制。
具体操作上:将一张图片划分为S*S个小格,每个小格负责检测落入该区域的物体,同时每个小格要预测B个边框以及该边框对应的置信度,这里的置信度定义为是否含有物体的概率以及预测的框与真实的IOU值(这里物体的概率只有0或1,其实就是前景或背景)。每一个网格的回归值有5*B+20个,B个框,每个框需要预测5个值,分别是中心的坐标(边界框相对于网格单元边界框的中心,比值),长和宽(相对于整张图片的长宽,比值)以及置信度,最后每个网格还要预测这20类的概率。所以对于每一张图片最后的输出值一共有S*S*(B*5+20)个。在论文中,作者S取的是7,B取的是2。注意这些划分都只是作者在结构上的设计,具体的体现就是在最后的全连接层输出上面,没有对整张图片进行显式的划分。(做深度学习一定要注意,有些东西就是你强制让网络去学的)
作者这里预训练网络的输入是224*224的,这是基于ImageNet的数据,训练好了之后,在前面加上4个卷积层,权重随机初始化,把输入变成了448*448的。
整体的网络结构如下图所示:
这个网络架构是在Google Net的基础上改的,Google Net的介绍可以看我之前的一篇知乎文章,这里交替使用1*1的卷积层是为了降维。这里的全连接层激活函数都是使用的漏泄修正线性激活,最后一层是直接输出的
这里重点需要介绍一下损失函数,对于one stage的网络而言,结构设计和损失函数的设计是非常重要的。先来看看这个函数到底长啥样:
一看这个误差函数就知道,真的是很复杂,其实也就是由三个部分组成的,框的坐标误差,IOU误差以及分类的误差。这里IOU误差由分为两部分,一部分是含有目标的置信度预测值和不含有目标的置信度预测值,这里需要注意的是对于不含有目标的框的置信度损失,我们需要令他小一点,毕竟一副图片中大部分都不含有目标,如果这个设置过大的话,那么容易忽略掉存在目标的框,造成训练发散,所以这里设定了权值。长宽的误差可以发现这里用的是根号,这样做的目的是因为同样的绝对偏差对于小边框而言比大边框影响会更大。YOLO的思想是让边框预测落在自己中心的物体,所以这个时候就必须要在损失函数上有所体现,这里的表示目标是否出现在第i个网格,表示第i个网格的第j个边框负责该预测。YOLO在训练中不是每个预测框都要与真是IOU计算误差,这里选择的是IOU值最大的与真是边框求误差,也就是说每个网格只有一个边框与真实值求误差,并反向传播。
2.YOLO V2(YOLO9000)
这篇论文中作者对YOLO进行了一系列改进,然后得到了YOLO V2,同时作者提出了一种数据联合训练方法可以结合不同数据集进行训练,得到了可以分9000个类别的检测算法。
作者借鉴VGG重新设计了一个模型叫darknet-19,.有19个卷积层和5个maxpooling层,处理一张图片只需要5.58 billion次运算,速度更快(darknet是一个较为轻型的完全基于C与CUDA的开源深度学习框架,其主要特点就是容易安装,没有任何依赖项(OpenCV都可以不用),移植性非常好,支持CPU与GPU两种计算方式)。同时删除了最后一个卷积层,加上了三个具有1024个滤波器的3×3卷积层,其后是最后的1×1卷积层与我们检测需要的输出数量,最终每个格子输出是125个,因为每个格子需要输出5个框,每个框需要输出类别信息20个,置信度和坐标一共5个。
引入BN:作者在每个卷积之后就都加了一个BN层,mAP提升了2个百分点。BN层简单的来说就是减均值除方差,然后再学一个线性的y=ax+b,这里a和b是要学习的参量。
高分辨率适应:以前是在224*224的网络上进行的预训练,然后检测的时候再在前面加卷积层,使分辨率变为448*448。作者这次预训练直接就用的448*448,在ImageNet预训练然后再去适应检测网络,mAP提高了4个百分点。
引入锚框,这个是在Faster RCNN里面提出来的,就是说每个点生成一些长宽大小不一的边框,所以这里YOLO把全连接层去掉了,保留了卷积,这样可以有效的保留空间信息,同时这里为了保证经过卷积下采样之后能够得到唯一的中心点,对图像进行了缩放,缩放为416*416(416/32=13),原来的YOLO是网格复杂预测类别,边框负责预测坐标值,V2中每个边框预测都要预测类别,坐标和置信度。
引入聚类算法为锚框自动选择大小,首先在训练集上运行K-Means算法,这里采用的度量函数是基于IOU值的,因为如果是欧式度量的话,那么较大的边界框比较小的边界框产生更多的误差。
作者在训练集上发现k=5会有一个比较好的结果,于是每个锚点就产生5个锚框。
直接预测位置,锚框在之前Faster RCNN里面是用来预测偏移量和缩放的,但是作者发现这样会导致中心点可以出现在图像的任意位置(但是我们YOLO是要求只预测落在网格内的物体),所以作者还是沿用了YOLO直接预测坐标的方法。作者是在特征图上进行的操作,映入逻辑回归函数保证了中心位置的偏移只能在(0,1)之间,再加上网格的中心位置坐标,这样就得到了新的预测中心坐标。(这样限制了坐标位置)
每个锚框预测五个值,中心点坐标,长和宽以及置信度。需要注意的是这里的p_w,p_h都是聚类生成的先验。这个操作和聚类生成锚框长和宽,准确率大概提升了5%。
细粒度融合,无论是Faster RCNN,还是同样单阶段的SSD都用到了多尺度的信息,所以作者这里也用了一个跨层连接来实现多尺度信息融合,这个与ResNet不同的是:这里使用的是Concat。就是引一条旁路出来,把26*26的特征图通过一个1*1的卷积降维为64通道,这个时候获得的就是26*26*64,然后通过一个特征重排(隔行隔列采样,这样获得4个13*13*64的特征图,把这四个特征图concat起来得到13*13*256)获得13*13*256的特征图,然后再同上一层的13*13*1024一起concat起来作为下一层的输入。这个方法可以获得1%的提升。
尺度训练,因为作者原来是448,后来又变成了416,所以作者就想,希望整个网络能够适应多个尺度的变化,强迫网络去学习这些参数,所以作者这里采取了一种策略就是没迭代10轮就改变一个网络的输入大小,由于使用了下采样参数是32,所以不同的尺寸大小也选择为32的倍数{320,352 …..608},最小320*320,最大608*608。
最后作者在这篇论文中提出了联合训练分类和检测数据集的机制,使得可以分到超过9000个类别。训练的时候,作者混合来自检测和分类数据集的图像。当网络看到标记为检测的图像时,就基于完整的YOLOv2损失函数(分类+框)进行反向传播。当它看到一个分类图像时,就从该架构的分类特定部分反向传播损失。
这个就需要解决一个关键点,检测的数据集通常是更广泛的抽象,比如狗,猫,但是分类却有更细致的分类,比如狗有很多种狗,猫也有很多种猫,因此需要整合这两者的数据。作者在这里从WordNet(一种认知语言词典)当中提取出来一个WordTree ,具体操作就是:首先找出ImageNet中一个类别的词汇在WordNet中到根节点的路径,如果有很多条路径到达根节点,那么选择最短的那一条。遍历ImageNet,获得WordTree
这是一个视觉概念的分层模型,获得了这棵树以后,对于每一个节点的概率就根据链式法则去计算。
获得了一个树之后,对于数据我们就需要重新进行一下标注,也就是标签扩展,因为Norfolk terrier现在也是terrier又是hunting dog,也是dog,也是animal。所以原来的标签是[0,0,0,0,0,0,0,1,0,0]可能现在就变为了[0,0,0,1,0,0,1,1,1,1]。这个时候可以在共同的下义词上执行多次softmax操作。
看到一个检测图像时,正常的反向传播损失。对于分类损失,仅在等于或高于标签对应的层反向传播损失。当网络输入的是分类图像的时候, 只需找到预测该类别最高概率的边界框,然后计算其预测树上的损失。这里假设预测边界框与真实标签的IOU值至少为0.3,并且基于这个假设反向传播目标损失。
3.YOLO V3
这是最新的一篇,前两天刚刚放出来,简直是快到没朋友,作者文风也很跳脱。相比于YOLO9000,改进的地方如下:
每个框会预测中心点坐标和长度宽度以及该框内有目标的置信度(通过逻辑回归产生),引入了一个Faster RCNN的阈值,如果IOU小于0.5,就不考虑,在大于0.5的所有边框里面选一个先验最好(预测的IOU最大)的框与真是边框计算损失(注意:也就是说每个网格最多只有一个边框与真实的IOU进行计算误差,如果当前网格所有边框的预测值都小于0.5,那么这个网格就不会与真实边框计算IOU损失。)
用独立的逻辑分类器代替了softmax函数,因为作者发现用softmax并不能提升性能,同时考虑到了在某些多标签问题上,softmax限制每个框只有一个类别,不符合实际情况。
引入了一个新的基础网络,这个网络仿照着ResNet对Darknet-19的改进。
最后作者引入了FPN网络,来对多尺度预测。具体的可以看FPN网络。这篇文章严格来说应该是一篇技术报告,因为作者写的非常之随意,不过这种文风还是非常之有趣的。
4.SSD
SSD是ECCV2016年的一篇文章,这篇文章也是one stage方法的,当时这篇文章精度比YOLO更高,但是速度比两阶段的都要慢,所以这篇文章引起了极大的关注。作者在SSD里面指定了不同的长宽比,面积(在YOLO里面是没有的,YOLOV2里面通过聚类产生了一些框的尺寸)同时作者做了多尺度的预测(其实也就是对不同大小的特征图做检测),其实这些思路在之前都已经介绍过了。
SSD300用的是VGG作为基础架构,在降采样的时候,每一层特征图都会做预测。SSD的设计创新点如下:
1.用多尺度的特征图来检测,这样做可以对小目标物体有一定的改善,在每个尺度都会做出预测。
2.去掉了全连接层,直接用3*3的卷积去对特征图山的每一个点产生k个预测框,每个框会有4个坐标输出(这里输出的是预先设定的bounding box与真实的bounding box的偏移量)以及21个类别输出,这样每个点有k*(21+4)个输出,所以卷积的滤波器数目p=k*(21+4)。
3.设置先验边框。由不同的scale 和 ratio 生成,k 个 default boxes,特征图的每个点都会产生k个。现在假定输入为w*h,给定n个不同的大小s,可以获得ws*hs大小的框,m个不同的比例,可以获得大小的框。不同层的感知野不一样,所以对于不同层上的尺寸选择也不一样,作者在论文中给出了一个选择公式:
这里的这里m表示特征图的个数,但是由于conv4_3是单独设置的,所以取5。那么我们可以计算出每一层的尺度分别为0.2,0.37,0.54,0.71,0.88,再分别乘以300,就可以得到每一层的具体预测尺寸为:30(conv4_3),60,111,162,213,264。作者在论文中每个尺度设定了一些比例,分别是{1,2,3,1/2,1/3}作者在这里额外增加了一个框的尺寸s_k^'=√(s_k s_(k+1) ),但是最后一层没有下一层了,所以最后一层在这个尺度上的设置为315。每个box的中心选择这里是在每个点的坐标上偏移了0.5, ,其中表示k个特征图的大小.每个点会生成6个box,在多个层上面做预测,这样看出SSD其实是一个密集采样的算法。
4.匹配策略:这里和faster RCNN类似。每个ground truth先与其IOU值最大的框匹配,然后只要预测框与一个ground truth的IOU值大于0.5,都进行匹配。
5.损失函数:对于多任务而言,损失函数永远是一个不可忽视的问题,两个任务,所以还是分成两个部分,分类损失函数和定位损失函数。
这里和Faster RCNN的损失函数设置一样的,softmax损失和L1平滑损失。
6负难例挖掘:先将每一个物体位置上对应 predictions(default boxes)是背景的 boxes 进行排序,按照 boxes 的 confidence的大小。 选择最高的几个,保证最后正负比例在 1:3。(参考:小白将:目标检测|SSD原理与实现)
5.DSSD
这是对SSD的一个改进,SSD的作者也是本文的作者之一。这篇文章主要是为了解决多尺度融合的问题,原先的SSD,只是在不同的特征图上面进行了预测,但是没有充分考虑到上下文的信息,FPN里面也提到过。这篇论文主要有两个贡献:1.使用了ResNet替代了VGG,提升了特征的提取能力,同时引入预测模块,提升了准确度;2.引入转置卷积,将上下信息融合到一起,提升了精度。
作者将首先将VGG直接替换为ResNet,发现精度反而还下降了一点点,从77.5降到了76.4。这表面如果只是简单更换网络是不能提升精度的,作者根据论文《A unified multiscale deep convolutional neural network for fast object detection》中提到的改善任务的每个子网络,有助于提升精度,于是作者在每个预测之间,加了一个残差模块。
上图是作者提出的几种预测模块,每个模块的测试结果如下所示:
为了更好的融合上下文信息,作者这里采取了转置卷积操作来获得一个与之前特征图对应的高分辨率的特征图,形成了编码-解码的网络结构。转置卷积这个不是本文提出来的而是在分割网络里面用的,最早是在ZFNet里面提出来的,要想理解转置卷积的过程,需要了解卷积在底层是如何实现的。因为在底层实现的时候,通常会把卷积转化成SGEMM进行加速,这就需要对输入图片进行滑动窗展开。(注意:caffe里面不是这样实现的,caffe的实现不是将整张图转换为一个向量)
对于矩阵运算y=Cx,首先将图片展开为向量的形式,这样就有输入图片的大小为16*1,为了加速运算,这里会将卷积核根据滑动窗进行展开,对于输出的特征图(0,0)上面的点,只是原图位置中(0,0),(0,1),(0,2),(1,0),(1,1,),(1,2),(2,0),(2,1),(2,2)9个点的加权和,那么对应矩阵的第一行,应该只有对应位置有值,其余位置都是0,于是卷积的矩阵可以写成如下形式:
对于梯度反向传播公式,则有:
现在将Loss对y的导看做是输入,Loss对x的导看做输出,那么就是输入梯度与输出梯度之间的权值。我们假定一个16*1的经过4*16的矩阵,得到4*1,同理,将4*1的矩阵,经过一个4*16转置之后,可以获得16*1。
附:Caffe内部的实现机制如下(参考:余俊:FCN学习:Semantic Segmentation)
对于矩阵运算操作:A*B=C
在caffe内部的操作如下:
这就是im2col过程,这里的feature matrix对应于上图中的矩阵B的转置,k即是卷积核的尺寸,C为输入的维度,矩阵B中的K=C x k x k,当然N就等于H' x W'了,H',W'对应于输出的高和宽,显然H'=(H-k+2*pad)/stride+1,W'=(W-k+2*pad)/stride+1(这里向下取整),接下来我们看看A矩阵:
A矩阵对应于filter matrix,Cout是输出的维度,亦即卷积核的个数,K= C x k x k.
所以在caffe中,先调用im2col将filters和input转换为对应filter matrix(A)和feature matrix(B'),然后再用filter matrix乘以feature matrix的转置,就得到了C矩阵,亦即输出矩阵,再将C矩阵通过col2im转换为对应的feature
map,这就是caffe中完整的卷积的前向传播过程。
通过转置卷积获得了一个与之对应的高分辨率特征图,然后将两者合并起来。
蓝色的是特征图,红色的是经过转置卷积获得的尺度相同的更高级特征图,具体的办法如下图所示:
作者在论文中也提到,在最后融合的时候,试过加法和乘法,乘法会好一些,大概0.2,但是预测速度会有所降低。
6.RetinaNet(Focal Loss)
这也是何凯明提出来的,这篇论文主要是提出了 Focal
Loss函数,用来消除样本比例不均衡问题。作者分析了,当前精度表现好的网络都是two-stage的,而one-stage的网络主要优势在于其速度会非常快。为什么one-stage不如two-stage的精度高呢?作者通过实验发现主要是因为two-stage的网络通过生成候选区域,消除了大量的背景,而one-stage的网络却要在大量的背景当中找到少量的目标信息,这样负例过多,导致梯度回传的时候,可能会淹没掉正例信息,这导致了模型优化的方向,有时候可能不是我们预期的方向。
OHEM是通常采用的一种方法,它通过对loss排序,选出loss最大的样本来进行训练,这样就能保证训练的区域都是比较难分的区域,但是它又把易于区分的样本给忽视掉了。
本文提出的Focal Loss就是为了解决one stage的精度问题。这个损失函数是在交叉熵损失函数的基础上进行的改进,它降低了容易分类样本的权重,让整个优化方向更加的专注于难分类的样本。
标准的交叉熵损失函数如下:
这里将p写成以下格式:
果引入一个α,那么这个α就可以对不同的样本产生的loss的权重进行控制:
这样就解决了背景权重过大的问题,但是它并没有区分难分的样本和容易分的样本之间的差异,于是,作者引入了一个γ参数,作为对难分和易分样本之间差异的衡量:
从这个函数就可以看出对于好分的样本,loss较小,对于难分的样本,loss较大
最后两α和γ一结合就得到了本文提出的新损失函数focal loss:
从函数表达形式可以看出:如果p_t很小, 也就是与原来标准的交叉熵损失函数没有什么大的变化,若p_t较大,整体就趋于0,对loss贡献就比较小(也就是容易分类的共享比较小)。最后作者在这篇论文里面用了一个基于ResNet的FPN的网络结构来验证了分类这个损失函数的有效性,这里α=0.25和γ=2效果比较好。
上述涉及论文连接,感兴趣的同学请自行下载
.链接: https://pan.baidu.com/s/1GTWY5LQvDSGlbZmxjxwSmg 密码: jti6
来源:知乎 -方宇,知乎专栏:slam 学习之旅,专知已获得作者授权。
https://zhuanlan.zhihu.com/p/35724768
https://zhuanlan.zhihu.com/p/35731743
-END-
专 · 知
人工智能领域主题知识资料查看与加入专知人工智能服务群:
【专知AI服务计划】专知AI知识技术服务会员群加入与人工智能领域26个主题知识资料全集获取
点击上面图片加入会员
请PC登录www.zhuanzhi.ai或者点击阅读原文,注册登录专知,获取更多AI知识资料!
请扫一扫如下二维码关注我们的公众号,获取人工智能的专业知识!
点击“阅读原文”,使用专知