Repository: ivy-llc/ivy

Issue:
cosine_embedding_loss



Discussion:

Resolving patch:
diff --git a/ivy/functional/frontends/paddle/nn/functional/loss.py b/ivy/functional/frontends/paddle/nn/functional/loss.py
--- a/ivy/functional/frontends/paddle/nn/functional/loss.py
+++ b/ivy/functional/frontends/paddle/nn/functional/loss.py
@@ -2,8 +2,10 @@
 import ivy
 from ivy.func_wrapper import with_supported_dtypes
 import ivy.functional.frontends.paddle as paddle
+from ivy.utils.exceptions import handle_exceptions
 from ivy.functional.frontends.paddle.func_wrapper import (
     inputs_to_ivy_arrays,
+    to_ivy_arrays_and_back,
 )
 
 
@@ -43,3 +45,46 @@ def binary_cross_entropy_with_logits(
         ret = ivy.multiply(weight, ret)
     ret = reduction(ret).astype(label.dtype)
     return paddle.to_tensor(ret.reshape([-1]))
+
+
+@handle_exceptions
+@to_ivy_arrays_and_back
+@with_supported_dtypes({"2.5.0 and below": ("float32", "float64")}, "paddle")
+def cosine_embedding_loss(
+    input1, input2, label, margin=0.0, reduction="mean", name=None
+):
+    if len(label.shape) != 1:
+        raise ValueError("1D target tensor expected, multi-target not supported")
+
+    if input1.shape != input2.shape:
+        raise ValueError(
+            "the shape of input tensor 1 should be equal to input tensor 2, but found"
+            " inputs with different sizes"
+        )
+
+    if len(input1.shape) > 2:
+        raise ValueError(
+            "1D target tensor expects 1D or 2D input tensors, but found inputs with"
+            " different sizes"
+        )
+
+    prod_sum = (input1 * input2).sum(axis=-1)
+    mag_square1 = ivy.square(input1).sum(axis=-1) + 1e-11
+    mag_square2 = ivy.square(input2).sum(axis=-1) + 1e-11
+    denom = ivy.sqrt(mag_square1 * mag_square2)
+    cos = prod_sum / denom
+    zeros = ivy.zeros_like(cos)
+    pos = 1 - cos
+    neg = ivy.clip(cos - margin, 0, 0)
+    out_pos = ivy.where(label == 1, pos, zeros)
+    out_neg = ivy.where(label == -1, neg, zeros)
+    out = out_pos + out_neg
+
+    if reduction == "none":
+        pass
+    if reduction == "mean":
+        out = ivy.mean(out)
+    elif reduction == "sum":
+        out = ivy.sum(out)
+
+    return out


Test patch:
diff --git a/ivy_tests/test_ivy/test_frontends/test_paddle/test_nn/test_functional/test_paddle_loss.py b/ivy_tests/test_ivy/test_frontends/test_paddle/test_nn/test_functional/test_paddle_loss.py
--- a/ivy_tests/test_ivy/test_frontends/test_paddle/test_nn/test_functional/test_paddle_loss.py
+++ b/ivy_tests/test_ivy/test_frontends/test_paddle/test_nn/test_functional/test_paddle_loss.py
@@ -56,3 +56,67 @@ def test_paddle_binary_cross_entropy_with_logits(
         weight=weight[0],
         reduction=reduction,
     )
+
+
+# cosine embedding loss
+@st.composite
+def _cos_embd_loss_helper(draw):
+    dtype_inputs_shape = draw(
+        helpers.dtype_and_values(
+            available_dtypes=helpers.get_dtypes("valid"),
+            min_num_dims=1,
+            max_num_dims=2,
+            min_dim_size=2,
+            ret_shape=True,
+            num_arrays=2,
+        )
+    )
+
+    input_dtypes, inputs, shape = dtype_inputs_shape
+
+    _, label = draw(
+        helpers.dtype_and_values(
+            dtype=input_dtypes, shape=(shape[0],), min_value=-1, max_value=1
+        ),
+    )
+
+    return input_dtypes, inputs, label
+
+
+@handle_frontend_test(
+    fn_tree="paddle.nn.functional.cosine_embedding_loss",
+    dtype_xs_label=_cos_embd_loss_helper(),
+    margin=st.floats(
+        min_value=-1.0,
+        max_value=1.0,
+        width=16,
+    ),
+    reduction=st.sampled_from(["none", "mean", "sum"]),
+    test_with_out=st.just(False),
+)
+def test_paddle_cosine_embedding_loss(
+    *,
+    dtype_xs_label,
+    margin,
+    reduction,
+    test_flags,
+    fn_tree,
+    frontend,
+    on_device,
+):
+    input_dtypes, xs, label = dtype_xs_label
+    input1_dtype, input1 = input_dtypes[0], xs[0]
+    input2_dtype, input2 = input_dtypes[1], xs[1]
+
+    helpers.test_frontend_function(
+        input_dtypes=[input1_dtype, input2_dtype],
+        frontend=frontend,
+        test_flags=test_flags,
+        fn_tree=fn_tree,
+        on_device=on_device,
+        input1=input1,
+        input2=input2,
+        label=label[0],
+        margin=margin,
+        reduction=reduction,
+    )