目标检测算法RCNN论文解读

论文题目:Rich feature hierarchies for accurate object detection and semantic segmentation

论文地址:https://arxiv.org/abs/1311.2524

tensorflow rcnn代码地址:https://github.com/Liu-Yicheng/R-CNN

 

RCNN,即Region CNN。

目标检测,不仅要将图片中含有的物体判断出是什么类别,而且还要找到物体所在的位置。 

一般分为以下步骤:

1、提取可能存在物体的区域框

2、用CNN提取特征

3、对区域框的物体进行分类、框回归

 

一、对论文的解读

1、网络模型:AlexNet

 

2、目标检测过程

(1)用selective search方法,从输入图片中提取2000个类别独立的候选区域。(selective search 也就是将图像分割成很多小的区域,计算区域之间的相似度(颜色、纹理等等),进行融合,形成大一些的region,结合各尺度结果。)

(2)对每个区域使用CNN,得到一个固定长度的特征向量。

(3)对每个区域用SVM进行目标分类。

 

3、迁移学习、finetune

在ImageNet数据集上训练得到很多很好的物体通用的特征,将其放在PASCAL VOC数据集上训练识别某些物体类型的能力。

 

4、inputsize:227*227pixel,由CNN的网络输入大小决定,因此将不同尺度的候选框wrap到227*227。

 

5、NMS

NMS,non maximum suppression,即非极大值抑制。就是将检测出的候选框,按照置信度score进行排序,保留最高的那个候选框。用NMS可以去掉重复的候选框,可以大大提高计算速度,没有冗余计算,而且较为准确。

 

6、查全率(precison)和查准率(recall)

定义以下标记:

tp:正确的标记为正;预测为真,实际为真 

fp:错误的标记为正;预测为假,实际为假 

tn:正确的标记为负;预测为真,实际为假 

fn:错误的标记为负;预测为假,实际为真  

查准率:precision = tp / (tp+fp) ;宁愿漏掉,不可错杀;正确预测占所有预测的比例

查全率:recall = tp / (tp+fn) ;宁可错杀,不可漏掉;正确预测占所有正例的比例

它们是评价模型的不同标准。

 

7、评价指标mAP

mAP,mean Average precision,对所有类别的precison取平均。

IoU,Intersection over Union,即交并比,本文Iou>0.5,就标记为positive正样本。

 

8、HNM

HNM,hard negetive mining,硬样本挖掘,所谓硬样本hard example,就是容易让分类器混淆,不好判断的样本。由于训练数据太大,全部训练成本大,采取HNM方法,可以将硬样本运用到下次训练中。

 

9、pool5特征可视化

这是一种无参方法,中心思想就是,挑选一个特征出来(本文采用的是pool5)计算对于不同的候选区域,激活层activation的值,将这些值按从大到小排序,取出前n个,显示对应的候选区域,就可以知道提取的是什么特征。

 

10、提取特征主要是卷积层,而不是全连接层

在finetune前,fc6,fc7作用不大,几乎可以移除;finetune后,fc6,fc7的作用得到提升。

 

11、bbox回归

借鉴于DPM中的框回归,线性回归模型,用pool5预测box的位置。

 

12、网络结构

(1)用selective search 提取候选区域

(2)用CNN提取特征

(3)用SVM进行分类

(4)对每个类别用NMS舍掉一部分region,进行框回归

 

13、预训练

使用一个大型辅助数据集 ILSVRC 2012 进行有监督的预训练,解决训练集数据缺乏的问题。

学习率:0.1

 

14、用region做detection的CNN

train:随机梯度下降SGD

学习率:0.001

 

15、判断正/负样本

部分区域含有物体,如何判断postive/negative example?IoU>0.5,记为正样本。

 

16、与DPM比较

DPM,deformable parts model,用一系列既定的model对feature map做计算,得到每类的值。DPM框架如下:

 

17、object proposal transformation

