class_docstr: Base class for information retrieval models.
docstr: Called at the end of validation to aggregate outputs.
  :param outputs: list of individual outputs of each validation step.
docstr_tok: ["Called","at","the","end","of","validation","to","aggregate","outputs",".",":","param","outputs",":","list","of","individual","outputs","of","each","validation","step","."]
code: def on_validation_epoch_end(self):
      """
      Called at the end of validation to aggregate outputs.
      :param outputs: list of individual outputs of each validation step.
      """
  
      query_ids = torch.cat(
          [x["query_ids"] for x in self.validation_step_outputs]
      )
      passage_ids = torch.cat(
          [x["passage_ids"] for x in self.validation_step_outputs]
      )
      scores = torch.cat(
          [x["scores"] for x in self.validation_step_outputs]
      )
  
      all_query_ids, all_passage_ids, all_scores = [], [], []
      if torch.distributed.is_initialized():
          world_size = torch.distributed.get_world_size()
          for ind in range(world_size):
              all_query_ids.append(torch.empty_like(query_ids))
              all_passage_ids.append(torch.empty_like(passage_ids))
              all_scores.append(torch.empty_like(scores))
          torch.distributed.all_gather(all_query_ids, query_ids)
          torch.distributed.all_gather(all_passage_ids, passage_ids)
          torch.distributed.all_gather(all_scores, scores)
      else:
          all_query_ids.append(query_ids)
          all_passage_ids.append(passage_ids)
          all_scores.append(scores)
  
      val_mrr = 0
      if (
          not torch.distributed.is_initialized()
          or torch.distributed.get_rank() == 0
      ):
          query2passages, query2rels = {}, {}
          processed_queries = set()
  
          for i in range(len(all_query_ids)):
              query_ids = all_query_ids[i].detach().cpu().numpy()
              passage_ids = all_passage_ids[i].detach().cpu().numpy()
              scores = all_scores[i].detach().cpu().numpy()
  
              for j, query_id in enumerate(query_ids):
                  if query_id not in processed_queries:
                      processed_queries.add(query_id)
                      query2passages[query_id] = {
                          "psg_ids": passage_ids[j],
                          "scores": scores[j],
                      }
                      query2rels[query_id] = [passage_ids[j][0]]
                  else:
                      query2passages[query_id][
                          "psg_ids"
                      ] = np.concatenate(
                          (
                              query2passages[query_id]["psg_ids"],
                              passage_ids[j][1:],
                          )
                      )
                      query2passages[query_id][
                          "scores"
                      ] = np.concatenate(
                          (
                              query2passages[query_id]["scores"],
                              scores[j][1:],
                          )
                      )
  
          val_mrr = self.calculate_mean_reciprocal_rank(
              query2passages, query2rels
          )
  
      val_loss = torch.stack(
          [x["val_loss"] for x in self.validation_step_outputs]
      ).mean()
      self.validation_step_outputs.clear()  # free memory
      tensorboard_logs = {
          "val_mrr": val_mrr,
          "val_loss": val_loss,
      }
  
      return {"log": tensorboard_logs}
  
imports: import math
  from typing import Dict, Optional
  import numpy
  import torch
  from omegaconf import DictConfig, OmegaConf
  from pytorch_lightning import Trainer
  from nemo.collections.nlp.data import BertInformationRetrievalDataset
  from nemo.collections.nlp.models.nlp_model import NLPModel
  from nemo.collections.nlp.modules.common.lm_utils import get_lm_model
  from nemo.core.classes.common import typecheck
label_desc: Use image node_id 8 for calling the BaseIRModel obj's underlying member method code with example usage: obj.on_validation_epoch_end() and returns: dict