Merge pull request #1 from joggino/master

Added PELU Activation Function
This commit is contained in:
Fariz Rahman
2017-01-26 09:14:11 +00:00
committed by GitHub
3 changed files with 98 additions and 0 deletions
+5
View File
@@ -34,6 +34,11 @@ var/
pip-log.txt
pip-delete-this-directory.txt
# PyCharms
*.xml
*.iml
.idea/
# Unit test / coverage reports
htmlcov/
.tox/
@@ -1,4 +1,84 @@
from .. import initializations
from keras.engine import Layer
from keras.utils.generic_utils import get_custom_objects
from .. import backend as K
import numpy as np
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_init: initialization function for the alpha variable weights.
betas_init: 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, alphas_init='one', betas_init='one', weights=None, shared_axes=None, **kwargs):
self.supports_masking = True
self.alphas_init = initializations.get(alphas_init)
self.betas_init = initializations.get(betas_init)
self.initial_weights = weights
if not isinstance(shared_axes, (list, tuple)):
self.shared_axes = [shared_axes]
else:
self.shared_axes = list(shared_axes)
super(PELU, self).__init__(**kwargs)
def build(self, input_shape):
param_shape = list(input_shape[1:])
self.param_broadcast = [False] * len(param_shape)
if self.shared_axes[0] is not None:
for i in self.shared_axes:
param_shape[i - 1] = 1
self.param_broadcast[i - 1] = True
# Initialised as ones to emulate the default ELU
self.alphas = self.alphas_init(param_shape,
name='{}_alphas'.format(self.name))
self.betas = self.betas_init(param_shape,
name='{}_betas'.format(self.name))
self.trainable_weights = [self.alphas, self.betas]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
def call(self, x, mask=None):
if K.backend() == 'theano':
pos = x * (K.pattern_broadcast(self.alphas, self.param_broadcast) /
K.pattern_broadcast(self.betas, self.param_broadcast))
neg = (K.pattern_broadcast(self.alphas, self.param_broadcast) *
(K.exp(x / K.pattern_broadcast(self.betas, self.param_broadcast)) - 1))
else:
pos = K.relu(x) * (self.alphas / self.betas)
neg = self.alphas * (K.exp(x / self.betas) - 1)
return K.switch(x < 0., neg, pos)
def get_config(self):
config = {'alphas_init': self.alphas_init.__name__,
'betas_init': self.betas_init.__name__}
base_config = super(PELU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
get_custom_objects().update({"PELU": PELU})
@@ -1,5 +1,18 @@
import pytest
from keras.utils.test_utils import layer_test, keras_test
from keras_contrib.layers import advanced_activations
@keras_test
def test_pelu():
layer_test(advanced_activations.PELU, kwargs={},
input_shape=(2, 3, 4))
@keras_test
def test_pelu_share():
layer_test(advanced_activations.PELU, kwargs={'shared_axes': 1},
input_shape=(2, 3, 4))
if __name__ == '__main__':