采用图b的方式,wraping with context padding,对候选框进行变形,也就是补全部分背景区域的图像,填充了16个像素。经过CNN计算,得到4096d的特征。

 

18、用selective search替代滑动窗口

selective search,区域合并的选择性搜索算法

(1)比滑动窗口复杂度低

(2)适应不同尺度,采用图像分割以及一种层次算法

(3)多样化,采用color/texture/size多种策略进行merge

(4)速度快

 

19、使用不同的标准(阈值)定义正负样本,这是调参的结果。

 

20、用SVM替代softmax,softmax背景样本共存,svm背景样本独立,更hard

 

21、最后要再做一次框回归,因为提取特征前为了resize样本,padding了16个像素,提取出来的框偏大。

 

22、瓶颈:对每个候选区域计算feature,2000个区域,计算量太大。

 

二、对代码的解读

1、IOU计算

def IOU(ver1, vertice2):
    '''
    用于计算两个矩形框的IOU
    :param ver1: 第一个矩形框
    :param vertice2: 第二个矩形框
    :return: 两个矩形框的IOU值
    '''
    vertice1 = [ver1[0], ver1[1], ver1[0]+ver1[2], ver1[1]+ver1[3]]
    area_inter = if_intersection(vertice1[0], vertice1[2], vertice1[1], vertice1[3], vertice2[0], vertice2[2], vertice2[1], vertice2[3])
    if area_inter:
        area_1 = ver1[2] * ver1[3]
        area_2 = vertice2[4] * vertice2[5]
        iou = float(area_inter) / (area_1 + area_2 - area_inter)
        return iou
    return False

 

2、selective search计算

def selective_search(
        im_orig, scale=1.0, sigma=0.8, min_size=50):
    '''Selective Search

    Parameters
    ----------
        im_orig : ndarray
            Input image
        scale : int
            Free parameter. Higher means larger clusters in felzenszwalb segmentation.
        sigma : float
            Width of Gaussian kernel for felzenszwalb segmentation.
        min_size : int
            Minimum component size for felzenszwalb segmentation.
    Returns
    -------
        img : ndarray
            image with region label
            region label is stored in the 4th value of each pixel [r,g,b,(region)]
        regions : array of dict
            [
                {
                    'rect': (left, top, right, bottom),
                    'labels': [...]
                },
                ...
            ]
    '''
    assert im_orig.shape[2] == 3, "3ch image is expected"

    # load image and get smallest regions
    # region label is stored in the 4th value of each pixel [r,g,b,(region)]
    img = _generate_segments(im_orig, scale, sigma, min_size)

    if img is None:
        return None, {}

    imsize = img.shape[0] * img.shape[1]
    R = _extract_regions(img)

    # extract neighbouring information
    neighbours = _extract_neighbours(R)

    # calculate initial similarities
    S = {}
    for (ai, ar), (bi, br) in neighbours:
        S[(ai, bi)] = _calc_sim(ar, br, imsize)

    # hierarchal search
    while S != {}:

        # get highest similarity
        # i, j = sorted(S.items(), cmp=lambda a, b: cmp(a[1], b[1]))[-1][0]
        i, j = sorted(list(S.items()), key = lambda a: a[1])[-1][0]

        # merge corresponding regions
        t = max(R.keys()) + 1.0
        R[t] = _merge_regions(R[i], R[j])

        # mark similarities for regions to be removed
        key_to_delete = []
        for k, v in S.items():
            if (i in k) or (j in k):
                key_to_delete.append(k)

        # remove old similarities of related regions
        for k in key_to_delete:
            del S[k]

        # calculate similarity set with the new region
        for k in filter(lambda a: a != (i, j), key_to_delete):
            n = k[1] if k[0] in (i, j) else k[0]
            S[(t, n)] = _calc_sim(R[t], R[n], imsize)

    regions = []
    for k, r in R.items():
        regions.append({
            'rect': (
                r['min_x'], r['min_y'],
                r['max_x'] - r['min_x'], r['max_y'] - r['min_y']),
            'size': r['size'],
            'labels': r['labels']
        })

    return img, regions

 

