目标检测——Faster R-CNN 详解、Pytorch搭建、训练自己的数据集

转载请注明出处!

目标检测在CV里面占很大一席之地了,而目标检测当红网络肯定少不了RCNN家族。在自己的数据集上使用了Faster RCNN,效果确实不错。

理解Faster RCNN还需要相应地看Fast RCNN和RCNN,因为有的公式在前2篇出现过的会略过,就不太明白。

ok进入正题~

1 Faster RCNN论文详解

Faster RCNN网络就是:

1)  卷积网络去掉全连接层的Feature Map;

2)  Feature Map——>RPN生成region proposal;

3)  region proposal+Feature Map——>ROI pooling 生成proposal feature maps;

4)   proposal feature maps经过全连接层后分类+bounding box regression获得最终的检测框的精确定位以及类别。

这可能会有疑问(1)为什么要生成Feature Map而不是直接输入原始图像?(2) RPN是什么,生成的region proposal和proposal feature maps有什么区别? (3)为什么还要再经过bounding box regression?

问题(1),回想曾经行人检测是hog+SVM,选定一些窗口,通过滑窗来提取区域,并提取区域的HOG特征,输入到SVM判断是否行人.而Faster RCNN就是利用神经网络提特征.

1.1 RPN(region proposal network)

RPN的作用是生成region proposal,受到空间金字塔的启发。再回到行人检测的问题。人因为远近在图像中表现大小不一样,如果用同一个(w,h)的窗口去滑动,结果可能会漏掉小的人。所以,之后人们会用多个(w,h)的窗口去检测,并且选取响应最大的那个(w,h)。多个(w,h)具体多少个?具体w和h是多少?RPN确定了具体多少个,具体w和h是多少。

âè¡äººæ£æµâçå¾çæç´¢ç»æ

RPN取代了滑窗的形式(也可以理解为窗口的步长是1个像素吧),借鉴了FCN的思想,变成了pixel-2pixel预测,只不过FCN对于每个像素输出是N个类别的概率值,而RPN输出的就是region proposal。上述说RPN确定了具体多少个窗口和具体w和h是多少。这个窗口呢,他们叫Anchors。文献中这个Anchors的数量k=9,分别是3种尺寸size、w和h比分别为{1:1  1:2  2:1}。顺便说一句,不管你输入的图像大小是多少,最后输入进网络都会reshape为统一尺寸,比如800x600。

所以RPN就相当于,用9个窗口,步长为1个像素地去检测行人。每个像素呢,会有9个判断(同时进行,所以很节约时间),以它为中心的9个anchors最有可能存在的位置(每个点初始化的9个anchors是一样的,经过学习,每个点的9个anchors位置都会改变)。

RPN它不仅输出了region proposal,还要分个类,不过是二分类,背景还是目标。也就是它额外加了个预测的分支。

比如使用VGG网络后最后一层卷积层的输出是256个224x224的feature maps,输入RPN后变成了 6*k个224x224的通道。(region proposal是4k,分类是2k,因为anchors需要4个变量表示,左上角x、y和w,h,分类需要2个输出,分别是是背景的概率和是目标的概率)

再看看reg和cls不要想复杂了,这两个是并行的,reg使用的是bounding box回归,cls就是二分类!结合图和代码,可以看一下reg和cls具体如何操作的。

feature_maps --> 3x3 卷积+relu  后,

输入到cls:

 -->1x1卷积+relu-->reshape -->softmax-->reshpe-->output  (label prediction)

第一个reshape :[batch,channels,w,h]-->[batch,2,w*channels/2,h]。这里channels等于2(bg/fg) * 9 (anchors)

第二个reshape:[batch,channels,w,h]-->[batch,18,w*channels/18,h]。

为什么要reshape:要预测的话,输入channels表示你要预测的类别有channels个,比如二分类,输入到softmax里面必须channels等于2。所以要把channels = 2*9变成 2.

再看看bounding box reg,feature_maps --> 3x3 卷积后,

输入到reg:

-->1x1卷积+relu-->bounding box reg->output  (region proposals)

1.2 bounding box regression

写在前面:BB回归是特征图的函数,而不是位置的函数!即通过前面的卷积提取特征,将这些特征与偏移量(表示anchor到GT的所要经历的表示平移+缩放的4个参数)的映射关系就是BB回归要学习的东西。

这个问题在RCNN文章中详细介绍了。比如图中,绿色的框框是groundtruth,而红色的框框为rpn中某个anchor。如何让anchor逼近groundtruth呢?

平移+缩放!

