Robin
Robin

Reputation: 835

Custom pooling layer - minmax pooling - Keras - Tensorflow

I want to define my custom pooling layer, instead of returning the max values like the MaxPooling layer, it would output the k maximum values and the k minimum values.

I am using Tensorflow as the backend. I need the output vector to be sorted.

I was thinking about doing that:

from keras.layers.pooling import _Pooling1D

class MinMaxPooling1D(_Pooling1D):

    def __init__(self, output_dim, **kwargs):
        self.output_dim = output_dim
        super(MinMaxPooling1D, self).__init__(**kwargs)

    def _pooling_function(self, inputs, **kwargs):
        sorted_ = tf.contrib.framework.sort(inputs, axis = -1)
        print(sorted_)
        return np.concatenate((sorted_[:,:,:self.output_dim/2], sorted_[:,:,-self.output_dim/2:]))

But then I get:

Tensor("min_max_pooling1d_1/sort/Neg_1:0", shape=(?, 1, 1, ?), dtype=float32)
ValueError: zero-dimensional arrays cannot be concatenated

The MinMaxPooling1D layer is applied to a (None, 1, 10) shape output.

I was then thinking about adding a Flatten layer before the MinMaxPooling1D one, but then there is a dimension issue:

ValueError: Input 0 is incompatible with layer min_max_pooling1d_5: expected ndim=3, found ndim=2

Upvotes: 2

Views: 3905

Answers (2)

ikamen
ikamen

Reputation: 3485

So what you want to build is a Keras Layer that will take 3D input of shape [batch_dim, pool_dim, channels] and produce 4D output [batch_dim, pool_dim, channels, min_max_channels].

Unlike Keras _Pooling1D you will actually change the number of dimensions, and I would recommend to implement your layer by inheriting directly from keras Layer.

Implement the call method using tf.sort and taking the desired amount of max and min elements from the sorted input, and concatenating them along a new dimension (consider using tf.expand_dims and tf.concat).

p.s. I have tried to implement this myself, and have discovered it to be complicated. You basicly want something different from maxpool, and slightly more. You might take a look at tensorflow/python/ops/gen_nn_ops.py method max_pool to appreciate what kind of work you are in for, unless you can find some ready implementation somewhere...

Upvotes: 5

Robin
Robin

Reputation: 835

Instead of trying to use a Pooling Layer, I am using a Lambda:

def top_k(inputs, k):
  return tf.nn.top_k(inputs, k=k, sorted=True).values

def least_k(inputs, k):
    return -tf.nn.top_k(-inputs, k=k, sorted = True).values

def minmax_k(inputs, k):
    return tf.concat([least_k(inputs, k), top_k(inputs, k)], axis = -1)

model = Sequential()
...
model.add(Lambda(minmax_k, arguments={'k': R}))

Upvotes: 5

Related Questions