2016-12-01 11 views
2

として空間ピラミッドプーリング層を実装したいと思います。用紙設定として固定長の空間ピラミッドプール層を実装する方法は?

、キーポイントである、変異カーネルサイズとmax_pooling層のストライドサイズを定義することである:

a入力テンソル空間のサイズであり、そして nはピラミッドレベルで
kernel_size = ceil(a/n) 
stride_size = floor(a/n) 

プール出力の空間ビンである。

私はtensorflowで、この層を実装しよう:

import numpy as np 
import tensorflow as tf 


def spp_layer(input_, name='SPP_layer'): 
    """ 
    4 level SPP layer. 

    spatial bins: [6_6, 3_3, 2_2, 1_1] 

    Parameters 
    ---------- 
    input_ : tensor 
    name : str 

    Returns 
    ------- 
    tensor 
    """ 
    shape = input_.get_shape().as_list() 

    with tf.variable_scope(name): 

     spp_6_6_pool = tf.nn.max_pool(input_, 
             ksize=[1, 
              np.ceil(shape[1]/6).astype(np.int32), 
              np.ceil(shape[2]/6).astype(np.int32), 
              1], 
             strides=[1, shape[1]//6, shape[2]//6, 1], 
             padding='SAME') 
     print('SPP layer level 6:', spp_6_6_pool.get_shape().as_list()) 

     spp_3_3_pool = tf.nn.max_pool(input_, 
             ksize=[1, 
              np.ceil(shape[1]/3).astype(np.int32), 
              np.ceil(shape[2]/3).astype(np.int32), 
              1], 
             strides=[1, shape[1]//3, shape[2]//3, 1], 
             padding='SAME') 
     print('SPP layer level 3:', spp_3_3_pool.get_shape().as_list()) 

     spp_2_2_pool = tf.nn.max_pool(input_, 
             ksize=[1, 
              np.ceil(shape[1]/2).astype(np.int32), 
              np.ceil(shape[2]/2).astype(np.int32), 
              1], 
             strides=[1, shape[1]//2, shape[2]//2, 1], 
             padding='SAME') 
     print('SPP layer level 2:', spp_2_2_pool.get_shape().as_list()) 

     spp_1_1_pool = tf.nn.max_pool(input_, 
             ksize=[1, 
              np.ceil(shape[1]/1).astype(np.int32), 
              np.ceil(shape[2]/1).astype(np.int32), 
              1], 
             strides=[1, shape[1]//1, shape[2]//1, 1], 
             padding='SAME') 
     print('SPP layer level 1:', spp_1_1_pool.get_shape().as_list()) 

     spp_6_6_pool_flat = tf.reshape(spp_6_6_pool, [shape[0], -1]) 
     spp_3_3_pool_flat = tf.reshape(spp_3_3_pool, [shape[0], -1]) 
     spp_2_2_pool_flat = tf.reshape(spp_2_2_pool, [shape[0], -1]) 
     spp_1_1_pool_flat = tf.reshape(spp_1_1_pool, [shape[0], -1]) 

     spp_pool = tf.concat(1, [spp_6_6_pool_flat, 
           spp_3_3_pool_flat, 
           spp_2_2_pool_flat, 
           spp_1_1_pool_flat]) 

    return spp_pool 

しかし、入力サイズが異なる場合には、同じ長さのプール出力を島嶼地区などすることはできません。

この問題を解決するにはどうすればよいですか?

+0

も参照してください:https://github.com/tensorflow/tensorflow/issues/6011 –

答えて

0

はい、出力サイズは現在一定ではありません。コードを見ると、個々のプーリング操作の出力サイズは2つの数値の間で切り替わるようです。その理由は、ストライドのために、我々は、本質的にin_heightの床であるものを使用/ N、その後、出力がnの間で変動する場合には、出力サイズは、少なくとも「SAME」のため、式

out_height = ceil(float(in_height)/float(strides[1])) 

で計算されていることですn + 1である。定数を保証するために必要なことは、ストライド値の代わりにceil演算を使用することです。 spp_6_6プールの変更されたコードは、私は明確にするために)(tf.nn.max_pool呼び出しの外ksize定義

ksize=[1, np.ceil(shape[1]/6).astype(np.int32), np.ceil(shape[2]/6).astype(np.int32), 1] 
spp_6_6_pool = tf.nn.max_pool(input_, ksize=ksize,strides=ksize, padding='SAME') 

あろう。だから、あなたの歩みにもあなたのksizeを使用すれば、それはうまくいくはずです。入力次元の大きさが最大のピラミッドサイズnの値の少なくとも2倍である限り、数学的に切り上げると、あなたの出力サイズは 'SAME'パディングで一定でなければなりません!

あなたの質問に幾分関連は、あなたの最初の最大プール操作であなたのksizeパラメータがksizeの三要素について

ksize=[1, np.ceil(shape[1]/6).astype(np.int32), np.ceil(shape[1]/6).astype(np.int32), 1] 

である、あなたは形をした[1]/6の代わりに形状の[2]/6 。私はそれが誤字だと思ったので、私は上記のコードでそれを変更しました。

私は、ストライドがa/nの床であり、天井ではなく、テンソルフローのネイティブプール操作を使用していることを今のところ知っています。必要に応じて作業します。 'VALID'プーリングは、あなたが望むものの近くに何ももたらさないでしょう。

まあ...あなたが本当に時間を置こうと思っているなら、あなたの最大のピラミッド次元(この場合は6)を法とする入力サイズを取って、これらの状況の6つすべてを独立して扱うことができます。私はこれについて良い正当化を見つけることができません。 Tensorflowは、例えばCaffeのような他のライブラリとは異なっているので、本質的に違いがあります。上記の解決策は、画像の互いに素な領域が異なるレベルの粒度で最大プールされている、プール層のピラミッドである、彼らが目指しているものをあなたにもたらします。

EDIT:実際には、入力を手作業で埋めるためにtf.pad()を使用し、新しい入力の高さと幅がnのすっきりした倍数になるように、最大​​プール操作ごとに新しい入力を作成すると、あなたがすでに持っているコードを試してみてください。

+0

ありがとう。私はテストを受けており、それはまた、論文の目標を達成できません。ストライド= 16/6 = 3、出力サイズ= 16/3 = 6 '、形状= 13、ストライド= 13/6 = 3、出力サイズ= 13 / –

0

私は論文の著者らは間違っている、式があるべきと考えている。両方式はあなたがユークリッド除算を行うことによって、この結果を証明することができ、N < 4. に同じ結果を与えることを

stride_size = floor(a/n) 
kernel_size = floor(a/n) + (a mod n) 

お知らせのby a n。

は私が https://github.com/tensorflow/tensorflow/issues/6011で見つけたコードを修正し、ここにある:

def spp_layer(input_, levels=(6, 3, 2, 1), name='SPP_layer'): 
    shape = input_.get_shape().as_list() 
    with tf.variable_scope(name): 
     pyramid = [] 
     for n in levels: 

      stride_1 = np.floor(float(shape[1]/n)).astype(np.int32) 
      stride_2 = np.floor(float(shape[2]/n)).astype(np.int32) 
      ksize_1 = stride_1 + (shape[1] % n) 
      ksize_2 = stride_2 + (shape[2] % n) 
      pool = tf.nn.max_pool(input_, 
            ksize=[1, ksize_1, ksize_2, 1], 
            strides=[1, stride_1, stride_2, 1], 
            padding='VALID') 

      # print("Pool Level {}: shape {}".format(n, pool.get_shape().as_list())) 
      pyramid.append(tf.reshape(pool, [shape[0], -1])) 
     spp_pool = tf.concat(1, pyramid) 
    return spp_pool 
関連する問題