class_docstr: This loss expects as input a batch consisting of pairs (a_1, p_1), (a_2, p_2)…, (a_n, p_n) where
      we assume that (a_i, p_i) are a positive pair and (a_i, p_j) for i!=j a negative pair.
      For each a_i, it uses all other p_j as negative samples, i.e., for a_i,
      we have 1 positive example (p_i) and n-1 negative examples (p_j).
      It then minimizes the negative log-likehood for softmax normalized scores.
      It can also support gather negatives across processes.
code: def forward(
      self, features_a, features_b, logit_scale, rank=0, world_size=1
  ):
      device = features_a.device
      if world_size > 1:
          all_features_a, all_features_b = gather_features(
              features_a,
              features_b,
              self.local_loss,
              self.gather_with_grad,
              rank,
              world_size,
              self.use_horovod,
          )
  
          if self.local_loss:
              logits_per_a = logit_scale * features_a @ all_features_b.T
              logits_per_b = logit_scale * features_b @ all_features_a.T
          else:
              logits_per_a = (
                  logit_scale * all_features_a @ all_features_b.T
              )
              logits_per_b = logits_per_a.T
      else:
          logits_per_a = logit_scale * features_a @ features_b.T
          logits_per_b = logit_scale * features_b @ features_a.T
  
      # calculated ground-truth and cache if enabled
      num_logits = logits_per_a.shape[0]
      if (
          self.prev_num_logits != num_logits
          or device not in self.labels
      ):
          labels = torch.arange(
              num_logits, device=device, dtype=torch.long
          )
          if world_size > 1 and self.local_loss:
              labels = labels + num_logits * rank
          if self.cache_labels:
              self.labels[device] = labels
              self.prev_num_logits = num_logits
      else:
          labels = self.labels[device]
  
      total_loss = (
          F.cross_entropy(logits_per_a, labels)
          + F.cross_entropy(logits_per_b, labels)
      ) / 2
      return total_loss
  
imports: import logging
  from typing import Optional
  import torch
  import torch.nn
  import torch.nn.functional
label_desc: Use image node_id 2 for calling the MultiNegativesSoftmaxLoss obj's underlying member method code with example usage: obj.forward(features_a, features_b, logit_scale, rank, world_size) and returns: total_loss