假设红色的框框是A,用左上角坐标和长、宽描述,则A={Ax, Ay, Aw, Ah},绿色的groundtruth是G,G={Gx, Gy, Gw, Gh}。要找到一种映射F,是的F(A)=G',而G'尽量等于G。

1 平移:

G'x = Ax + △x             G'y = Ay + △y

2 缩放

 G'w = Aw *△w             G'h = G'h*△h

△x、△y、△w 和△h可以用A的函数来表示(因为要学习这四个变量,所以必须要写成A的函数形式)

G'x = Aw \times d_{x}(A) +Ax

G'y = Ah \times d_{y}( A) +Ay

G'w = Aw \times exp(d_{w}( A))

G'h = Ah \times exp(d_{h}( A))

要学习的就是  这四个变换dx,dy,dw和dh。

为什么有个exp,这是为了让缩放因子大于0。

由于输入RPN的是feature map,在feature map每个像素都有k个anchor,这k个anchor会有相应的4对变换d(dx,dy,dw和dh),每个anchor 都有相应的偏移量作为标准:

x,y,w,h是预测的框框,xa,ya,wa,ha是第i个像素的某个anchor,x*,y*,w*和h*是groundtruth的框框。t实际中就是d,而偏移量d是feature map的特征向量的函数:

d_{*} = \omega_{*}^{T} \times \Phi (P)

\Phi (Pi)是feature maps第i个像素的第k个anchor,则\Phi (Pi):k_ancho_w*k_ancho_h*channels的值。如下图:

纠正:在RPN阶段,\Phi (Pi)是整个feature maps的输入,而在后面的才是框框里面的。

(解释一下为什么是特征向量而不是坐标,因为特征向量是高级的语义信息,它可能包含坐标,也可能包含像素值和梯度等等,这都是需要学习后才能确定的,如果直接是坐标,这就属于低级的信息了,那也就不需要用VGG网络提取特征,直接输入原始图像就好了)

最终损失函数表示形式是:

