工作需要学习一下该文章,顺便做个小笔记。
paper链接
github code link
论文提供代码链接
一篇写的很详细的blog
论文阅读
RPN是一种全卷积网络,同时预测目标的边界和目标在没个位置的目标可信度得分。解决了region Proposal的计算瓶颈。传统的SS(selective search)方法比较耗时,占据了目标检测的大部分时间。本文使用一个深度网络计算Proposals,得出一个优雅而有效的解决方法,使得Proposals的计算几乎不占用目标检测网络的时间。提出的RPN网络与经典的目标检测网络共享卷积层。通过在测试时共享卷积层,计算region Proposal的边际成本变得很小。
我们发现基于region的目标检测网络的卷积feature map 也可以用到生产region Proposals中。因此在卷积特征的顶层,我们通过使用额外的两层卷积层来构建RPNs:其中一个是把卷积特征平面上的每个位置编码为一个短的特征向量(maybe 256);另一个在每一个卷积特征层的每个位置输出一个“是目标的得分”,并对k(maybe 9)个region Proposal的边界和尺度和位置的回归。
我么的RPN网络是一种全卷积网络(FCN,简单的来说,FCN与CNN的区域在把于CNN最后的全连接层换成卷积层,输出的是一张已经Label好的图片。FCN),可以使用端到端的方式训练用于产生目标检测Proposals。为了把我们的RPNs 和FAST Rcnn网络统一到一个框架中,我们提出了一个训练框架:交替训练优调region Proposal任务和目标检测任务。这种方法可以很快收敛并且可以生成一个共享卷积特征的统一网络框架。
使用该框架的网络检测精度浩宇fast rcnn,而且用于计算啊region Proposal的时间只有10ms。使用VGG,可以达到5fps。
RPN
RPN输入一个任意大小的图像,输出一组矩形目标候选区,每个候选区有一个是目标或者背景的分数(“Objectness” measures membership to a set of object classes vs. background)。我们吧这个过程使用FCN(fully convolution network)建模。因为我们的最终目标是与Fast rcnn目标检测网共用部分计算,我们设定这两个net共享部分卷积层。我们使用了ZFnet,共享5层卷积层,VGG共享13层卷积层。
为了生产region Proposals,我们在最后一层共享的卷积层输出的feature map 上滑动一个小得网络
,这个小的网络把输入的feature map全连接到一个nXn的空间窗口。每个小的滑动窗口映射到一个低维的向量上(256dfor ZF,512 for VGG)。这个向量输入到两个(并列)兄弟全连接网络层:一个框回归层(reg)和一个框分类层(cls)。本文中我们设定n=3,注意到输入图像上的有效映射场较大。这个小网络如下图所示:
因为这个小网络是滑动窗口风格,全连接层在整个空间上是共享的。这种架构自然地使用一个nXn的卷积层跟着两个1X1的卷积层(cls,reg)。Relu在nXn卷积层之后。
转换不变anchors
在每个滑动窗口位置,我们同时预测k个候选区域,我们的reg层需要4k个输出以编码k个框的坐标。我们的cls层需要输出2k个参数来估计每个Proposal的是目标/不是目标的概率。k个Proposals通过k个参考框(称之为Anchor)设定。每个anchor在所讨论的滑动窗口中心,并通过尺度和纵横比想关联。我们使用三种尺度和3中纵横比,即9个anchors 在每个滑动窗口。因此对于一个W*H的特征图,共有W*H*K个anchors。我们的方法的一个特点是在anchors和与anchors相关的计算中都保持转换不变性。不变性与MultiBox方法相比减少了参数的数量,减小了过拟合的风险。
学习RP的损失函数(loss func)
为了训练RPNs,我们对每个anchor设定了一个二分类的标签(是/不是目标)。我们设置两种anchors为正样本:(i) the anchor/anchors with the highest Intersectionover-Union (IoU) overlap with a ground-truth box,与Groud-truth-box 有最大的IOU;(ii) an anchor that has an IoU overlap higher
than 0.7 with any ground-truth box,IOU大于0.7的Anchor。因此一个Ground-truth box可能对应多个正样本Anchors。如果一个Anchor的对于任何ground-truth box的IOU都小于0.3,设置为负样本。其他样本不在训练中使用。
根据以上定义,我们的最小化目标函数按照Fast RCNN中的多任务损失函数:
i代表anchor的索引,pi为Anchor i是目标的概率,anchor是目标则pi*为1,否则为0;ti是表示预测边界框的4个参数化坐标的矢量,ti*是与正样本Anchor相关联的Ground-truth框坐标向量;分类损失函数Lcls is log loss over two classes (object vs. not object)(???);回归损失函数为R(ti-ti*),其中R是具有鲁棒性的损失函数(maybe smooth L1)(???);pi*Lreg项表示只有当为正anchor该项被激活。网络的输出包含pi和ti,这两项通过Ncls和Nerg归一化,通过lamda超参平衡。对于回归,我们采用4坐标的参数化方法:
xywh分别代表中心坐标和宽高;x,xa,x*分别代表预测的box,Anchor box和Ground-truthbox。这可以当做是从Anchor box到最近的GT box回归。
我们的bounding-box回归不同于之前的基于feature map的方法。原来的方法对来自任意大小区域的特征进行边界回归,并且所有区域大小共享回归权重。在我们的公式中,用于回归的特征在特征图上具有相同的空间大小(n×n)。为了解决不同大小的问题,我们学习了k组边界回归值。每个回归负责一个比例和一个纵横比,k个回归不共享权重。因此,即使特征具有固定的尺寸/尺度,仍然可以预测各种尺寸的boxes.
优化
RPN是FCN的自然应用,可以使用端到端的训练方法,使用后向传播和随机梯度下降法训练。我们使用以图像为中心的样本策略训练网络。每个mini-batch都是由一个单一的图像产生的,它包含许多正负的anchors。可以对所有anchor的损失函数进行优化,但是它们将偏向负向样本,因为负样本占大多数。相反,我们在图像中随机抽取256个锚点来计算小批量的损失函数,其中采样的正和负锚点的比率为1:1。如果图像中少于128个正样本,则使用负样本填充小批量。我们通过从具有标准偏差0.01的零均值高斯分布绘制权重来随机初始化所有新层(RPN)。所有其他层(共享转换层)通过预先训练ImageNet分类的模型来初始化。我们tune ZF网络的所有层,VGG网络优调conv3 1及以上层,以节省内存。在PASCAL数据集上,对于60k小批量,我们使用0.001的学习率,接下来的20k小批量的学习率为0.0001。我们也使用0.9的动量,重量衰减为0.0005
RPN和目标检测共享卷积特征
目标检测使用Fast-rcnn,RPN和Fast RCNN独立训练,使用不同的方式修改卷积层。因此,我们需要开发一种允许在两个网络之间共享conv层的技术,而不是学习两个单独的网络。原因是快速R-CNN训练取决于固定object Proposal,并且不太明确,学习快速R-CNN同时改变Proposal机制是否会收敛。这种联合优化是未来工作的一个有趣的问题,我们开发了一种务实的4步训练算法,通过交替优化来学习共享特征。
第一步:训练上述的RPN,该网络使用ImageNet预先训练的模型进行初始化,并针对RP任务进行端到端的微调;
第二步:我们使用第一步RPN生成的提案,通过Fast R-CNN训练单独的检测网络;
第三步:我们使用检测器网络来初始化RPN训练,但是我们固定共享cov层,并且仅微调RPN的层;
第四步:最后,保持共享的cov层固定,我们微调fast R-CNN的fc层。 因此,两个网络共享相同的cov层并形成统一的网络。
应用细节
使用相同大小的图片训练和测试RPN和目标检测而网络。
针对Anchors,三种尺度:128,256,512,三种纵横比:1:1,;1:2,2:1;我们注意到,我们的算法允许在预测大的RP时使用比底层接受域大的anchor框。这样的预测并不是不可能的 - 如果只有对象的中间是可见的,那么还可以粗略地推断对象的范围。我们的解决方案不需要多尺度功能或多尺度滑动窗口来预测大型区域,从而节省大量的运行时间。跨图像边界的anchor box需要小心处理。在训练过程中,我们忽视所有的跨境Anchors,以免造成损失。然而,在测试期间,我们仍然将全卷积RPN应用于整个图像。 这可能会产生跨边界rp框,我们将剪辑到图像边界(???)。
一些RPN Proposal相互重叠,为了减少冗余,我们根据其cls分数对提案区域采用非最大抑制(NMS)。我们固定IoU为0.7作为NMS的阈值,这使得我们每个图像大约有2k个提RPs。正如我们将展示的,NMS不会损害最终的检测精度,而是大大减少了RP数量。在NMS之后,我们使用排名前N位的RPs区进行检测。 以下,我们使用2k RPNRP训练Fast R-CNN,但在测试时评估不同数量的Proposal。
paper实验结果(移步论文)
mAP:目标检测中衡量识别精度的指标是mAP(mean average precision)。多个类别物体检测中,每一个类别都可以根据recall和precision绘制一条曲线,AP就是该曲线下的面积,mAP是多个类别AP的平均值。目标检测评价指标解释
代码阅读
实验测试
按照github里的说明一步一步执行。
- 问题1:
AttributeError: ‘dict’ object has no attribute ‘iteritems
Python3.5中:iteritems变为items
把setup.py line 53 修改一下即可。
- 问题2:
cudnn.hpp:108:70: error: too few arguments to function ‘cudnnStatus_t cudnnSetConvolution2dDescriptor(cudnnConvolutionDescriptor_t, int, int, int, int, int, int, cudnnConvolutionMode_t, cudnnDataType_t)’
用新版的caffe替换文件。
1.cp caffe里的cudnn.hpp ./include/caffe/util/cudnn.hpp
2.将./src/caffe/layer里所有以cudnn开头的文件,如cudnn_xxx_layer.cu,cudnn_xxx_layer.cpp
都替换成最新版的caffe里的相应的同名文件。
- 问题3:
error: ‘activ_desc_’ was not declared in this scope
cudnn::createActivationDescriptor(&activ_desc_, CUDNN_ACTIVATION_RELU);
解决方法:将./include/caffe/layers的,所有以cudnn开头的文件,例如cudnn_conv_layer.hpp,cudnn_lcn_laye.hpp
运行./tools/demo.py 提示:No module named ‘easydict’
解决方法:
为了确保正确install ,我把python2,python3,和anconda3 的python全部安装一次,暴力。
这个东西已使我疯狂,凌晨两点半
libopencv_imgcodecs.so:对‘png_create_read_struct@PNG16_0’未定义的引用
解决:cd /usr/lib/x86_64-linux-gnu
sudo ln -s ~/anaconda/lib/libpng16.so.16 libpng16.so.16
sudo ldconfig
问题4:src/caffe/test/test_smooth_L1_loss_layer.cpp:11:35: fatal error: caffe/vision_layers.hpp: No such file or directory
then simply removed src/caffe/test/test_smooth_L1_loss_layer.cpp file from running by renaming it to test_smooth_L1_loss_layer.cpp.orig.
This issue should be the only problem in make testand in make runtest. If both pass, you can expect the demo to run smoothly on your GPU.
问题5:这个问题困扰两天,极度崩溃。
ImportError: /home/zero/Documents/caffe-master/python/caffe/_caffe.so:undefined symbol:
_ZN5boost6python6detail11init_moduleER11PyModuleDefPFvvE
解决方法:http://blog.youkuaiyun.com/donatellobzero/article/details/51304162
这个错误的意思是,boost版本不匹配。
boost.python是啥东西呢?我理解的是boost.python是一个类似翻译器的东西,所以如果你是python3的程序,却用了python2的翻译器,那语法、定义等等各方面必然会有冲突。我记得在某篇帖子中看到过,str、int等等的定义,在两者中是不同的,所以有时会有报错信息说找不到str啦int啦之类。当时没有把没一个错误都记下来。
然后,如果我们去makefile中查找这个变量PYTHON_LIBRARIES,会发现有这么一句:
PYTHON_LIBRARIES := boost_python-py35 python3.5m
问题6:ModuleNotFoundError: No module named ‘google’
解决:conda install protobuf
问题7:ModuleNotFoundError: No module named ‘cPickle’
解决:python2有cPickle,但是在python3下,是没有cPickle的;
解决办法:将cPickle改为pickle即可
其他是python2,python3的版本问题。
问题8:Demo for data/demo/000456.jpg
F1010 01:35:33.146603 9647 syncedmem.cpp:56] Check failed: error == cudaSuccess (2 vs. 0) out of memory
* Check failure stack trace: *
小本的显存不足。。。
修改demo.py,运行ZF 模型。
终于成功了,这么小的事情,过程却如此艰辛,差距啊。