Skip to content

Commit c7b6b42

Browse files
authored
Add sparse_sigmoid activation (#21175)
* Add sparse_sigmoid activation layer * Correct typo
1 parent b840164 commit c7b6b42

File tree

15 files changed

+176
-0
lines changed

15 files changed

+176
-0
lines changed

keras/api/_tf_keras/keras/activations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from keras.src.activations.activations import softplus
3434
from keras.src.activations.activations import softsign
3535
from keras.src.activations.activations import sparse_plus
36+
from keras.src.activations.activations import sparse_sigmoid
3637
from keras.src.activations.activations import sparsemax
3738
from keras.src.activations.activations import squareplus
3839
from keras.src.activations.activations import tanh

keras/api/_tf_keras/keras/ops/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
from keras.src.ops.nn import softsign
104104
from keras.src.ops.nn import sparse_categorical_crossentropy
105105
from keras.src.ops.nn import sparse_plus
106+
from keras.src.ops.nn import sparse_sigmoid
106107
from keras.src.ops.nn import sparsemax
107108
from keras.src.ops.nn import squareplus
108109
from keras.src.ops.nn import tanh_shrink

keras/api/_tf_keras/keras/ops/nn/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from keras.src.ops.nn import softsign
4848
from keras.src.ops.nn import sparse_categorical_crossentropy
4949
from keras.src.ops.nn import sparse_plus
50+
from keras.src.ops.nn import sparse_sigmoid
5051
from keras.src.ops.nn import sparsemax
5152
from keras.src.ops.nn import squareplus
5253
from keras.src.ops.nn import tanh_shrink

keras/api/activations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from keras.src.activations.activations import softplus
3434
from keras.src.activations.activations import softsign
3535
from keras.src.activations.activations import sparse_plus
36+
from keras.src.activations.activations import sparse_sigmoid
3637
from keras.src.activations.activations import sparsemax
3738
from keras.src.activations.activations import squareplus
3839
from keras.src.activations.activations import tanh

keras/api/ops/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
from keras.src.ops.nn import softsign
104104
from keras.src.ops.nn import sparse_categorical_crossentropy
105105
from keras.src.ops.nn import sparse_plus
106+
from keras.src.ops.nn import sparse_sigmoid
106107
from keras.src.ops.nn import sparsemax
107108
from keras.src.ops.nn import squareplus
108109
from keras.src.ops.nn import tanh_shrink

keras/api/ops/nn/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from keras.src.ops.nn import softsign
4848
from keras.src.ops.nn import sparse_categorical_crossentropy
4949
from keras.src.ops.nn import sparse_plus
50+
from keras.src.ops.nn import sparse_sigmoid
5051
from keras.src.ops.nn import sparsemax
5152
from keras.src.ops.nn import squareplus
5253
from keras.src.ops.nn import tanh_shrink

keras/src/activations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from keras.src.activations.activations import softplus
2525
from keras.src.activations.activations import softsign
2626
from keras.src.activations.activations import sparse_plus
27+
from keras.src.activations.activations import sparse_sigmoid
2728
from keras.src.activations.activations import sparsemax
2829
from keras.src.activations.activations import squareplus
2930
from keras.src.activations.activations import tanh
@@ -53,6 +54,7 @@
5354
tanh_shrink,
5455
threshold,
5556
sigmoid,
57+
sparse_sigmoid,
5658
exponential,
5759
hard_sigmoid,
5860
hard_silu,

keras/src/activations/activations.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,27 @@ def log_sigmoid(x):
552552
return ops.log_sigmoid(x)
553553

554554

555+
@keras_export("keras.activations.sparse_sigmoid")
556+
def sparse_sigmoid(x):
557+
"""Sparse sigmoid activation function.
558+
559+
It is defined as
560+
561+
`f(x) = 0` for `x <= -1`,
562+
`f(x) = 0.5 * (x + 1)` for `-1 < x < 1`,
563+
`f(x) = 1` for `x >= 1`.
564+
565+
Args:
566+
x: Input tensor.
567+
568+
Reference:
569+
570+
- [M. Blondel, A. F. T. Martins, V. Niculae, 2019](https://arxiv.org/pdf/1901.02324)
571+
572+
"""
573+
return ops.sparse_sigmoid(x)
574+
575+
555576
@keras_export(["keras.activations.hard_silu", "keras.activations.hard_swish"])
556577
def hard_silu(x):
557578
"""Hard SiLU activation function, also known as Hard Swish.

keras/src/activations/activations_test.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ def _ref_hard_sigmoid(x):
4040
return z
4141

4242

43+
def _ref_sparse_sigmoid(x):
44+
return np.where(x <= -1, 0, np.where(x >= 1, 1, 0.5 * (x + 1)))
45+
46+
4347
def _ref_log_sigmoid(x):
4448
return -1 * _ref_softplus(-x)
4549

@@ -341,6 +345,45 @@ def test_hard_sigmoid(self):
341345
result_positive_above_1, expected_positive_above_1, rtol=1e-05
342346
)
343347

348+
def test_sparse_sigmoid(self):
349+
# Basic test for random values between 0 and 1
350+
x = np.random.uniform(0, 1, (2, 5))
351+
result = activations.sparse_sigmoid(x[np.newaxis, :])[0]
352+
expected = np.vectorize(_ref_sparse_sigmoid)(x)
353+
self.assertAllClose(result, expected, rtol=1e-05)
354+
355+
# Test with 1D array
356+
x_1d = np.random.uniform(-10, 10, 5)
357+
result_1d = activations.sparse_sigmoid(x_1d)
358+
expected_1d = np.vectorize(_ref_sparse_sigmoid)(x_1d)
359+
self.assertAllClose(result_1d, expected_1d, rtol=1e-05)
360+
361+
# Test with 3D array
362+
x_3d = np.random.uniform(-10, 10, (3, 3, 3))
363+
result_3d = activations.sparse_sigmoid(x_3d)
364+
expected_3d = np.vectorize(_ref_sparse_sigmoid)(x_3d)
365+
self.assertAllClose(result_3d, expected_3d, rtol=1e-05)
366+
367+
# Test large positive values
368+
x_large_positive = np.random.uniform(10, 100, (2, 5))
369+
result_large_positive = activations.sparse_sigmoid(x_large_positive)
370+
expected_large_positive = np.vectorize(_ref_sparse_sigmoid)(
371+
x_large_positive
372+
)
373+
self.assertAllClose(
374+
result_large_positive, expected_large_positive, rtol=1e-05
375+
)
376+
377+
# Test large negative values
378+
x_large_negative = np.random.uniform(-100, -10, (2, 5))
379+
result_large_negative = activations.sparse_sigmoid(x_large_negative)
380+
expected_large_negative = np.vectorize(_ref_sparse_sigmoid)(
381+
x_large_negative
382+
)
383+
self.assertAllClose(
384+
result_large_negative, expected_large_negative, rtol=1e-05
385+
)
386+
344387
def test_log_sigmoid(self):
345388
# Basic test for random values between 0 and 1
346389
x = np.random.uniform(0, 1, (2, 5))

keras/src/backend/jax/nn.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def sigmoid(x):
3636
return jnn.sigmoid(x)
3737

3838

39+
def sparse_sigmoid(x):
40+
x = convert_to_tensor(x)
41+
return jnn.sparse_sigmoid(x)
42+
43+
3944
def tanh(x):
4045
x = convert_to_tensor(x)
4146
return jnn.tanh(x)

0 commit comments

Comments
 (0)