3、读取数据

def load_17flowers(self,save_name='17flowers.pkl'):
    '''
    在train_txt文件中以列为单位依次获取 图片地址、图片类别等信息
    将图片的矩阵数据(img)与图片类别数据(lable)作为一个整体进行保存
    '''
    save_path = os.path.join(self.data, save_name)
    if os.path.isfile(save_path):
        self.flower17_data = pickle.load(open(save_path, 'rb'))
    else:
        with codecs.open(self.train_list, 'r', 'utf-8') as f:
            lines = f.readlines()
            for num, line in enumerate(lines):
                context = line.strip().split(' ')
                image_path = context[0]
                index = int(context[1])

                img = cv2.imread(image_path)
                img = resize_image(img, self.image_size, self.image_size)
                img = np.asarray(img, dtype='float32')

                label = np.zeros(self.train_class_num)
                label[index] = 1
                self.flower17_data.append([img, label])
                view_bar("Process train_image of %s" % image_path, num + 1, len(lines))
        pickle.dump(self.flower17_data,open(save_path,'wb'))

 

4、网络模型AlexNet

(1)network:

def build_network(self, input, output, is_svm= False, scope='R-CNN',is_training=True, keep_prob=0.5):
    with tf.variable_scope(scope):
        with slim.arg_scope([slim.fully_connected, slim.conv2d],
                            activation_fn=nn_ops.relu,
                            weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
                            weights_regularizer=slim.l2_regularizer(0.0005)):
            net = slim.conv2d(input, 96, 11, stride=4, scope='conv_1')
            net = slim.max_pool2d(net, 3, stride=2, scope='pool_2')
            net = local_response_normalization(net)
            net = slim.conv2d(net, 256, 5, scope='conv_3')
            net = slim.max_pool2d(net, 3, stride=2, scope='pool_2')
            net = local_response_normalization(net)
            net = slim.conv2d(net, 384, 3, scope='conv_4')
            net = slim.conv2d(net, 384, 3, scope='conv_5')
            net = slim.conv2d(net, 256, 3, scope='conv_6')
            net = slim.max_pool2d(net, 3, stride=2, scope='pool_7')
            net = local_response_normalization(net)
            net = slim.flatten(net, scope='flat_32')
            net = slim.fully_connected(net, 4096, activation_fn=self.tanh(), scope='fc_8')
            net = slim.dropout(net, keep_prob=keep_prob,is_training=is_training, scope='dropout9')
            net = slim.fully_connected(net, 4096, activation_fn=self.tanh(), scope='fc_10')
            if is_svm:
                return net
            net = slim.dropout(net, keep_prob=keep_prob, is_training=is_training, scope='dropout11')
            net = slim.fully_connected(net, output, activation_fn=self.softmax(), scope='fc_11')
    return net

(2)loss:分类问题用交叉熵损失函数

 

5、SVM:sklearn.svm.LinearSVC()

 

6、regression Net

(1)network

def build_network(self, input_image, output_num, is_training= True, scope='regression_box', keep_prob=0.5):
    with tf.variable_scope(scope):
        with slim.arg_scope([slim.fully_connected],
                            activation_fn=self.tanh(),
                            weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
                            weights_regularizer=slim.l2_regularizer(0.0005)):
            net = slim.fully_connected(input_image, 4096, scope='fc_1')
            net = slim.dropout(net, keep_prob=keep_prob, is_training=is_training, scope='dropout11')
            net = slim.fully_connected(net, output_num, scope='fc_2')
            return net

(2)loss:均方差

(3)激活函数activation:tf.tanh()

 

7、训练和预测

共三种任务:特征提取,SVM预测分类,Reg_Box预测框回归。不同任务,不同的网络,不同的训练data。

 

 

  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值