diff --git a/CODEOWNERS b/CODEOWNERS index afa98df95..cd1b1b2c9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -26,6 +26,7 @@ keras_contrib/callbacks/snapshot.py @titu1994 # layers +keras_contrib/layers/advanced_activations/isrlu.py @SriRangaTarun keras_contrib/layers/advanced_activations/sinerelu.py @wilderrodrigues keras_contrib/layers/advanced_activations/swish.py @gabrieldemarmiesse keras_contrib/layers/convolutional/subpixelupscaling.py @titu1994 diff --git a/keras_contrib/layers/__init__.py b/keras_contrib/layers/__init__.py index bc460c6e6..3968c09b7 100644 --- a/keras_contrib/layers/__init__.py +++ b/keras_contrib/layers/__init__.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +from .advanced_activations.isrlu import ISRLU from .advanced_activations.pelu import PELU from .advanced_activations.srelu import SReLU from .advanced_activations.swish import Swish diff --git a/keras_contrib/layers/advanced_activations/isrlu.py b/keras_contrib/layers/advanced_activations/isrlu.py new file mode 100644 index 000000000..7ead43860 --- /dev/null +++ b/keras_contrib/layers/advanced_activations/isrlu.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +from keras import backend as K +from keras.layers import Layer + + +class ISRLU(Layer): + """Inverse Square Root Linear Unit + See: https://arxiv.org/pdf/1710.09967.pdf by AI Perf + Reference: https://en.wikipedia.org/wiki/Activation_function + Inverse Square Root Linear activation f(α, x): + x >= 0: x + x < 0: x / sqrt(1 + α * x^2) + # 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 + alpha: Value of the alpha weights (float) + NOTE : This function can become unstable for + negative values of α (it may return + NaNs). In particular, this happens when + α < 0 and x < -1/sqrt(α) or x > 1/sqrt(α). + If this happens, try limiting the magnitude + of α below a certain threshold, such that + 1 + α * x^2 is always positive. + Alternatively, you can normalize the inputs + into fixed ranges before passing them to ISRLU. + Adjust the value of α based on your specific + dataset and use-case. + # Example + model = Sequential() + model.add(Dense(5, input_shape=(15,)) + model.add(ISRLU(alpha=-0.3)) + """ + def __init__(self, + alpha=0.1, + **kwargs): + + super(ISRLU, self).__init__(**kwargs) + self.alpha = alpha + + def alpha_initializer(self, input_shape): + return self.alpha * K.ones(input_shape) + + def build(self, input_shape): + new_input_shape = input_shape[1:] + self.alphas = self.add_weight(shape=new_input_shape, + name='{}_alphas'.format(self.name), + initializer=self.alpha_initializer, + trainable=False) + self.build = True + + def call(self, x): + def inverse_square(x): + return x / K.sqrt(1 + self.alphas * K.square(x)) + + def identity(x): + return x + + return K.switch(K.less(x, K.zeros_like(x)), inverse_square(x), identity(x)) + + def compute_output_shape(self, input_shape): + return input_shape + + def get_config(self): + config = {'alpha': self.alpha} + base_config = super(ISRLU, self).get_config() + base_config['trainable'] = False + return dict(list(base_config.items()) + list(config.items())) diff --git a/tests/keras_contrib/layers/advanced_activations/test_isrlu.py b/tests/keras_contrib/layers/advanced_activations/test_isrlu.py new file mode 100644 index 000000000..ffbad40bb --- /dev/null +++ b/tests/keras_contrib/layers/advanced_activations/test_isrlu.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import pytest +from keras_contrib.utils.test_utils import layer_test +from keras_contrib.layers import ISRLU + + +@pytest.mark.parametrize('alpha', [0.2, 0.3, -0.01]) +def test_isrlu(alpha): + layer_test(ISRLU, + kwargs={'alpha': alpha}, + input_shape=(2, 3, 4)) + + +if __name__ == '__main__': + pytest.main([__file__])