目标检测算法:Fast-RCNN论文解读
前言
其实网上已经有很多很好的解读各种论文的文章了,但是我决定自己也写一写,当然,我的主要目的就是帮助自己梳理、深入理解论文,因为写文章,你必须把你所写的东西表达清楚而正确,我认为这是一种很好的锻炼,当然如果可以帮助到网友,也是很开心的事情。
说明
如果有笔误或者写错误的地方请指出(勿喷),如果你有更好的见解也可以提出,我也会认真学习。
原始论文地址
点击这里,或者复制链接
https://arxiv.org/abs/1504.08083
目录结构
文章目录
1. 文章内容概述:
作者受到SSP-Net的启发,在15年提出了Fast-RCNN,其在保证mAP的情况下,大幅度提高了运行效率。
2. SSP-Net:
我没有单独写一篇博客来说SSP-Net,主要我觉得内容可能有点少,因为SSP-Net中最重要的知识点就是空间金字塔池化(Spatial Pyramid Pooling)。
2.1 思路来源:
我们知道,RCNN一个重要的缺点就对于一张图片,需要对2000个区域建议框进行CNN处理,这无疑是耗时的。另外,需要将区域建议框包围的图像缩放至指定大小,这无疑会影响图像的精度(如下图所示,SSP论文原图)。
因此,研究者人们思考是否有想出办法避免上述的两种情况。
2.2 措施1:ROI映射
为了解决第一个问题,即需要将2000个建议框都进行CNN处理,作者采取了ROI映射的方法。
- 首先,对于整张图片生成2000个建议框。
- 其次,将整张图片作为输入,传给CNN架构。
- 而CNN架构最后一个卷积层输出一个特征图。
- 然后,将原来的2000个建议框映射到特征图上,这样就不需要对每个建议框重新做CNN操作了
问题:原始建议框如何映射到特征图上正确位置?
举个例子,假设所有的卷积层都不改变尺寸大小,只改变通道数,而所有的池化层都减半。那么,假设原始图像尺寸为256*256,并且经历了4个池化层,那么输出的特征图尺寸为16*16。
假设,原始图像上一个建议框的左上角坐标为(Xmin,Ymin),右下角坐标为(Xmax,Ymax),那么映射到特征的坐标应该为:
左上角:
x = Xmin / 16
y = Ymin / 16
右上角:
x = Xmax / 16
y = Ymax / 16
2.3 措施2:空间金字塔池化
为了解决第二个问题,即需要固定输入图像尺寸的问题。作者采取了空间金字塔池化的操作,这个方法的作用是对于任意输入,都可以产生固定尺寸大小的输出。
在SSP-Net论文中的图片如下图所示:
上图你可以说它是三级空间金字塔池化,其中的256-d是CNN最后卷积层输出的维度为256维。之所以说它是三级,是因为它有三个池化,即上图从左到右的16*256-d、4*256-d、256-d。最后的输出即将三者拼接一起即可,这个长度是固定的。
怎么理解它这个池化操作呢?其实很简单,首先,假设我们的金字塔池化为三级,且池化大小分别为图中的4*4、2*2、1*1(这样就固定了输出长度),并且假设特征图大小为16*16。
那么以4*4为例,其一共16个单元格,那么每个单元格就取原特征图一块4*4区域的最大值。以2*2为例,一共4个单元格,那么每个单元格就取原特征图一块8*8区域的最大值。
这样,可以保证无论什么大小的特征图作为输入,SSP产生的输出都是一样的,即一个4*4大小,一个2*2大小,一个1*1大小。
3. Fast-RCNN流程:
论文的原图如下:
也可以看看网上的图片,来自参考资料2:
简单说一下流程:
- 首先,对于输入的图像生成2000个候选框
- 然后,将整张图片作为输入传给CNN架构,而CNN架构最后一个卷积层输出一张特征图
- 接着,将候选框映射到特征图上,并将候选框包围的值送给ROI Pooling,ROI Pooling输出一段固定长度的输出
- 然后,将ROI Pooling的输出传给两个全连接层,然后再分别进行分类和回归操作
4. ROI Pooling:
ROI Pooling操作其实就是一种特殊的空间金字塔池化操作,只是这里没有多级金字塔池化,只有一级。
原理如下(如果上面SSP没有理解好,这里可以再次参考理解):将h*w的ROI划分W*H个网络,其一个网格的大小为(h/H,w/W),而该网格的值就是该网格大小对应的ROI中的最大值(池化操作)。其中W*H就是SSP中的金字塔池化固定的输出大小,h*w就是特征图大小。
举个例子,见下图:
5. 联合优化(损失函数):
Fast-RCNN一个变化点就在于联合优化分类和回归,而不像RCNN一样还需要分开训练SVM、LR等内容。
通过Fast-RCNN流程图,我们可以看到其最后有两个兄弟输出,即一个分类输出和一个回归输出,前者输出离散概率分布
,后者输出边界框偏移量
,其中K表示一共的类别数(不包含背景),k为K中的一个类别。
而对于每一个ROI,都有其对应的真实类别u和真实的边界框v。那么联合损失可以这么表示:
其中,Lcls表示分类的损失值,Lloc表示回归定位的损失值,λ是权重参数,一般取1。
而,对于u值,我们一般默认0表示背景,而[u>=1]表示只有当满足u>=1时,该值等于1,否则等于0。这表示,负样本(即根本不包含对象的ROI)不参与回归损失计算。
而,分类损失还是常用的对数损失函数,pu表示预测为真实类别的概率:
回归的损失采取修正平滑的L1损失(L1损失就是MAE,没错,就是你想的绝对值之差):
其中,修正后的L1,即smooth L1表达式为:
为什么不采取L2损失或者修正的L2损失?
因为L2损失对离群点敏感,比如同样的差值5(一般的差值都为0.8或者1,这里5表示为离群点的差值),L1损失得出的结果时5,而L2损失却是25。
因此不采取L2损失。
6. 截断式奇异值分解:
作者发现,由于Fast-RCNN对于每一个ROI都要做全连接运算,因此在全连接的花费时间较多(另外回归和分类都交给全连接也是一个因素),如下图左所示,故考虑使用SVD来加速全连接的运算,如下图右所示:
具体SVD怎么实现的,我简单说一下(对于SVD原理要求很低)。
我们假设全连接层的输入为x,输出为y,全连接所有的权值构成的矩阵为W(u,v)。
那么,我们正常计算,y=Wx(加粗表示为向量),那么复杂度为u*v(只算乘法次数)。如果你不理解上面这个复杂度怎么计算的,我画个图举个列子说明:
使用SVD分解权值矩阵,可以表示为:
而SVD分解后,U的shape为u*u,Σ的shape为u*v,V的shape为v*v。其中,Σ是对角矩阵,为了满足尺寸u*v,其对角值由奇异值(可以由特征值计算得来)和0构成。
而,我们直接使用它的t个奇异值(不为0的部分)代替(这就是截断式的由来),那么整个表达式可以改写为:
那么,此时来计算全连接输出,表达式为:
复杂度为u*t+v*t+t,怎么理解这个复杂度。首先,对角矩阵Σ和V相乘(复杂度为t),再与x相乘(复杂度为t*v),得到的结果(shape为t*1)再与U相乘(复杂度为u*t),故,总体复杂度为u*t+v*t+t。(我看别人的博客复杂度没有最后的加t,我不知道怎么得来的,知道的朋友可以留言告知我一声)
当u和v值很大的时候(t值一般很小),这样的分解可以大大减少计算量,这一点上面的图片就已经证明了。
7. 作者探索的几个问题:
作者在实验时还探索了几个小问题:
- 单尺度图片和多尺度图片优劣比较
- 发现多尺度mAP高一点,但是耗时较多
- 单尺度快,而mAP也不低
- 训练数据是否越多越好?
- 作者将训练集扩大两倍,mAP略有提升,从66.9%提升至70%左右
- softmax比SVM分类好吗?
- 作者认为此时确实是Softmax好,因为Softmax引起了类的竞争(即不同的类都希望在评价时得到好的结果,于是开始竞争)
- 更多的区域建议框好吗?
- 并不是,作者发现过多的建议框反倒降低了精度值
8. 总结:
Fast-RCNN相比于之前的算法已经很优秀了。其提出了联合优化、SVD加速训练等思路,为后续的发展提供了很好的思路(比如后面大部分算法优化都是联合优化)。
另外,从Fast-RCNN我们也不难猜测后面进一步的优化路线,比如可以着手于区域建议框的获取方法,比如如何让模型变为真正的端到端的(即给一张图片,它直接给我一个结果)。而后面的Faster-RCNN、YOLO等算法也是这么去修改的。
9. 参考资料:
1. https://blog.csdn.net/qq_36926037/article/details/105984501
2. https://blog.csdn.net/abc13526222160/article/details/90344816
3. https://zhuanlan.zhihu.com/p/139050020
4. 论文原文
5. SVD分解:https://zhuanlan.zhihu.com/p/52890135