docstr: Builds the TorchLearner.
  
  This method is specific to TorchLearner. Before running super() it will
  initialze the device properly based on the `_use_gpu` and `_distributed`
  flags, so that `_make_module()` can place the created module on the correct
  device. After running super() it will wrap the module in a TorchDDPRLModule
  if `_distributed` is True.
code: def build(self) -> None:
      """Builds the TorchLearner.
  
      This method is specific to TorchLearner. Before running super() it will
      initialze the device properly based on the `_use_gpu` and `_distributed`
      flags, so that `_make_module()` can place the created module on the correct
      device. After running super() it will wrap the module in a TorchDDPRLModule
      if `_distributed` is True.
      """
      # TODO (Kourosh): How do we handle model parallelism?
      # TODO (Kourosh): Instead of using _TorchAccelerator, we should use the public
      #  API in ray.train but allow for session to be None without any errors raised.
      if self._use_gpu:
          # get_device() returns the 0th device if
          # it is called from outside of a Ray Train session. Its necessary to give
          # the user the option to run on the gpu of their choice, so we enable that
          # option here via the local gpu id scaling config parameter.
          if self._distributed:
              self._device = get_device()
          else:
              assert self._local_gpu_idx < torch.cuda.device_count(), (
                  f"local_gpu_idx {self._local_gpu_idx} is not a valid GPU id or is "
                  " not available."
              )
              # this is an index into the available cuda devices. For example if
              # os.environ["CUDA_VISIBLE_DEVICES"] = "1" then
              # torch.cuda.device_count() = 1 and torch.device(0) will actuall map to
              # the gpu with id 1 on the node.
              self._device = torch.device(self._local_gpu_idx)
      else:
          self._device = torch.device("cpu")
  
      super().build()
  
      if self._torch_compile_complete_update:
          torch._dynamo.reset()
          self._compiled_update_initialized = False
          self._possibly_compiled_update = torch.compile(
              self._uncompiled_update,
              backend=self._torch_compile_cfg.torch_dynamo_backend,
              mode=self._torch_compile_cfg.torch_dynamo_mode,
              **self._torch_compile_cfg.kwargs,
          )
      else:
          if self._torch_compile_forward_train:
              if isinstance(self._module, TorchRLModule):
                  self._module.compile(self._torch_compile_cfg)
              elif isinstance(self._module, MultiAgentRLModule):
                  for module in self._module._rl_modules.values():
                      # Compile only TorchRLModules, e.g. we don't want to compile
                      # a RandomRLModule.
                      if isinstance(self._module, TorchRLModule):
                          module.compile(self._torch_compile_cfg)
              else:
                  raise ValueError(
                      "Torch compile is only supported for TorchRLModule and "
                      "MultiAgentRLModule."
                  )
  
          self._possibly_compiled_update = self._uncompiled_update
  
      self._make_modules_ddp_if_necessary()
  
imports: import logging
  import pathlib
  from typing import Any, Callable, Dict, Hashable, Sequence, Union, Tuple
  from ray.rllib.algorithms.algorithm_config import AlgorithmConfig, TorchCompileWhatToCompile
  from ray.rllib.core.learner.learner import Learner
  from ray.rllib.core.rl_module.marl_module import MultiAgentRLModule
  from ray.rllib.core.rl_module.rl_module import RLModule, SingleAgentRLModuleSpec
  from ray.rllib.core.rl_module.torch.torch_rl_module import TorchCompileConfig, TorchDDPRLModule, TorchRLModule
  from ray.rllib.policy.sample_batch import MultiAgentBatch
  from ray.rllib.utils.annotations import override, OverrideToImplementCustomLogic
  from ray.rllib.utils.deprecation import deprecation_warning
  from ray.rllib.utils.framework import try_import_torch
  from ray.rllib.utils.metrics import ALL_MODULES
  from ray.rllib.utils.nested_dict import NestedDict
  from ray.rllib.utils.torch_utils import convert_to_torch_tensor, copy_torch_tensors
  from ray.rllib.utils.typing import ModuleID, Optimizer, Param, ParamDict, TensorType
label_desc: Use image node_id 16 for calling the TorchLearner obj's underlying member method code with example usage: obj.build() without return types