code: def forward(
      self,
      spectrograms,
      spec_masks,
      decoder_outputs,
      decoder_lengths=None,
  ):
      spec_in = spectrograms.transpose(-2, -1)
      masks = spec_masks.transpose(-2, -1)
      targets = spec_in
      # BxTxC
  
      targets = targets.reshape(
          targets.shape[0],
          targets.shape[1] // self.combine_time_steps,
          -1,
      )
      masks = masks.reshape(targets.shape[0], targets.shape[1], -1)
  
      if self.quantized_targets:
          if self.store_ids:
              # store ids for use by other losses
              (
                  targets,
                  prob_ppl_loss,
                  cur_codebook_temp,
                  self.target_ids,
              ) = self.quantizer(targets, return_ids=True)
  
              if self.reduce_ids:
                  # reduce consecutive equivalent ids to a single occurence
                  _, indices = torch.unique_consecutive(
                      self.target_ids, return_inverse=True
                  )
                  indices -= indices.min(dim=1, keepdims=True)[0]
                  reduced_ids = torch.zeros_like(self.target_ids)
                  reduced_ids = reduced_ids.scatter_(
                      1, indices, self.target_ids
                  )
                  reduced_lens = indices.max(dim=-1)[0] + 1
  
                  self.target_ids = reduced_ids.narrow(
                      1, 0, reduced_lens.max()
                  )
                  self.target_lengths = reduced_lens
  
              else:
                  self.target_lengths = None
  
          else:
              (
                  targets,
                  prob_ppl_loss,
                  cur_codebook_temp,
              ) = self.quantizer(targets)
      else:
          targets = self.target_proj(targets)
  
      if self.sample_from_same_utterance_only:
          bs = decoder_outputs.shape[0]
          masks = masks.mean(-1) > self.mask_threshold
          out_masked_only = decoder_outputs[masks]
          targets_masked_only = targets[masks]
          out_masked_only = out_masked_only.reshape(
              bs, -1, out_masked_only.shape[-1]
          )
          targets_masked_only = targets_masked_only.reshape(
              bs, -1, targets_masked_only.shape[-1]
          )
  
          # BxT'xC
          # number of masked time steps to predict (T')
          # -> T'xBxC
  
          out_masked_only = out_masked_only.transpose(0, 1)
          targets_masked_only = targets_masked_only.transpose(0, 1)
          # -> T'xBxC
  
          if self.sample_from_non_masked:
              # sample from all steps in utterance
              negatives, _ = self.sample_negatives(
                  targets.transpose(0, 1),
                  targets_masked_only.size(0),  # TxBxC  # T'
              )
          else:
              # only sample from masked steps in utterance
              negatives, _ = self.sample_negatives(
                  targets_masked_only, targets_masked_only.size(0)
              )  # T'xBxC  # T'
          # NxT'xBxC
  
          out_masked_only = out_masked_only.reshape(
              -1, out_masked_only.shape[-1]
          )
          targets_masked_only = targets_masked_only.reshape(
              -1, targets_masked_only.shape[-1]
          )
          negatives = negatives.reshape(
              self.num_negatives, -1, negatives.shape[-1]
          )
  
          # T'BxC and NxT'BxC
  
      else:
          masks = masks.mean(-1) > self.mask_threshold
          out_masked_only = decoder_outputs[masks]
          targets_masked_only = targets[masks]
  
          # T'xC
          # number of masked time steps to predict (T')
  
          if self.group_loss:
              num_groups = self.quantizer.groups
              negatives = self.quantizer.vars.reshape(
                  num_groups, self.quantizer.num_vars, -1
              )
              # GxNx(C//G)
              negatives = negatives.transpose(0, 1)
              # NxGx(C//G)
              negatives = negatives.unsqueeze(1).expand(
                  -1, out_masked_only.shape[0], -1, -1
              )
              # NxT'xGx(C//G)
              negatives = negatives.reshape(
                  negatives.shape[0], -1, negatives.shape[-1]
              )
              # NxT'Gx(C//G)
  
              out_masked_only = out_masked_only.reshape(
                  -1, out_masked_only.shape[-1] // num_groups
              )
              targets_masked_only = targets_masked_only.reshape(
                  -1, targets_masked_only.shape[-1] // num_groups
              )
              # T'Gx(C//G)
          elif self.sample_from_codebook:
              # sample from the full codebook
              negatives = self.quantizer.sample_from_codebook(
                  self.num_negatives, targets_masked_only.size(0)
              )
          elif self.sample_from_non_masked:
              # sample from all steps in batch
              negatives, _ = self.sample_negatives(
                  targets.reshape(
                      targets.shape[0] * targets.shape[1], -1
                  ),
                  targets_masked_only.size(0),  # BTxC
              )  # T'
          else:
              # only sample from masked steps
              negatives, _ = self.sample_negatives(
                  targets_masked_only, targets_masked_only.size(0)
              )  # T'xC  # T'
              # NxT'xC
  
      # Calculate similarity between outputs and all targets
      similarity_scores = self._calculate_similarity(
          out_masked_only, negatives, targets_masked_only
      )
      # (1+N)xT'
      # cosine similarity of outs with targets + N negatives
  
      # Create targets of size T
      similarity_targets = decoder_outputs.new_zeros(
          similarity_scores.size(1), dtype=torch.long
      )
      # T'
      # targets are 0, since it's the first, followed by N sampled negatives
  
      # Transpose similarity scores to TxF for loss
      similarity_scores = similarity_scores.transpose(0, 1)
      # T'x(1+N)
  
      loss = F.cross_entropy(
          similarity_scores, similarity_targets, reduction=self.reduce
      )
  
      sample_size = similarity_targets.numel()
  
      if self.prob_ppl_weight != 0 and self.quantized_targets:
          prob_ppl_loss = (
              self.prob_ppl_weight * prob_ppl_loss * sample_size
          )
          loss += prob_ppl_loss
  
      if not isinstance(loss, torch.Tensor):
          loss = torch.Tensor([0]).to(device=decoder_outputs.device)
  
      batch_size = spectrograms.shape[0]
      loss *= self.multiplier / batch_size
  
      return loss
  
file_path: NeMo/nemo/collections/asr/losses/ssl_losses/contrastive.py
imports: import torch
  import torch.nn.functional
  from torch import nn
  from nemo.core import Loss, typecheck
  from nemo.core.neural_types import AcousticEncodedRepresentation, LengthsType, LossType, NeuralType, SpectrogramType
label_desc: Use image node_id 6 for calling the ContrastiveLoss obj's underlying member method code with example usage: obj.forward(spectrograms, spec_masks, decoder_outputs, decoder_lengths) and returns: loss