空間金字塔池化
空間金字塔池化,使得任意大小的特征圖都能夠轉(zhuǎn)換成固定大小的特征向量,這就是空間金字塔池化的意義(多尺度特征提取出固定大小的特征向量),送入全連接層。


首先是輸入層(input image),其大小可以是任意的
進行卷積運算,到最后一個卷積層(圖中是(conv_5))輸出得到該層的特征映射(feature maps),其大小也是任意的
下面進入SPP層
我們先看最左邊有16個藍色小格子的圖,它的意思是將從(conv_5)得到的特征映射分成16份,另外16X256中的256表示的是channel,即SPP對每一層都分成16份(不一定是等比分,原因看后面的內(nèi)容就能理解了)。
中間的4個綠色小格子和右邊1個紫色大格子也同理,即將特征映射分別分成4X256和1X256份
那么將特征映射分成若干等分是做什么用的呢? 我們看SPP的名字就是到了,是做池化操作,一般選擇MAX Pooling,即對每一份進行最大池化。
我們看上圖,通過SPP層,特征映射被轉(zhuǎn)化成了16X256+4X256+1X256 = 21X256的矩陣,在送入全連接時可以擴展成一維矩陣,即1X10752,所以第一個全連接層的參數(shù)就可以設(shè)置成10752了,這樣也就解決了輸入數(shù)據(jù)大小任意的問題了。
注意上面劃分成多少份是可以自己是情況設(shè)置的,例如我們也可以設(shè)置成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)