Repository: ivy-llc/ivy

Issue:
log_poisson_loss



Discussion:

Resolving patch:
diff --git a/ivy/functional/frontends/tensorflow/nn.py b/ivy/functional/frontends/tensorflow/nn.py
--- a/ivy/functional/frontends/tensorflow/nn.py
+++ b/ivy/functional/frontends/tensorflow/nn.py
@@ -482,3 +482,9 @@ def pool(
         data_format=data_format,
         dilations=dilations,
     )
+
+
+# log_poisson_loss
+@to_ivy_arrays_and_back
+def log_poisson_loss(targets, log_input, compute_full_loss=False, name=None):
+    return ivy.log_poisson_loss(targets, log_input, compute_full_loss, name)
diff --git a/ivy/functional/ivy/losses.py b/ivy/functional/ivy/losses.py
--- a/ivy/functional/ivy/losses.py
+++ b/ivy/functional/ivy/losses.py
@@ -11,6 +11,7 @@
 )
 from ivy.utils.exceptions import handle_exceptions
 
+
 # Helpers #
 # ------- #
 
@@ -382,3 +383,40 @@ def sparse_cross_entropy(
     return ivy.cross_entropy(
         true, pred, axis=axis, epsilon=epsilon, reduction=reduction, out=out
     )
+
+
+# log_poisson_loss
+@handle_exceptions
+@handle_nestable
+@handle_array_like_without_promotion
+@inputs_to_ivy_arrays
+@handle_array_function
+def log_poisson_loss(
+    targets: Union[ivy.Array, ivy.NativeArray],
+    log_input: Union[ivy.Array, ivy.NativeArray],
+    compute_full_loss: bool = False,
+    name=None,
+) -> ivy.Array:
+    try:
+        assert targets.shape == log_input.shape
+    except ValueError:
+        raise ValueError(
+            "`log_input` and `targets` must have the same shape, received "
+            f"({log_input.shape} vs {targets.shape})."
+        )
+
+    result = ivy.exp(log_input) - log_input * targets
+    if compute_full_loss:
+        point_five = 0.5
+        two_pi = 2 * ivy.pi
+
+        stirling_approx = (
+            (targets * ivy.log(targets))
+            - targets
+            + (point_five * ivy.log(two_pi * targets))
+        )
+        zeros = ivy.zeros_like(targets, dtype=targets.dtype)
+        ones = ivy.ones_like(targets, dtype=targets.dtype)
+        cond = ivy.logical_and(targets >= zeros, targets <= ones)
+        result += ivy.where(cond, zeros, stirling_approx)
+    return result


Test patch:
diff --git a/ivy_tests/test_ivy/test_frontends/test_tensorflow/test_nn.py b/ivy_tests/test_ivy/test_frontends/test_tensorflow/test_nn.py
--- a/ivy_tests/test_ivy/test_frontends/test_tensorflow/test_nn.py
+++ b/ivy_tests/test_ivy/test_frontends/test_tensorflow/test_nn.py
@@ -1563,3 +1563,43 @@ def test_tensorflow_pool(
         data_format=data_format,
         dilations=dilation,
     )
+
+
+@handle_frontend_test(
+    fn_tree="tensorflow.nn.log_poisson_loss",
+    dtype_target_log_inputs=helpers.dtype_and_values(
+        available_dtypes=helpers.get_dtypes("float"),
+        num_arrays=2,
+        min_value=0,
+        max_value=1,
+        min_num_dims=1,
+        max_num_dims=3,
+        min_dim_size=1,
+        max_dim_size=3,
+        shared_dtype=True,
+    ),
+    compute_full_loss=st.sampled_from([True, False]),
+    test_with_out=st.just(False),
+)
+def test_log_poisson_loss(
+    *,
+    dtype_target_log_inputs,
+    compute_full_loss,
+    test_flags,
+    frontend,
+    fn_tree,
+    on_device,
+):
+    input_dtype, input_values = dtype_target_log_inputs
+    targets, log_input = input_values
+    helpers.test_frontend_function(
+        input_dtypes=input_dtype,
+        test_flags=test_flags,
+        frontend=frontend,
+        fn_tree=fn_tree,
+        on_device=on_device,
+        targets=targets,
+        log_input=log_input,
+        compute_full_loss=compute_full_loss,
+        atol=1e-2,
+    )
diff --git a/ivy_tests/test_ivy/test_functional/test_nn/test_losses.py b/ivy_tests/test_ivy/test_functional/test_nn/test_losses.py
--- a/ivy_tests/test_ivy/test_functional/test_nn/test_losses.py
+++ b/ivy_tests/test_ivy/test_functional/test_nn/test_losses.py
@@ -209,3 +209,57 @@ def test_sparse_cross_entropy(
         epsilon=epsilon,
         reduction=reduction,
     )
+
+
+# log_poisson_loss
+@handle_test(
+    fn_tree="functional.ivy.log_poisson_loss",
+    dtype_and_targets=helpers.dtype_and_values(
+        available_dtypes=helpers.get_dtypes("float"),
+        min_value=0,
+        max_value=3,
+        allow_inf=False,
+        min_num_dims=1,
+        max_num_dims=3,
+        min_dim_size=3,
+    ),
+    dtype_and_log_input=helpers.dtype_and_values(
+        available_dtypes=helpers.get_dtypes("float"),
+        small_abs_safety_factor=4,
+        safety_factor_scale="log",
+        min_value=0,
+        max_value=3,
+        allow_inf=False,
+        exclude_min=True,
+        exclude_max=True,
+        min_num_dims=1,
+        max_num_dims=3,
+        min_dim_size=3,
+    ),
+    compute_full_loss=st.sampled_from([True, False]),
+    test_with_out=st.just(False),
+)
+def test_log_poisson_loss(
+    dtype_and_targets,
+    dtype_and_log_input,
+    compute_full_loss,
+    test_flags,
+    backend_fw,
+    fn_name,
+    on_device,
+    ground_truth_backend,
+):
+    targets_dtype, targets = dtype_and_targets
+    log_input_dtype, log_input = dtype_and_log_input
+    helpers.test_function(
+        ground_truth_backend=ground_truth_backend,
+        input_dtypes=targets_dtype + log_input_dtype,
+        test_flags=test_flags,
+        fw=backend_fw,
+        fn_name=fn_name,
+        on_device=on_device,
+        targets=targets[0],
+        log_input=log_input[0],
+        compute_full_loss=compute_full_loss,
+        atol_=1e-2,
+    )