Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented hardsilu activation function #28299

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions ivy/data_classes/array/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,28 @@ def hardshrink(
ivy.array([0., 0., 0.])
"""
return ivy.hardshrink(self._data, lambd=lambd, out=out)

def hardsilu(self, out: Optional[ivy.Array] = None) -> ivy.Array:
"""ivy.Array instance method which acts as a wrapper for ivy.hardsilu.

Parameters
----------
self
input array
out
optional output array, for writing the result to. It must have a shape
that the inputs broadcast to.

Returns
-------
an array containing the output of the hardsilu/hardswish function applied
to each element in ``x``.

Examples
--------
>>> x = ivy.array([1., 2., 3.])
>>> y = x.hardsilu()
>>> print(y)
ivy.array([0.66666667, 1.66666667, 3.])
"""
return ivy.hardsilu(self._data, out=out)
114 changes: 114 additions & 0 deletions ivy/data_classes/container/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1837,3 +1837,117 @@ def hardshrink(
map_sequences=map_sequences,
out=out,
)

@staticmethod
def _static_hardsilu(
x: Union[ivy.Array, ivy.NativeArray, ivy.Container],
/,
*,
key_chains: Optional[Union[List[str], Dict[str, str], ivy.Container]] = None,
to_apply: Union[bool, ivy.Container] = True,
prune_unapplied: Union[bool, ivy.Container] = False,
map_sequences: Union[bool, ivy.Container] = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""ivy.Container static method which acts as a wrapper for
ivy.hardsilu.

Parameters
----------
x
input container
key_chains
The keychains to apply or not apply the method to. Default is ``None``.
to_apply
If True, the method will be applied to key_chains, otherwise key_chains
will be skipped. Default is ``True``.
prune_unapplied
Whether to prune key_chains for which the function was not applied.
Default is ``False``.
map_sequences
Whether to also map method to sequences (lists, tuples).
Default is ``False``.
out
optional output container, for writing the result to. It must have a shape
that the inputs broadcast to.

Returns
-------
a container containing the output of the hardsilu/hardswish function applied
to each element in ``x``.

Examples
--------
>>> x = ivy.Container(a=ivy.array([-0.5, -1, 0]), b=ivy.array([0.5, 1., 2]))
>>> y = ivy.Container._static_hardsilu(x)
>>> print(y)
{
a: ivy.array([-0.20833333, 0.33333333, 0.]),
b: ivy.array([0.29166667, 0.66666667, 1.66666667])
}
"""
return ContainerBase.cont_multi_map_in_function(
"hardsilu",
x,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
out=out,
)

def hardsilu(
self,
/,
*,
key_chains: Optional[Union[List[str], Dict[str, str], ivy.Container]] = None,
to_apply: Union[bool, ivy.Container] = True,
prune_unapplied: Union[bool, ivy.Container] = False,
map_sequences: Union[bool, ivy.Container] = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""ivy.Container instance method which acts as a wrapper for
ivy.hardsilu.

Parameters
----------
self
input container
key_chains
The keychains to apply or not apply the method to. Default is ``None``.
to_apply
If True, the method will be applied to key_chains, otherwise key_chains
will be skipped. Default is ``True``.
prune_unapplied
Whether to prune key_chains for which the function was not applied.
Default is ``False``.
map_sequences
Whether to also map method to sequences (lists, tuples).
Default is ``False``.
out
optional output container, for writing the result to. It must have a shape
that the inputs broadcast to.

Returns
-------
a container containing the output of the hardsilu/hardswish function applied
to each element in the input container.

Examples
--------
>>> x = ivy.Container(a=ivy.array([-0.5, -1, 0]), b=ivy.array([0.5, 1., 2]))
>>> y = x.hardsilu()
>>> print(y)
{
a: ivy.array([-0.20833333, 0.33333333, 0.]),
b: ivy.array([0.29166667, 0.66666667, 1.66666667])
}
"""
return self._static_hardsilu(
self,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
out=out,
)
8 changes: 8 additions & 0 deletions ivy/functional/backends/jax/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,11 @@ def hardshrink(
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ret


@with_unsupported_dtypes({"0.4.16 and below": ("float16", "bfloat16")}, backend_version)
def hardsilu(x: JaxArray, /, *, out: Optional[JaxArray] = None) -> JaxArray:
ret = jax.nn.hard_silu(x)
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ret
12 changes: 12 additions & 0 deletions ivy/functional/backends/numpy/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,15 @@ def hardshrink(


hardshrink.support_native_out = True


@with_unsupported_dtypes({"2.14.0 and below": ("complex",)}, backend_version)
@_scalar_output_to_0d_array
def hardsilu(x: np.ndarray, /, *, out: Optional[np.ndarray] = None) -> np.ndarray:
ret = x * np.divide(relu6(x + 3), 6)
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ivy.astype(ret, x.dtype)


hardsilu.support_native_out = True
7 changes: 7 additions & 0 deletions ivy/functional/backends/paddle/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,10 @@ def hardshrink(
F.hardshrink(x.img(), threshold=lambd),
)
return F.hardshrink(x.cast("float32"), threshold=lambd).cast(x.dtype)


@with_supported_dtypes({"2.5.1 and below": ("float32", "float64")}, backend_version)
def hardsilu(
x: paddle.Tensor, /, *, out: Optional[paddle.Tensor] = None
) -> paddle.Tensor:
return F.hardswish(x)
10 changes: 10 additions & 0 deletions ivy/functional/backends/tensorflow/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,13 @@ def hardshrink(
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ivy.astype(ret, x.dtype)


@with_unsupported_dtypes({"2.14.0 and below": ("complex",)}, backend_version)
def hardsilu(
x: Tensor, /, *, complex_mode="jax", out: Optional[Tensor] = None
) -> Tensor:
ret = tf.multiply(x, tf.nn.relu6(tf.math.add(x, 3)) / 6)
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ivy.astype(ret, x.dtype)
8 changes: 8 additions & 0 deletions ivy/functional/backends/torch/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,11 @@ def hardshrink(
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ivy.astype(ret, x.dtype)


@with_unsupported_dtypes({"2.0.1 and below": ("complex", "float16")}, backend_version)
def hardsilu(x: torch.Tensor, /, *, out: Optional[torch.Tensor] = None) -> torch.Tensor:
ret = torch.nn.functional.hardswish(x)
if ivy.exists(out):
return ivy.inplace_update(out, ret).astype(x.dtype)
return ivy.astype(ret, x.dtype)
52 changes: 52 additions & 0 deletions ivy/functional/ivy/experimental/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,55 @@ def hardshrink(
[ 1.70000005, 4.19999981, -6.5999999 ]])
"""
return current_backend(x).hardshrink(x, lambd=lambd, out=out)


@handle_exceptions
@handle_backend_invalid
@handle_nestable
@handle_array_like_without_promotion
@handle_out_argument
@to_native_arrays_and_back
@handle_device
def hardsilu(
x: Union[ivy.Array, ivy.NativeArray], /, *, out: Optional[ivy.Array] = None
) -> ivy.Array:
"""Apply the hardsilu/hardswish function element-wise.

Parameters
----------
x
input array
out
optional output array, for writing the result to. It must have a shape that the
inputs broadcast to.

Returns
-------
an array containing the output of the hardsilu/hardswish function applied
to each element in ``x``.

Examples
--------
With :class:`ivy.Array` input:

>>> x = ivy.array([1., 2., 3.])
>>> y = ivy.hardsilu(x)
>>> print(y)
ivy.array([0.66666667, 1.66666667, 3.])
>>> x = ivy.array([-2.1241, 1.4897, 4.4090])
>>> y = ivy.zeros(3)
>>> ivy.hardsilu(x, out=y)
>>> print(y)
ivy.array([-0.3101, 1.1147, 4.4090])

With :class:`ivy.Container` input:

>>> x = ivy.Container(a=ivy.array([-0.5, -1, 0]), b=ivy.array([0.5, 1., 2]))
>>> y = ivy.hardsilu(x)
>>> print(y)
{
a: ivy.array([-0.20833333, 0.33333333, 0.]),
b: ivy.array([0.29166667, 0.66666667, 1.66666667])
}
"""
return current_backend(x).hardsilu(x, out=out)
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ def test_hardshrink(
)


# hardsilu
@handle_test(
fn_tree="functional.ivy.experimental.hardsilu",
dtype_and_x=helpers.dtype_and_values(
available_dtypes=helpers.get_dtypes("float"),
large_abs_safety_factor=8,
small_abs_safety_factor=8,
safety_factor_scale="log",
),
)
def test_hardsilu(*, dtype_and_x, test_flags, backend_fw, fn_name, on_device):
dtype, x = dtype_and_x
helpers.test_function(
input_dtypes=dtype,
backend_to_test=backend_fw,
test_flags=test_flags,
fn_name=fn_name,
on_device=on_device,
x=x[0],
)


# hardtanh
@handle_test(
fn_tree="functional.ivy.experimental.hardtanh",
Expand Down
Loading