前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战 | 源码入门之Faster RCNN

实战 | 源码入门之Faster RCNN

作者头像
用户1150922
发布2019-05-27 10:08:50
1.1K0
发布2019-05-27 10:08:50
举报

代码的主要文件

-data文件中主要是文件的与dataset相关的文件

-misc中有下载caffe版本预训练模型的文件,可以不看

-model文件中主要是与构建Faster Rcnn网络模型有关的文件

-utils中主要是一些辅助可视化和验证的文件

-train.py是整个程序的运行文件,下面有一部分会做介绍

-trainer.py文件主要是用于训练,模型的损失函数的计算都在这个文件中

train

先来看一下train.py里的主要内容:

def train(train(**kwargs)):    #训练网络的主要内容(位于train.py文件中)
  opt._parse(kwargs)
  dataset = Dataset(opt)      #读取用于训练的图片及进行相关的预处理(在下文的dataset部分做详细介绍)
  dataloader = data_.DataLoader(dataset, \
                                batch_size=1, \
                                shuffle=True, \
                                # pin_memory=True,
                                num_workers=opt.num_workers)
  testset = TestDataset(opt)  #读取用于测试的图片及进行相关的预处理
  test_dataloader = data_.DataLoader(testset,
                                     batch_size=1,
                                     num_workers=opt.test_num_workers,
                                     shuffle=False, \
                                     pin_memory=True
                                     )
  faster_rcnn = FasterRCNNVGG16()    #网络结构,包含主要Extractor,RPN和RoIHead三部分结构。
  trainer = FasterRCNNTrainer(faster_rcnn).cuda()  #主要包含模型的训练过程的

  for epoch in range(opt.epoch):#开始迭代训练
        trainer.reset_meters()
        for ii, (img, bbox_, label_, scale) in tqdm(enumerate(dataloader)):
            scale = at.scalar(scale)
            img, bbox, label = img.cuda().float(), bbox_.cuda(), label_.cuda()
            trainer.train_step(img, bbox, label, scale)  #执行训练

从train.py中的主要函数可以看出,主要的步骤涉及训练数据和测试数据的预处理,网络模型的构建(Faster RCNN),然后就是迭代训练,这也是通用的神经网络搭建和训练的过程。在Faster Rcnn网络模型中主要包含Extractor、RPN和RoIhead三部分。网络中Extractor主要是利用CNN进行特征提取,网络采用的VGG16;RPN是候选区网络,为RoIHead模块提供可能存在目标的候选区域(rois);RoIHead主要负责rois的分类和微调。整体的框架图如下图所示:

图片来源于陈云的知乎

Dataset

在本版本的代码中读取的数据格式为VOC,Dataset和TestDataset类分别负责训练数据和测试数据的读取及预处理。在预处理部分主要的操作就是resize图像的大小、像素值的处理以及图像的随机翻转。主要的内容如下:

class Dataset:     #训练数据预处理(位于data/dataset.py文件中)
    def __init__(self, opt):
        self.opt = opt
        self.db = VOCBboxDataset(opt.voc_data_dir)  #读取VOC格式的数据,包括图像和label(.xml)
        self.tsf = Transform(opt.min_size, opt.max_size) #resize图像的大小,在代码中默认长边小于等于1000,\
        #短边小于等于600,两个边至少有一个等于其值,然后对图像像素值减去均值,使得像素均值为零,并对图像进行随机翻转(具体细节代码见**)

    def __getitem__(self, idx):
        ori_img, bbox, label, difficult = self.db.get_example(idx)
        img, bbox, label, scale = self.tsf((ori_img, bbox, label))
        return img.copy(), bbox.copy(), label.copy(), scale

    def __len__(self):
        return len(self.db)
class TestDataset:
    pass          #与class Dataset相似,没有图像翻转过程(具体内容见data/dataset.py文件中TestDataset)

FasterRCNNVGG16

下面主要介绍Extractor、RPN和RoIHead三部分结构

Extractor
extractor, classifier = decom_vgg16() #该行代码位于model/faster_rcnn_vgg16.py中的FasterRCNNVGG16类中

Extractor部分主要使用的VGG16的网络结构,同时使用预训练好的模型提取图片的特征。论文中主要使用的是Caffe的预训练模型,根据代码的作者讲该版本的预训练模型效果比较好。

为了节约显存,作者将前四层卷积层的学习率设置为0,Conv5_3的输入作为图片的特征输入到RPN网络中。根据网络结构,Conv5_3部分的感受野为16,也就是相较于输入的图片大小,feature map的尺寸为(C,H/16,W/16).该部分网络结构图如下所示:

具体的decom_vgg16()代码如下:

