#!/usr/bin/env python
'''Autopool: Adaptive pooling operators for multiple instance learning'''
from tensorflow.keras import backend as K
from tensorflow.keras.layers import Layer, InputSpec
from tensorflow.keras import initializers
from tensorflow.keras import constraints
from tensorflow.keras import regularizers
[docs]class AutoPool1D(Layer):
'''Automatically tuned soft-max pooling. (tensorflow.keras implementation)
This layer automatically adapts the pooling behavior to interpolate
between mean- and max-pooling for each dimension.
'''
[docs] def __init__(self, axis=0,
kernel_initializer='zeros',
kernel_constraint=None,
kernel_regularizer=None,
**kwargs):
'''
Parameters
----------
axis : int
Axis along which to perform the pooling. By default 0 (should be time).
kernel_initializer: Initializer for the weights matrix
kernel_regularizer: Regularizer function applied to the weights matrix
kernel_constraint: Constraint function applied to the weights matrix
kwargs
'''
if 'input_shape' not in kwargs and 'input_dim' in kwargs:
kwargs['input_shape'] = (kwargs.pop('input_dim'), )
super(AutoPool1D, self).__init__(**kwargs)
self.axis = axis
self.kernel_initializer = initializers.get(kernel_initializer)
self.kernel_constraint = constraints.get(kernel_constraint)
self.kernel_regularizer = regularizers.get(kernel_regularizer)
self.input_spec = InputSpec(min_ndim=3)
self.supports_masking = True
def build(self, input_shape):
assert len(input_shape) >= 3
input_dim = input_shape[-1]
self.kernel = self.add_weight(shape=(1, input_dim),
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
self.input_spec = InputSpec(min_ndim=2, axes={-1: input_dim})
self.built = True
def compute_output_shape(self, input_shape):
return self.get_output_shape_for(input_shape)
def get_output_shape_for(self, input_shape):
shape = list(input_shape)
del shape[self.axis]
return tuple(shape)
def get_config(self):
config = {'kernel_initializer': initializers.serialize(self.kernel_initializer),
'kernel_constraint': constraints.serialize(self.kernel_constraint),
'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
'axis': self.axis}
base_config = super(AutoPool1D, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
def call(self, x, mask=None):
weights = K.softmax(self.kernel * x, axis=self.axis)
return K.sum(x * weights, axis=self.axis, keepdims=False)
[docs]class SoftMaxPool1D(Layer):
'''
Tensorflow-keras softmax pooling layer.
'''
[docs] def __init__(self, axis=0, **kwargs):
'''
Parameters
----------
axis : int
Axis along which to perform the pooling. By default 0
(should be time).
kwargs
'''
super(SoftMaxPool1D, self).__init__(**kwargs)
self.axis = axis
def get_output_shape_for(self, input_shape):
shape = list(input_shape)
del shape[self.axis]
return tuple(shape)
def compute_output_shape(self, input_shape):
return self.get_output_shape_for(input_shape)
def call(self, x, mask=None):
weights = K.softmax(x, axis=self.axis)
return K.sum(x * weights, axis=self.axis, keepdims=False)
def get_config(self):
config = {'axis': self.axis}
base_config = super(SoftMaxPool1D, self).get_config()
return dict(list(base_config.items()) + list(config.items()))