SPP-net解读

介绍:在上面的过程中我们已经看了YOLO实现图片的定位和识别的过程,可以看到它是一个end-to-end的网络,通过设置S*S个格子,然后让每个格子预测B个bbox,然后进行NMS可以得到置信度较大的几个类的预测,然后进行回归分析,注意里面loss值的计算,便可以得到计算速度非常快,效果很不错的YOLO网络,相比faster-rcnn网络,效果没有那么好,但是速度却有了很大的提升!今天我们看一个非end-to-end网络,来自何凯明大神团队的一种对RCNN的一种提升的网络-spp net,为什么要讲这个网络而不讲fast-RCNN后者faster-RCNN网络呢,因为spp net中有一个spatial pyramid pooling layer(添加在最后一个卷积层和第一个全连接层之间),这个层可以实现将通道数(channel)相同但大小不同(width,height)的feature maps进行转化,然后进行flatten运算,然后就可以进行和后期的全连接层进行全连接运算,然后实现对不同输入大小的图像进行CNN运算的操作(这个主要体现在spp net中的),下面我们来做一个介绍!

问题提出:

RCNN的候选框是通过selective search方法得到的,一张图片大概有2k左右个region proposals,然后通过crop/warp进行处理,将每个region proposal送入CNN中进行卷积特征的提取,这样导致:
1)训练时间非常慢,因为一张图片产生2k左右的region proposals,都会送入CNN中进行训练;
2)识别准确率很低,因为产生的region proposals都会通过crop/warp操作,resize到同一大小送入CNN中进行训练,这样会造成图片信息的缺失或者变形失真,会降低图片识别的正确率。

解决方法:

这里写图片描述
针对1),RCNN中将一张图片的每一个region proposal都送入CNN中进行特征提取,而卷积运算是比较耗时的,能不能将一张图片整体送入CNN中进行特征提取,然后将一张图片的多个region proposals映射到最后的特征层上,形成每个region proposal的feature maps,进而加速特征的提取;
针对2)呢,RCNN中将region proposal都resize成统一大小,这样会造成图片信息的丢失或者变形,导致识别准确率降低,那么能不能不resize,直接用不同大小的region proposals的feature maps呢,分析一下,CNN需要用同一大小的图片输入是主要是在最后一个卷积层(pool5/conv5(如果没有pool5)的话)与第一个全连接层(fc)之间需要训练一个大小固定的二维数组,那么意味着我们特征resize的最晚期限至少可以拖延到pool5/conv5(如果没有poo5的话),这样可以得到的特征更完整一些,然后将这些大小不同的region proposal对应的feature maps输出到同一大小,何凯明大神在这里采用了spatial pyramid pooling(spp layer)完成这个工作,提高了对应的准确率(定位+识别)。既然这个方法芥末厉害,那么就让我们来了解一下这个网络!

网络结构:

从下面图片可以看到,无论最后一个卷积层得到的feature maps的大小是怎样的,我们都将其转化为了(4*4+2*2+1*1)*256的全连接层,不过需要注意的是,可以转化的条件是虽然这些feature maps的大小不同,但是feature maps的channels相同(这里为256),那么如何将不同大小的feature maps进行spp 呢?下面我们来具体分析:

假设输入的大小为a*a*c,然后呢,这些feature maps分别被分成了[1*1,2*2,4*4]大小的块,期望的输出为1*1*c,2*2*c,4*4*c,然后将reshape成(1*1+2*2+4*4)*c的二维数组,具体这儿是采用pool操作实现的,不过pool层的size和stride是不同的,具体有如下公式:
输出为[n,n],输入为[a,a],假设取上整运算为<-(),取下整运算为->(),那么pool_size=<-(n/a),stride=->(n/a),这样我们就将其转化为了n*n*c的矩阵,例如(13*13,10*10)都要转化为(4*4),那么采用[p_s=4,,s=3],[p_s=3,s=2]的池化操作后便可以得到(这里有一个问题哈,就是如果(7*7)也要得到4*4的话,利用公式算出来得到的池化为(6*6)与预期的4*4不符,这里暂时还有问题,准备后期再找一些资料再深入理解,如果有知道这个问题是怎么结局的大佬还望不吝赐教!

这里写图片描述

spp layer代码分析:

代码中存放的是spp layer中的目标输出大小,代码中bins=[1,2,3],经过处理之后就可以得到对应的(1*1+2*2+3*3)*256=14*256=3584个神经元,即无论前面的feature map是多大的,经过spp layer处理之后得到固定大小的神经元,然后就可以和全连接层进行矩阵运算了!

import tensorflow as tf
import math

class SPPLayer():
    def __init__(self,bins,feature_map_size):
        self.strides = []
        self.filters = []
#        print(type(feature_map_size))
        self.a = float(feature_map_size)
        self.bins = bins
        self.n = len(bins)

    def spatial_pyramid_pooling(self,data):
        self.input = data
        self.batch_size = self.input.get_shape().as_list()[0]
        for i in range(self.n):
            x = int(math.floor(self.a/float(self.bins[i])))
            self.strides.append(x)
            x = int (math.ceil(self.a/float(self.bins[i])))
            self.filters.append(x)

        self.pooled_out = []
        for i in range(self.n):
            self.pooled_out.append(tf.nn.max_pool(self.input,
                ksize=[1, self.filters[i], self.filters[i], 1], 
                strides=[1, self.strides[i], self.strides[i], 1],
                padding='VALID'))

        for i in range(self.n):
            self.pooled_out[i] = tf.reshape(self.pooled_out[i], [self.batch_size, -1])

        self.output = tf.concat(1, [self.pooled_out[0], self.pooled_out[1], self.pooled_out[2]])

        return self.output

应用:

  1. 图像分类
    这里我们不做过多讲解,对比添加spp-single和spp-multi和no spp对应的错误率,可以发现使用spp layer可以提高识别准确率!
    这里写图片描述
  2. 目标检测

这里注意是将region proposals映射到了对应的最后的卷积层的上面,然后得到了大批大小不同的feature maps,通过转化可以输出相同的feature maps!
这里写图片描述

可以看到利用spp net进行object detection的时候,不仅缩短了时间,同时也提高了对应的精度!
这里写图片描述

优点:

(PS:在卷积神经挽留过中,当输入不是固定size时?如何解决?
1):对输入进行resize,统一到同一大小;(裁剪或者伸缩变换将会使得图片变化很大,造成准确率的降低!)
2)取消全连接吃呢个,对最后的卷积层global average pooling(GAP);
3)在第一个全连接层前,假如spp layer(spatial pyramid pooling)。

参考:
Spatial Pyramid Pooling 详解
目标检测(3)-SPPNet
对sppnet网络的理解

你可能感兴趣的:(机器学习,深度学习进行目标定位和识别)