code: def get_resources_per_job(
      self,
      total_num_cpus,
      total_num_gpus,
      num_jobs,
      minimum_cpu_per_job,
      minimum_gpu_per_job,
      wrap_resources_per_job_into_placement_group=False,
      user_resources_per_job=None,
      **kwargs,
  ):
      if user_resources_per_job is not None:
          cpu_per_job = user_resources_per_job.get(
              "num_cpus", minimum_cpu_per_job
          )
          assert (
              cpu_per_job <= total_num_cpus
          ), f"Detected model level cpu requirement = {cpu_per_job} > total cpu granted to AG predictor = {total_num_cpus}"
          assert (
              cpu_per_job >= minimum_cpu_per_job
          ), f"The model requires minimum cpu {minimum_cpu_per_job}, but you only specified {cpu_per_job}"
          gpu_per_job = user_resources_per_job.get(
              "num_gpus", minimum_gpu_per_job
          )
          assert (
              gpu_per_job <= total_num_gpus
          ), f"Detected model level gpu requirement = {gpu_per_job} > total cpu granted to AG predictor = {total_num_gpus}"
          assert (
              gpu_per_job >= minimum_gpu_per_job
          ), f"The model requires minimum gpu {minimum_gpu_per_job}, but you only specified {gpu_per_job}"
          num_parallel_jobs = min(
              total_num_cpus // cpu_per_job,
              total_num_gpus / gpu_per_job,
          )
          batches = math.ceil(num_jobs / num_parallel_jobs)
      else:
          cpu_per_job = max(
              minimum_cpu_per_job, int(total_num_cpus // num_jobs)
          )
          gpu_per_job = max(
              minimum_gpu_per_job, total_num_gpus / num_jobs
          )
          num_parallel_jobs = num_jobs
          if cpu_per_job:
              num_parallel_jobs = min(
                  num_parallel_jobs, total_num_cpus // cpu_per_job
              )
          if gpu_per_job:
              num_parallel_jobs = min(
                  num_parallel_jobs, total_num_gpus // gpu_per_job
              )
          if num_parallel_jobs == 0:
              raise AssertionError(
                  "Cannot train model with provided resources! "
                  f"(num_cpus, num_gpus)==({total_num_cpus}, {total_num_gpus}) | "
                  f"(min_cpus, min_gpus)==({minimum_cpu_per_job}, {minimum_gpu_per_job})"
              )
          cpu_per_job = int(total_num_cpus // num_parallel_jobs)
          gpu_per_job = total_num_gpus / num_parallel_jobs
          batches = math.ceil(num_jobs / num_parallel_jobs)
  
      resources_per_job = dict(cpu=cpu_per_job, gpu=gpu_per_job)
      if wrap_resources_per_job_into_placement_group:
          resources_per_job = (
              self.wrap_resources_per_job_into_placement_group(
                  resources_per_job
              )
          )
  
      resources_info = dict(
          resources_per_job=resources_per_job,
          num_parallel_jobs=num_parallel_jobs,
          batches=batches,
          cpu_per_job=cpu_per_job,
          gpu_per_job=gpu_per_job,
      )
      logger.log(
          10,
          f"Resources info for {self.__class__.__name__}: {resources_info}",
      )
  
      return resources_info
  
imports: import logging
  import math
  from abc import ABC, abstractmethod
  from autogluon.common.utils.resource_utils import ResourceManager
label_desc: Use image node_id 2 for calling the GpuResourceCalculator obj's underlying member method code with example usage: obj.get_resources_per_job(total_num_cpus, total_num_gpus, num_jobs, minimum_cpu_per_job, minimum_gpu_per_job, wrap_resources_per_job_into_placement_group, user_resources_per_job) and returns: resources_info