SPP-net详解(金字塔池化)(附代码实现)

最近想弄透faster rcnn,觉得spp应该是非常重要的,先详细总结下:

为什么会有spp
先看下和传统分类的对比图
SPP-net详解(金字塔池化)(附代码实现)_第1张图片
解释:可以看到传统的操作是先将原图crop(裁剪/变换,也就是类似resize操作),直接送入卷积层,然后进入全连接分类。那么问题就来了,随便一张图目标物体位置和大小不一样,crop肯定会影响特征的准确性啊,但是不crop成统一大小,提取的特征图大小就不一样,没法送进全连接层,那有没有可能不crop直接得到固定维度的特征图呢?ok,这就是spp作用,加入spp之后就不需要提前crop,直接任意图片送进来,把spp核心放在卷积层和全连接层之间就搞定了!

spp具体结构是咋样的?
SPP-net详解(金字塔池化)(附代码实现)_第2张图片
解释:
上图就是spp结构,从下往上看,第一步卷积提取特征图,第二步金字塔池化,第三步将池化结果送入全连接层。第二步具体啥样子,就是把原来的特征图分别分成44=16块,22=4块,11=1块(不变),总共21块,取每块的最大值作为代表,即每张特征图就有21维的参数,总共卷积出来256个特征图,则送入全连接层的维度就是21256。

可能有些人到这里还是不懂,分块啥又变成21维,太抽象了,其实放到代码上来说,就是对特征图进行不同步长的池化而已,分四块取每块的最大值不就是步长大点,让一张图只池化四次,这下懂了吧。

当然这里输出的21维是可变的,改步长等具体参数就好了

spp的代码实现
具体来看下代码实现:

# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
import pandas as pd

def spp_layer(input_, levels=4, name = 'SPP_layer',pool_type = 'max_pool'):

    '''
    Multiple Level SPP layer.
    
    Works for levels=[1, 2, 3, 6].
    '''
    
    shape = input_.get_shape().as_list()
    
    with tf.variable_scope(name):

        for l in range(levels):
        #设置池化参数
            l = l + 1
            ksize = [1, np.ceil(shape[1]/ l + 1).astype(np.int32), np.ceil(shape[2] / l + 1).astype(np.int32), 1]
            strides = [1, np.floor(shape[1] / l + 1).astype(np.int32), np.floor(shape[2] / l + 1).astype(np.int32), 1]
            
            if pool_type == 'max_pool':
                pool = tf.nn.max_pool(input_, ksize=ksize, strides=strides, padding='SAME')
                pool = tf.reshape(pool,(shape[0],-1),)
                
            else :
                pool = tf.nn.avg_pool(input_, ksize=ksize, strides=strides, padding='SAME')
                pool = tf.reshape(pool,(shape[0],-1))
            print("Pool Level {:}: shape {:}".format(l, pool.get_shape().as_list()))
            if l == 1:
                x_flatten = tf.reshape(pool,(shape[0],-1))
            else:
                x_flatten = tf.concat((x_flatten,pool),axis=1) #四种尺度进行拼接
            print("Pool Level {:}: shape {:}".format(l, x_flatten.get_shape().as_list()))
            # pool_outputs.append(tf.reshape(pool, [tf.shape(pool)[1], -1]))
            

    return x_flatten


#x  = tf.ones((4,16,16,3))
#x_sppl = spp_layer(x,4)

refer https://www.jianshu.com/p/7f30b5935f3f
https://blog.csdn.net/v1_vivian/article/details/73275259

你可能感兴趣的:(目标检测,sppnet)