from keras.layers import Layer, InputSpec from keras import initializers, regularizers, constraints import keras.backend as K from keras_contrib.utils.test_utils import to_tuple class PELU(Layer): """Parametric Exponential Linear Unit. It follows: `f(x) = alphas * (exp(x / betas) - 1) for x < 0`, `f(x) = (alphas / betas) * x for x >= 0`, where `alphas` & `betas` are learned arrays with the same shape as x. # Input shape Arbitrary. Use the keyword argument `input_shape` (tuple of integers, does not include the samples axis) when using this layer as the first layer in a model. # Output shape Same shape as the input. # Arguments alphas_initializer: initialization function for the alpha variable weights. betas_initializer: initialization function for the beta variable weights. weights: initial weights, as a list of a single Numpy array. shared_axes: the axes along which to share learnable parameters for the activation function. For example, if the incoming feature maps are from a 2D convolution with output shape `(batch, height, width, channels)`, and you wish to share parameters across space so that each filter only has one set of parameters, set `shared_axes=[1, 2]`. # References - [Parametric exponential linear unit for deep convolutional neural networks]( https://arxiv.org/abs/1605.09332v3) """ def __init__(self, alpha_initializer='ones', alpha_regularizer=None, alpha_constraint=None, beta_initializer='ones', beta_regularizer=None, beta_constraint=None, shared_axes=None, **kwargs): super(PELU, self).__init__(**kwargs) self.supports_masking = True self.alpha_initializer = initializers.get(alpha_initializer) self.alpha_regularizer = regularizers.get(alpha_regularizer) self.alpha_constraint = constraints.get(alpha_constraint) self.beta_initializer = initializers.get(beta_initializer) self.beta_regularizer = regularizers.get(beta_regularizer) self.beta_constraint = constraints.get(beta_constraint) if shared_axes is None: self.shared_axes = None elif not isinstance(shared_axes, (list, tuple)): self.shared_axes = [shared_axes] else: self.shared_axes = list(shared_axes) def build(self, input_shape): input_shape = to_tuple(input_shape) param_shape = list(input_shape[1:]) self.param_broadcast = [False] * len(param_shape) if self.shared_axes is not None: for i in self.shared_axes: param_shape[i - 1] = 1 self.param_broadcast[i - 1] = True param_shape = tuple(param_shape) # Initialised as ones to emulate the default ELU self.alpha = self.add_weight(shape=param_shape, name='alpha', initializer=self.alpha_initializer, regularizer=self.alpha_regularizer, constraint=self.alpha_constraint) self.beta = self.add_weight(shape=param_shape, name='beta', initializer=self.beta_initializer, regularizer=self.beta_regularizer, constraint=self.beta_constraint) # Set input spec axes = {} if self.shared_axes: for i in range(1, len(input_shape)): if i not in self.shared_axes: axes[i] = input_shape[i] self.input_spec = InputSpec(ndim=len(input_shape), axes=axes) self.built = True def call(self, x, mask=None): if K.backend() == 'theano': pos = K.relu(x) * (K.pattern_broadcast(self.alpha, self.param_broadcast) / K.pattern_broadcast(self.beta, self.param_broadcast)) neg = (K.pattern_broadcast(self.alpha, self.param_broadcast) * (K.exp((-K.relu(-x)) / K.pattern_broadcast(self.beta, self.param_broadcast)) - 1)) else: pos = K.relu(x) * self.alpha / self.beta neg = self.alpha * (K.exp((-K.relu(-x)) / self.beta) - 1) return neg + pos def get_config(self): config = { 'alpha_initializer': initializers.serialize(self.alpha_initializer), 'alpha_regularizer': regularizers.serialize(self.alpha_regularizer), 'alpha_constraint': constraints.serialize(self.alpha_constraint), 'beta_initializer': initializers.serialize(self.beta_initializer), 'beta_regularizer': regularizers.serialize(self.beta_regularizer), 'beta_constraint': constraints.serialize(self.beta_constraint), 'shared_axes': self.shared_axes } base_config = super(PELU, self).get_config() return dict(list(base_config.items()) + list(config.items())) def compute_output_shape(self, input_shape): return input_shape