class_docstr: Extension of the standard TFModelV2 for SAC.
  
  To customize, do one of the following:
  - sub-class SACTFModel and override one or more of its methods.
  - Use SAC's `q_model_config` and `policy_model` keys to tweak the default model
    behaviors (e.g. fcnet_hiddens, conv_filters, etc..).
  - Use SAC's `q_model_config->custom_model` and `policy_model->custom_model` keys
    to specify your own custom Q-model(s) and policy-models, which will be
    created within this SACTFModel (see `build_policy_model` and
    `build_q_model`.
  
  Note: It is not recommended to override the `forward` method for SAC. This
  would lead to shared weights (between policy and Q-nets), which will then
  not be optimized by either of the critic- or actor-optimizers!
  
  Data flow:
      `obs` -> forward() (should stay a noop method!) -> `model_out`
      `model_out` -> get_policy_output() -> pi(actions|obs)
      `model_out`, `actions` -> get_q_values() -> Q(s, a)
      `model_out`, `actions` -> get_twin_q_values() -> Q_twin(s, a)
code: def _get_q_value(self, model_out, actions, net):
      # Model outs may come as original Tuple/Dict observations, concat them
      # here if this is the case.
      if isinstance(net.obs_space, Box):
          if isinstance(model_out, (list, tuple)):
              model_out = tf.concat(model_out, axis=-1)
          elif isinstance(model_out, dict):
              model_out = tf.concat(list(model_out.values()), axis=-1)
  
      # Continuous case -> concat actions to model_out.
      if actions is not None:
          if self.concat_obs_and_actions:
              input_dict = {
                  "obs": tf.concat([model_out, actions], axis=-1)
              }
          else:
              # TODO(junogng) : SampleBatch doesn't support list columns yet.
              #     Use ModelInputDict.
              input_dict = {"obs": (model_out, actions)}
      # Discrete case -> return q-vals for all actions.
      else:
          input_dict = {"obs": model_out}
      # Switch on training mode (when getting Q-values, we are usually in
      # training).
      input_dict["is_training"] = True
  
      return net(input_dict, [], None)
  
imports: import gymnasium
  from gymnasium.spaces import Box, Discrete
  import numpy
  import tree
  from typing import Dict, List, Optional
  from ray.rllib.models.catalog import ModelCatalog
  from ray.rllib.models.tf.tf_modelv2 import TFModelV2
  from ray.rllib.utils.annotations import override
  from ray.rllib.utils.framework import try_import_tf
  from ray.rllib.utils.spaces.simplex import Simplex
  from ray.rllib.utils.typing import ModelConfigDict, TensorType, TensorStructType
label_desc: Use image node_id 7 for calling the SACTFModel obj's underlying member method code with example usage: obj._get_q_value(model_out, actions, net) and returns: net