空间金字塔池化
空间金字塔池化,使得任意大小的特征图都能够转换成固定大小的特征向量,这就是空间金字塔池化的意义(多尺度特征提取出固定大小的特征向量),送入全连接层。
首先是输入层(input image),其大小可以是任意的
进行卷积运算,到最后一个卷积层(图中是(conv_5))输出得到该层的特征映射(feature maps),其大小也是任意的
下面进入SPP层
我们先看最左边有16个蓝色小格子的图,它的意思是将从(conv_5)得到的特征映射分成16份,另外16X256中的256表示的是channel,即SPP对每一层都分成16份(不一定是等比分,原因看后面的内容就能理解了)。
中间的4个绿色小格子和右边1个紫色大格子也同理,即将特征映射分别分成4X256和1X256份
那么将特征映射分成若干等分是做什么用的呢? 我们看SPP的名字就是到了,是做池化操作,一般选择MAX Pooling,即对每一份进行最大池化。
我们看上图,通过SPP层,特征映射被转化成了16X256+4X256+1X256 = 21X256的矩阵,在送入全连接时可以扩展成一维矩阵,即1X10752,所以第一个全连接层的参数就可以设置成10752了,这样也就解决了输入数据大小任意的问题了。
注意上面划分成多少份是可以自己是情况设置的,例如我们也可以设置成3X3等,但一般建议还是按照论文中说的的进行划分。
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 20 18:13:52 2018
@author: yanghe
"""
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)