class_docstr: Implementation of:
  [1] Curiosity-driven Exploration by Self-supervised Prediction
  Pathak, Agrawal, Efros, and Darrell - UC Berkeley - ICML 2017.
  https://arxiv.org/pdf/1705.05363.pdf
  
  Learns a simplified model of the environment based on three networks:
  1) Embedding observations into latent space ("feature" network).
  2) Predicting the action, given two consecutive embedded observations
  ("inverse" network).
  3) Predicting the next embedded obs, given an obs and action
  ("forward" network).
  
  The less the agent is able to predict the actually observed next feature
  vector, given obs and action (through the forwards network), the larger the
  "intrinsic reward", which will be added to the extrinsic reward.
  Therefore, if a state transition was unexpected, the agent becomes
  "curious" and will further explore this transition leading to better
  exploration in sparse rewards environments.
code: def get_exploration_optimizer(self, optimizers):
      # Create, but don't add Adam for curiosity NN updating to the policy.
      # If we added and returned it here, it would be used in the policy's
      # update loop, which we don't want (curiosity updating happens inside
      # `postprocess_trajectory`).
      if self.framework == "torch":
          feature_params = list(
              self._curiosity_feature_net.parameters()
          )
          inverse_params = list(
              self._curiosity_inverse_fcnet.parameters()
          )
          forward_params = list(
              self._curiosity_forward_fcnet.parameters()
          )
  
          # Now that the Policy's own optimizer(s) have been created (from
          # the Model parameters (IMPORTANT: w/o(!) the curiosity params),
          # we can add our curiosity sub-modules to the Policy's Model.
          self.model._curiosity_feature_net = (
              self._curiosity_feature_net.to(self.device)
          )
          self.model._curiosity_inverse_fcnet = (
              self._curiosity_inverse_fcnet.to(self.device)
          )
          self.model._curiosity_forward_fcnet = (
              self._curiosity_forward_fcnet.to(self.device)
          )
          self._optimizer = torch.optim.Adam(
              forward_params + inverse_params + feature_params,
              lr=self.lr,
          )
      else:
          self.model._curiosity_feature_net = (
              self._curiosity_feature_net
          )
          self.model._curiosity_inverse_fcnet = (
              self._curiosity_inverse_fcnet
          )
          self.model._curiosity_forward_fcnet = (
              self._curiosity_forward_fcnet
          )
          # Feature net is a RLlib ModelV2, the other 2 are keras Models.
          self._optimizer_var_list = (
              self._curiosity_feature_net.base_model.variables
              + self._curiosity_inverse_fcnet.variables
              + self._curiosity_forward_fcnet.variables
          )
          self._optimizer = tf1.train.AdamOptimizer(
              learning_rate=self.lr
          )
          # Create placeholders and initialize the loss.
          if self.framework == "tf":
              self._obs_ph = get_placeholder(
                  space=self.model.obs_space, name="_curiosity_obs"
              )
              self._next_obs_ph = get_placeholder(
                  space=self.model.obs_space, name="_curiosity_next_obs"
              )
              self._action_ph = get_placeholder(
                  space=self.model.action_space,
                  name="_curiosity_action",
              )
              (
                  self._forward_l2_norm_sqared,
                  self._update_op,
              ) = self._postprocess_helper_tf(
                  self._obs_ph, self._next_obs_ph, self._action_ph
              )
  
      return optimizers
  
imports: from gymnasium.spaces import Discrete, MultiDiscrete, Space
  import numpy
  from typing import Optional, Tuple, Union
  from ray.rllib.models.action_dist import ActionDistribution
  from ray.rllib.models.catalog import ModelCatalog
  from ray.rllib.models.modelv2 import ModelV2
  from ray.rllib.models.tf.tf_action_dist import Categorical, MultiCategorical
  from ray.rllib.models.torch.misc import SlimFC
  from ray.rllib.models.torch.torch_action_dist import TorchCategorical, TorchMultiCategorical
  from ray.rllib.models.utils import get_activation_fn
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.utils import NullContextManager
  from ray.rllib.utils.annotations import override, PublicAPI
  from ray.rllib.utils.exploration.exploration import Exploration
  from ray.rllib.utils.framework import try_import_tf, try_import_torch
  from ray.rllib.utils.from_config import from_config
  from ray.rllib.utils.tf_utils import get_placeholder, one_hot
  from ray.rllib.utils.torch_utils import one_hot
  from ray.rllib.utils.typing import FromConfigSpec, ModelConfigDict, TensorType
label_desc: Use image node_id 3 for calling the Curiosity obj's underlying member method code with example usage: obj.get_exploration_optimizer(optimizers) and returns: optimizers