class_docstr: A simple, hard-coded dueling head model.
code: def __init__(
      self, obs_space, action_space, num_outputs, model_config, name
  ):
      # Pass num_outputs=None into super constructor (so that no action/
      # logits output layer is built).
      # Alternatively, you can pass in num_outputs=[last layer size of
      # config[model][fcnet_hiddens]] AND set no_last_linear=True, but
      # this seems more tedious as you will have to explain users of this
      # class that num_outputs is NOT the size of your Q-output layer.
      super(DuelingQModel, self).__init__(
          obs_space, action_space, None, model_config, name
      )
      # Now: self.num_outputs contains the last layer's size, which
      # we can use to construct the dueling head (see torch: SlimFC
      # below).
  
      # Construct advantage head ...
      self.A = tf.keras.layers.Dense(num_outputs)
      # torch:
      # self.A = SlimFC(
      #     in_size=self.num_outputs, out_size=num_outputs)
  
      # ... and value head.
      self.V = tf.keras.layers.Dense(1)
  
imports: from gymnasium.spaces import Box
  from ray.rllib.models.tf.fcnet import FullyConnectedNetwork
  from ray.rllib.models.tf.tf_modelv2 import TFModelV2
  from ray.rllib.models.torch.fcnet import FullyConnectedNetwork
  from ray.rllib.models.torch.misc import SlimFC
  from ray.rllib.models.torch.torch_modelv2 import TorchModelV2
  from ray.rllib.utils.framework import try_import_tf, try_import_torch
label_desc: Use image node_id 1 to create a new DuelingQModel object from inherited base classes: TFModelV2 with example: obj = DuelingQModel(obs_space, action_space, num_outputs, model_config, name)