code: def triplet_semihard_loss(
      y_true: TensorLike,
      y_pred: TensorLike,
      margin: FloatTensorLike = 1.0,
      distance_metric: Union[str, Callable] = "L2",
  ) -> tf.Tensor:
      r"""Computes the triplet loss with semi-hard negative mining.
  
      Usage:
  
      >>> y_true = tf.convert_to_tensor([0, 0])
      >>> y_pred = tf.convert_to_tensor([[0.0, 1.0], [1.0, 0.0]])
      >>> tfa.losses.triplet_semihard_loss(y_true, y_pred, distance_metric="L2")
      <tf.Tensor: shape=(), dtype=float32, numpy=2.4142137>
  
      >>> # Calling with callable `distance_metric`
      >>> distance_metric = lambda x: tf.linalg.matmul(x, x, transpose_b=True)
      >>> tfa.losses.triplet_semihard_loss(y_true, y_pred, distance_metric=distance_metric)
      <tf.Tensor: shape=(), dtype=float32, numpy=1.0>
  
      Args:
        y_true: 1-D integer `Tensor` with shape `[batch_size]` of
          multiclass integer labels.
        y_pred: 2-D float `Tensor` of embedding vectors. Embeddings should
          be l2 normalized.
        margin: Float, margin term in the loss definition.
        distance_metric: `str` or a `Callable` that determines distance metric.
          Valid strings are "L2" for l2-norm distance,
          "squared-L2" for squared l2-norm distance,
          and "angular" for cosine similarity.
  
          A `Callable` should take a batch of embeddings as input and
          return the pairwise distance matrix.
  
      Returns:
        triplet_loss: float scalar with dtype of `y_pred`.
      """
      labels = tf.convert_to_tensor(y_true, name="labels")
      embeddings = tf.convert_to_tensor(y_pred, name="embeddings")
  
      convert_to_float32 = (
          embeddings.dtype == tf.dtypes.float16
          or embeddings.dtype == tf.dtypes.bfloat16
      )
      precise_embeddings = (
          tf.cast(embeddings, tf.dtypes.float32)
          if convert_to_float32
          else embeddings
      )
  
      # Reshape label tensor to [batch_size, 1].
      lshape = tf.shape(labels)
      labels = tf.reshape(labels, [lshape[0], 1])
  
      # Build pairwise squared distance matrix
  
      if distance_metric == "L2":
          pdist_matrix = metric_learning.pairwise_distance(
              precise_embeddings, squared=False
          )
  
      elif distance_metric == "squared-L2":
          pdist_matrix = metric_learning.pairwise_distance(
              precise_embeddings, squared=True
          )
  
      elif distance_metric == "angular":
          pdist_matrix = metric_learning.angular_distance(
              precise_embeddings
          )
  
      else:
          pdist_matrix = distance_metric(precise_embeddings)
  
      # Build pairwise binary adjacency matrix.
      adjacency = tf.math.equal(labels, tf.transpose(labels))
      # Invert so we can select negatives only.
      adjacency_not = tf.math.logical_not(adjacency)
  
      batch_size = tf.size(labels)
  
      # Compute the mask.
      pdist_matrix_tile = tf.tile(pdist_matrix, [batch_size, 1])
      mask = tf.math.logical_and(
          tf.tile(adjacency_not, [batch_size, 1]),
          tf.math.greater(
              pdist_matrix_tile,
              tf.reshape(tf.transpose(pdist_matrix), [-1, 1]),
          ),
      )
      mask_final = tf.reshape(
          tf.math.greater(
              tf.math.reduce_sum(
                  tf.cast(mask, dtype=tf.dtypes.float32),
                  1,
                  keepdims=True,
              ),
              0.0,
          ),
          [batch_size, batch_size],
      )
      mask_final = tf.transpose(mask_final)
  
      adjacency_not = tf.cast(adjacency_not, dtype=tf.dtypes.float32)
      mask = tf.cast(mask, dtype=tf.dtypes.float32)
  
      # negatives_outside: smallest D_an where D_an > D_ap.
      negatives_outside = tf.reshape(
          _masked_minimum(pdist_matrix_tile, mask),
          [batch_size, batch_size],
      )
      negatives_outside = tf.transpose(negatives_outside)
  
      # negatives_inside: largest D_an.
      negatives_inside = tf.tile(
          _masked_maximum(pdist_matrix, adjacency_not), [1, batch_size]
      )
      semi_hard_negatives = tf.where(
          mask_final, negatives_outside, negatives_inside
      )
  
      loss_mat = tf.math.add(margin, pdist_matrix - semi_hard_negatives)
  
      mask_positives = tf.cast(
          adjacency, dtype=tf.dtypes.float32
      ) - tf.linalg.diag(tf.ones([batch_size]))
  
      # In lifted-struct, the authors multiply 0.5 for upper triangular
      #   in semihard, they take all positive pairs except the diagonal.
      num_positives = tf.math.reduce_sum(mask_positives)
  
      triplet_loss = tf.math.truediv(
          tf.math.reduce_sum(
              tf.math.maximum(
                  tf.math.multiply(loss_mat, mask_positives), 0.0
              )
          ),
          num_positives,
      )
  
      if convert_to_float32:
          return tf.cast(triplet_loss, embeddings.dtype)
      else:
          return triplet_loss
  
file_path: addons/tensorflow_addons/losses/triplet.py
imports: import tensorflow
  from tensorflow_addons.losses import metric_learning
  from tensorflow_addons.utils.keras_utils import LossFunctionWrapper
  from tensorflow_addons.utils.types import FloatTensorLike, TensorLike
  from typeguard import typechecked
  from typing import Optional, Union, Callable
label_desc: Use image node_id 3 for calling a global function with example usage: triplet_semihard_loss(y_true, y_pred, margin, distance_metric) and returns: tf, triplet_loss