Loss = \sum _{i=1}^{N}(t_{*}^{'}-\omega _{*}^{T}\Phi (P^{i}))^{2}

feature maps经过3x3卷积后,分别输入到cls和reg中,得到的rpn_cls_prob和rpn_bbox_pred,将这二者还有im_info输入到RPN_proposal。(im_info解释:https://blog.csdn.net/hejin_some/article/details/80743635

1.3 RPN_proposal

#为每个位置i产生一个以i为中心的anchor  A

#在像素 i 中 预测的bbox偏移量 应用在每个anchor中

#剪辑 预测框 到图像

#删除高度或宽度 小于 阈值的预测框

#根据score对所有的(proposal,score)进行排序

#在NMS之前 提取前 top pre_nms_topN的proposals  (NMS:nonmaximum suppression)

#对其余提案应用阈值为0.7的NMS

 #NMS之后,采取  after_nms_topN 个  proposals

#返回最靠前的proposals( - > RoIs top,得分排名靠前)

通过RPN_proposal后,还需要使用Fast RCNN。

1.4 Fast RCNN: ROI pooling+分类回归

Fast RCNN:ROI pooling+(分类/回归)。

为什么需要ROI pooling?我们知道,分类在全连接层后接一个softmax,但是是需要大小一样的。前面的rpn阶段输入的是整张feature map,而这里输入的是目标ROI的feature maps,如:

ROI 和anchor的区别,anchor是统一的一定size和ratio的矩形,ROI是anchor学习的偏移量所得。这一过程是:

anchor学习了4个偏移量,anchor根据4个偏移量得到的是原始的图像对应的位置,称为bounding box(如512x512resize到600x600,则对应的是这个600x600的),bounding box经过缩小变为feature maps上的ROI。

但RPN后,根据偏移量,会把这些anchors按偏移量缩放,这就不能保证每个ROI都一样了。所以ROI pooling的作用有2个:

第一就是提取ROI的特征;

第二个就是,将每个不同大小的ROI映射出相同大小size_fix的H和W,  如(7*7*channels)。方便接下来的cls 和reg。

1.5 Sharing Features for RPN and Fast R-CNN

原文中是说,RPN和Fast R-CNN独立训练的话那二者将会以不同的方式调节参数,所以需要将RPN和fast R-CNN联合起来,共同学习。

他采取的方案是交替训练——4-Step Alternating Training:

第一步:用pre-trained 的用来提取特征的model(如VGG等)初始化RPN网络,然后训练RPN,在训练后,model以及RPN会被更新。
第二步:用pre-trained 的model(和第一步一样)初始化Fast-rcnn。然后使用训练过的RPN来计算proposal,再将proposal给予Fast-rcnn网络,接着训练Fast-rcnn。训练完以后,model以及Fast-rcnn会被更新(RPN没有参与训练所以不变)。

这有个疑问,我没想明白,我觉得这个时候,Fast-rcnn和RPN是共享了的,因为RPN的结果用来训练了Fast rcnn,但是文中说At this point the two networks do not share convolutional layers.可是这一步明明是:we train a separate detection network by Fast R-CNN using the proposals generated by the step-1 RPN.

这个博主给了我解答Faster R-CNN的训练过程的理解_hotgarlicwang的博客-CSDN博客_faster rcnn训练过程  我混淆了 共享卷积的概念:model始终保持和上一步Fast-rcnn中model一致,所以就称之为着共享。

分享是美德,对我有启发的尽量po上,感谢博主的分享~~~~

第三步:使用第二步训练完成的model来初始化RPN网络,第二次训练RPN网络。但是这次要把model锁定,训练过程中,model始终保持不变,而RPN的会被改变。

第四步:仍然保持第三步的model不变,初始化Fast-rcnn,第二次训练Fast-rcnn网络。其实就是对其unique进行finetune,训练完毕,得到一个文中所说的unified network。

我觉得Faster RCNN就介绍到这,可能还需要补一些Fast rcnn,因为有个roi pooling,后续加上把~~

后面到重头戏了,用自己的数据训练网络,我使用的是pytorch,配置有点繁琐,所以第二步说一下如何配置以及最可能遇到的坑!

2 Pytorch 搭建 Faster RCNN系列——Linux环境

环境介绍:

Pytorch

GPU: l英伟达 1070 8G

CUDA:9.0(8.0也可以)

传输门: https://github.com/jwyang/faster-rcnn.pytorch/

改一下这个,比如我的是1070系列,则改成 sm_61

我觉得这个时候很多人都会遇到问题,我花了半天解决~~避免大家入坑,

RuntimeError: cuda runtime error (8) : invalid device function at /pytorch/torch/lib/THC/THCTensorCopy.cu:204

问题解决方案:

https://github.com/jwyang/faster-rcnn.pytorch/issues/110

然后就是运行例题了~~嗯,这个就略过了,bug这些东西真的看人品~~

下面进入我们的训练自己的数据的环节了.

3 Faster RCNN训练自己的数据集

3.1 准备自己的数据集

介绍一下为自己的数据,为的数据已经分割了.比如一幅图像中有3个杯子,则处理原始图像,还有3张每个杯子的分割图.

第一步是制作成txt:

xxxxx1.jpg xmin1 ymin1 xmax1 ymax1

xxxxx1.jpg xmin2 ymin2 xmax2 ymax2

第二步是将txt变成xml.

尊重他人劳动成果,传输门:

https://github.com/ChaoPei/create-pascal-voc-dataset

3.2 训练自己的网络

首先可以下载别人训练好的模型,我下载的是VGG提特征的那个.resnet效果会好一点.

上述链接有训练好的模型:https://github.com/jwyang/faster-rcnn.pytorch

Pretrained Model

We used two pretrained models in our experiments, VGG and ResNet101. You can download these two models from:

点击VT Server.

介绍一下如何改参数把,以及调整网络:

def parse_args():
  """
  Parse input arguments
  """
  parser = argparse.ArgumentParser(description='Train a Fast R-CNN network')
  parser.add_argument('--dataset', dest='dataset',
                      help='training dataset',
                      default='pascal_voc', type=str) #可不改动
  parser.add_argument('--net', dest='net',
                    help='vgg16, res101', #我使用的是VGG,所以把default改了
                    default='vgg16', type=str)
  parser.add_argument('--start_epoch', dest='start_epoch',
                      help='starting epoch',
                      default=1, type=int) #训练的时候epoch从哪开始
  parser.add_argument('--epochs', dest='max_epochs',
                      help='number of epochs to train',
                      default=100, type=int) #迭代多少次
  parser.add_argument('--disp_interval', dest='disp_interval',
                      help='number of iterations to display',
                      default=10, type=int) #在一个迭代中,间隔多少个batch显示
  parser.add_argument('--checkpoint_interval', dest='checkpoint_interval',
                      help='number of iterations to display',
                      default=20, type=int) #每多少个迭代显示

  parser.add_argument('--save_dir', dest='save_dir',
                      help='directory to save models', default="/home/faster-rcnn.pytorch/models",
                      type=str)
  parser.add_argument('--nw', dest='num_workers',
                      help='number of worker to load data',
                      default=0, type=int) #加载数据要多少个worker
  parser.add_argument('--cuda', dest='cuda',
                      help='whether use CUDA',default=True,
                      action='store_true') #是否使用cuda
  parser.add_argument('--ls', dest='large_scale',
                      help='whether use large imag scale',
                      action='store_true')  #学习率                    
  parser.add_argument('--mGPUs', dest='mGPUs',
                      help='whether use multiple GPUs',
                      action='store_true') #是否使用cuda
  parser.add_argument('--bs', dest='batch_size',
                      help='batch_size',
                      default=4, type=int)
  parser.add_argument('--cag', dest='class_agnostic',
                      help='whether perform class_agnostic bbox regression',
                      action='store_true') #是否执行类无关的bbox回归

# config optimization
  parser.add_argument('--o', dest='optimizer',
                      help='training optimizer',
                      default="sgd", type=str) #优化算法
  parser.add_argument('--lr', dest='lr',
                      help='starting learning rate',
                      default=0.001, type=float) #初始学习率
  parser.add_argument('--lr_decay_step', dest='lr_decay_step',
                      help='step to do learning rate decay, unit is epoch',
                      default=5, type=int)
  parser.add_argument('--lr_decay_gamma', dest='lr_decay_gamma',
                      help='learning rate decay ratio',
                      default=0.1, type=float) #学习率下降率

# set training session
  parser.add_argument('--s', dest='session',
                      help='training session',
                      default=1, type=int) #训练会话,针对多gpu

# resume trained model #使用训练好的模型
  parser.add_argument('--r', dest='resume',
                      help='resume checkpoint or not',
                      default=False, type=bool)
  parser.add_argument('--checksession', dest='checksession',
                      help='checksession to load model',
                      default=1, type=int)
  parser.add_argument('--checkepoch', dest='checkepoch',
                      help='checkepoch to load model',
                      default=1, type=int)
  parser.add_argument('--checkpoint', dest='checkpoint',
                      help='checkpoint to load model',
                      default=0, type=int)
# log and diaplay
  parser.add_argument('--use_tfboard', dest='use_tfboard',
                      help='whether use tensorflow tensorboard',
                      default=False, type=bool)

  args = parser.parse_args()
  return args

题外话:介绍一下argparse:arguments parser参数解析器.有时需要在终端执行python文件的时候,我们需要传入参数,所以会有个argparse来传参数.

但如果本地可以直接执行,会定义个:

if __name__ == '__main__':
    args = parse_args()

这个时候,应该如何修改或赋值上面定义的参数呢?

if __name__ == '__main__':
    args = parse_args()
    args.class_agnostic = True

这个时候直接训练就可以了.训练的适合有可能出现loss会出现NaN还是-1来着,这是因为,在制作xmin ymin xmax和ymax有的是-1.python 默认是0开始,而有的坐标从1开始,具体自己谷歌吧吼吼

3.3 测试和计算mAP

我运行的是demo.py并且稍微改了一下使得能够测mAP,test_net.py有比较多的bug,这个一调试电脑就死机.放在我的

github帐号上把,需要的自取.

https://github.com/ShourenWang/Faster-RCNN-pytorch

恩,如有疑惑之处,欢迎留言~

PS:

回头看曾经写的博客,深知记录和分享于己于人的重要性,目前在互联网大厂工作几年,建了技术分享群,欢迎添加~

  • 43
    点赞
  • 389
    收藏
    觉得还不错? 一键收藏
  • 33
    评论
目标检测是计算机视觉领域的重要任务,而Faster R-CNN作为目标检测领域的经典算法之一,具有较高的检测精度和鲁棒性。在睿智的目标检测系列中,我们将使用PyTorch搭建一个基于Faster R-CNN目标检测平台。 首先,我们将使用PyTorch构建一个深度学习模型的基础框架。PyTorch是一个开源的机器学习库,具有灵活的设计和易于使用的特点,因此非常适合用于搭建目标检测平台。我们将利用PyTorch提供的模块和工具,构建一个包含RPN模块、ROI pooling模块和分类回归模块的Faster R-CNN模型。 其次,我们将使用标记好的目标检测数据集,如COCO或PASCAL VOC数据集,对我们搭建目标检测平台进行训练和验证。我们将利用PyTorch内置的数据加载和预处理工具,以及优化器和损失函数,对Faster R-CNN模型进行端到端的训练,以提高检测精度和泛化能力。 最后,我们将通过在真实场景下的目标检测任务中的应用,来验证我们搭建Faster R-CNN目标检测平台的性能。我们将评估其在目标定位、多目标检测、不同尺寸目标检测等方面的表现,并对可能的改进和优化进行进一步的研究和实验。 通过这样一个基于PyTorch搭建Faster R-CNN目标检测平台,我们将能够深入理解目标检测算法的原理和实现细节,提高对深度学习框架的应用能力,并为未来的研究和应用奠定基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值