class_docstr: Basic Batch Infer Task
class_docstr_tok: ["Basic","Batch","Infer","Task"]
code: def __call__(self, request, datastore: Datastore, infer: Callable):
      image_ids = sorted(self.get_images(request, datastore))
      max_batch_size = request.get("max_batch_size", 0)
      label_tag = request.get("label_tag", DefaultLabelTag.ORIGINAL)
      logger.info(
          f"Total number of images for batch inference: {len(image_ids)}; Max Batch Size: {max_batch_size}; Label Tag: {label_tag}"
      )
  
      start = time.time()
      if max_batch_size > 0:
          image_ids = image_ids[:max_batch_size]
  
      multi_gpu = request.get("multi_gpu", True)
      multi_gpus = request.get("gpus", "all")
      gpus = (
          list(range(torch.cuda.device_count()))
          if not multi_gpus or multi_gpus == "all"
          else multi_gpus.split(",")
      )
      device = name_to_device(request.get("device", "cuda"))
      device_ids = (
          [f"cuda:{id}" for id in gpus] if multi_gpu else [device]
      )
  
      result: dict = {}
      infer_tasks = []
      for idx, image_id in enumerate(image_ids):
          req = copy.deepcopy(request)
          req["_id"] = idx
          req["_image_id"] = image_id
  
          req["image"] = image_id
          req["save_label"] = True
          req["label_tag"] = label_tag
          req["logging"] = request.get("logging", "INFO")
          req["device"] = device_ids[idx % len(device_ids)]
  
          infer_tasks.append(req)
          result[image_id] = None
  
      total = len(infer_tasks)
      max_workers = request.get("max_workers", 0)
      max_workers = (
          max_workers
          if max_workers
          else max(1, multiprocessing.cpu_count() // 4)
      )
      max_workers = min(max_workers, multiprocessing.cpu_count())
  
      if len(infer_tasks) > 1 and (max_workers == 0 or max_workers > 1):
          logger.info(
              f"MultiGpu: {multi_gpu}; Using Device(s): {device_ids}; Max Workers: {max_workers}"
          )
          futures = {}
          with ThreadPoolExecutor(
              max_workers if max_workers else None, "WSI Infer"
          ) as executor:
              for t in infer_tasks:
                  futures[t["_id"]] = t, executor.submit(
                      run_infer_task, t, datastore, infer
                  )
  
              for tid, (t, future) in futures.items():
                  image_id = t["_image_id"]
                  try:
                      res = future.result()
                      result[image_id] = res
                  except Exception:
                      logger.warning(
                          f"Failed to finish Infer Task: {tid} => {image_id}",
                          exc_info=True,
                      )
                      result[image_id] = {}
  
                  finished = len(
                      [a for a in result.values() if a is not None]
                  )
                  logger.info(
                      f"{tid} => {image_id} => {t['device']} => {finished} / {total}"
                  )
      else:
          for t in infer_tasks:
              tid = t["_id"]
              res = run_infer_task(t, datastore, infer)
  
              image_id = t["_image_id"]
              result[image_id] = res
              finished = tid + 1
              logger.info(
                  f"{tid} => {image_id} => {t['device']} => {finished} / {total}"
              )
  
      latency_total = time.time() - start
      logger.info(f"Batch Infer Time Taken: {latency_total:.4f}")
      return result
  
file_path: MONAILabel/monailabel/interfaces/tasks/batch_infer.py
imports: import copy
  import logging
  import multiprocessing
  import time
  from concurrent.futures import ThreadPoolExecutor
  from enum import Enum
  from typing import Callable
  import torch
  from monailabel.interfaces.datastore import Datastore, DefaultLabelTag
  from monailabel.utils.others.generic import handle_torch_linalg_multithread, name_to_device, remove_file
label_desc: Use image node_id 2 for calling the BatchInferTask obj's underlying member method code with example usage: obj.__call__(request, datastore, infer) and returns: result