def decom_vgg16():    #该段落代码位于model/faster_rcnn_vgg16.py中
    # the 30th layer of features is relu of conv5_3
    if opt.caffe_pretrain:  #使用caffe版本的预训练模型
        model = vgg16(pretrained=False)  #使用pytorch中自带的vgg16模型
        if not opt.load_path:
            model.load_state_dict(t.load(opt.caffe_pretrain_path)) #加载caffe版本的预训练模型,需要自己下载。
    else:
        model = vgg16(not opt.load_path)

    features = list(model.features)[:30]    #提取特征的网络
    classifier = model.classifier          #classifier在RoIhead部分使用

    classifier = list(classifier)
    del classifier[6]
    if not opt.use_drop:                #是否使用dropout
        del classifier[5]
        del classifier[2]
    classifier = nn.Sequential(*classifier)  #分类器网络

    # 冻结前四层卷积层
    for layer in features[:10]:
        for p in layer.parameters():
            p.requires_grad = False

    return nn.Sequential(*features), classifier
RPN

Faster RCNN中最突出的贡献就是提出了Region Proposal Network(RPN),将候选区域提取的时间开销几乎降为0。该模块的主要作用提供可能存在目标的候选区域rois。模块结构图如下所示:

图片来源于陈云的知乎

class RegionProposalNetwork(nn.Module):   #代码中实现RPN的类(代码位于model/region_proposal_network.py中)

  def __init__():#省略,具体看先关文件
  # ......
  def forward(self, x, img_size, scale=1.):
      #x: Extractor模块处理后的特征图,形状为(N, C, H, W)
      #img_size : 输入图像的大小
      #scale : 网络下采样的尺寸大小
      n, _, hh, ww = x.shape
      anchor = _enumerate_shifted_anchor(   #枚举所有anchor
          np.array(self.anchor_base),
          self.feat_stride, hh, ww)

      n_anchor = anchor.shape[0] // (hh * ww)  #一个anchor产生的锚点框
      h = F.relu(self.conv1(x))  #激活函数

      rpn_locs = self.loc(h)     #卷积产生每个锚点框的位置
      rpn_locs = rpn_locs.permute(0, 2, 3, 1).contiguous().view(n, -1, 4)
      rpn_scores = self.score(h)  #卷积产生每个锚点框的评分
      rpn_scores = rpn_scores.permute(0, 2, 3, 1).contiguous()
      rpn_softmax_scores = F.softmax(rpn_scores.view(n, hh, ww, n_anchor, 2), dim=4) #softmax操作
      rpn_fg_scores = rpn_softmax_scores[:, :, :, :, 1].contiguous()
      rpn_fg_scores = rpn_fg_scores.view(n, -1)
      rpn_scores = rpn_scores.view(n, -1, 2)

      rois = list()
      roi_indices = list()
      for i in range(n):
          roi = self.proposal_layer(            #根据每个锚点的评分选出对应的候选区域
              rpn_locs[i].cpu().data.numpy(),
              rpn_fg_scores[i].cpu().data.numpy(),
              anchor, img_size,
              scale=scale)
          batch_index = i * np.ones((len(roi),), dtype=np.int32)
          rois.append(roi)
          roi_indices.append(batch_index)

      rois = np.concatenate(rois, axis=0)
      roi_indices = np.concatenate(roi_indices, axis=0)
      return rpn_locs, rpn_scores, rois, roi_indices, anchor
RoIHead

RoIhead主要任务是对RPN网络选出的候选框进行分类和回归,在RoIhead中作者提出了RolPooling方法将不同尺度的候选区域全部pooling到一个尺度上。模块结构图如下所示:

图片来源于陈云的知乎

class VGG16RoIHead(nn.Module):                         #代码位于model/faster_rcnn_vgg16.py中
    def __init__(self, n_class, roi_size, spatial_scale,
                 classifier):
        # n_class includes the background
        super(VGG16RoIHead, self).__init__()

        self.classifier = classifier                   #vgg16的两层全连接,可见文中的Extractor部分VGG16的结构图
        self.cls_loc = nn.Linear(4096, n_class * 4)    #输出目标区域位置
        self.score = nn.Linear(4096, n_class)          #输出预测类别

        normal_init(self.cls_loc, 0, 0.001)            #正则化
        normal_init(self.score, 0, 0.01)

        self.n_class = n_class                         #类别
        self.roi_size = roi_size                       #roi大小
        self.spatial_scale = spatial_scale             #空间尺度
        self.roi = RoIPooling2D(self.roi_size, self.roi_size, self.spatial_scale)

    def forward(self, x, rois, roi_indices):
        #......省略
        pool = self.roi(x, indices_and_rois)     #RoI池化部分
        pool = pool.view(pool.size(0), -1)       #降维
        fc7 = self.classifier(pool)              #VGG16的两层全连接
        roi_cls_locs = self.cls_loc(fc7)         #预测出位置
        roi_scores = self.score(fc7)             #分类
        return roi_cls_locs, roi_scores

运行代码

整体来说该版本的代码环境相当简单,配置起来相当容易,没有什么坑,认真阅读作者的readme就好。在utils文件中有一个config.py文件,在里边可以修改文件读取的路径,学习率等参数,自己运行时根据自己的情况进行修改即可。小编运行自己的数据(非VOC2007)结果如下图:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年05月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码的主要文件
  • train
  • Dataset
  • FasterRCNNVGG16
    • Extractor
      • RPN
        • RoIHead
        • 运行代码
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档