code: def forward(self, samples):
      with torch.no_grad():
          self.temp.clamp_(0.001, 0.5)
  
      visual_inputs = samples["video"]
      caption = samples["text_input"]
  
      b, t, c, h, w = visual_inputs.shape
  
      # forward text
      text = self.tokenizer(
          caption,
          padding="max_length",
          truncation=True,
          max_length=self.max_txt_len,
          return_tensors="pt",
      ).to(self.device)
  
      text_output = self.text_encoder.forward_text(
          text,
          token_type_ids=torch.zeros(
              text.input_ids.shape, dtype=torch.long, device=self.device
          ),
      )
      text_embeds = text_output.last_hidden_state
      text_feat = F.normalize(
          self.text_proj(text_embeds[:, 0, :]), dim=-1
      )
  
      # forward visual
      # timeSformer asks for (b, c, t, h, w) as input.
      video_embeds = self.visual_encoder.forward_features(visual_inputs)
      video_feat = F.normalize(
          self.vision_proj(video_embeds[:, 0, :]), dim=-1
      )
      video_atts = torch.ones(
          video_embeds.size()[:-1], dtype=torch.long
      ).to(self.device)
  
      # ========== (in-batch) ITC loss ==========
      gathered_video_feats = all_gather_with_grad(video_feat)
      gathered_text_feats = all_gather_with_grad(text_feat)
  
      sim_v2t = video_feat @ gathered_text_feats.t() / self.temp
      sim_t2v = text_feat @ gathered_video_feats.t() / self.temp
  
      sim_targets = torch.zeros_like(sim_v2t)
  
      local_rank = get_rank()
      b_start, b_end = b * local_rank, b * (local_rank + 1)
      sim_targets[:, b_start:b_end] = torch.eye(b)
  
      loss_v2t = -torch.sum(
          F.log_softmax(sim_v2t, dim=1) * sim_targets, dim=1
      ).mean()
      loss_t2v = -torch.sum(
          F.log_softmax(sim_t2v, dim=1) * sim_targets, dim=1
      ).mean()
  
      vtc_loss = (loss_v2t + loss_t2v) / 2
  
      (
          vtm_loss,
          vtm_logits,
          vtm_labels,
          encoder_output,
          encoder_output_neg,
      ) = self.compute_vtm(
          text_embeds=text_embeds,
          text_atts=text.attention_mask,
          image_embeds=video_embeds,
          image_atts=video_atts,
          sim_i2t=sim_v2t.clone(),  # for hard mining
          sim_t2i=sim_t2v.clone(),  # for hard mining
      )
  
      loss = vtc_loss + vtm_loss
  
      # return {"loss": loss}
      return AlproOutput(
          loss=loss,
          loss_vtc=vtc_loss,
          loss_vtm=vtm_loss,
          intermediate_output=AlproIntermediateOutput(
              video_embeds=video_embeds,
              text_embeds=text_embeds,
              encoder_output=encoder_output,
              encoder_output_neg=encoder_output_neg,
              vtm_logits=vtm_logits,
              vtm_labels=vtm_labels,
          ),
      )
  
imports: import datetime
  import logging
  import time
  import lavis.common.dist_utils
  import numpy
  import torch
  import torch.distributed
  import torch.nn.functional
  from lavis.common.config import node_to_dict
  from lavis.common.dist_utils import get_rank
  from lavis.common.logger import MetricLogger
  from lavis.common.registry import registry
  from lavis.models.alpro_models import AlproBase
  from lavis.models.alpro_models.alpro_outputs import AlproIntermediateOutput, AlproOutput
  from lavis.models.base_model import all_gather_with_grad
  from lavis.models.med import XBertEncoder
  from lavis.models.timesformer.vit import TimeSformer
  from torch import nn
label_desc: Use image node_id 2 for calling the AlproRetrieval obj's underlying member method code with example usage: obj.forward(samples) and returns: AlproOutput