class_docstr: Creates a recurrent Critic network.
code: def call(self, inputs, step_type, network_state=(), training=False):
      observation, action = inputs
      observation_spec, _ = self.input_tensor_spec
      num_outer_dims = nest_utils.get_outer_rank(
          observation, observation_spec
      )
      if num_outer_dims not in (1, 2):
          raise ValueError(
              "Input observation must have a batch or batch x time outer shape."
          )
  
      has_time_dim = num_outer_dims == 2
      if not has_time_dim:
          # Add a time dimension to the inputs.
          observation = tf.nest.map_structure(
              lambda t: tf.expand_dims(t, 1), observation
          )
          action = tf.nest.map_structure(
              lambda t: tf.expand_dims(t, 1), action
          )
          step_type = tf.nest.map_structure(
              lambda t: tf.expand_dims(t, 1), step_type
          )
  
      observation = tf.cast(tf.nest.flatten(observation)[0], tf.float32)
      action = tf.cast(tf.nest.flatten(action)[0], tf.float32)
  
      batch_squash = utils.BatchSquash(2)  # Squash B, and T dims.
      observation = batch_squash.flatten(
          observation
      )  # [B, T, ...] -> [BxT, ...]
      action = batch_squash.flatten(action)
  
      for layer in self._observation_layers:
          observation = layer(observation, training=training)
  
      for layer in self._action_layers:
          action = layer(action, training=training)
  
      joint = tf.concat([observation, action], -1)
      for layer in self._joint_layers:
          joint = layer(joint, training=training)
  
      joint = batch_squash.unflatten(
          joint
      )  # [B x T, ...] -> [B, T, ...]
  
      network_kwargs = {}
      if isinstance(
          self._lstm_network, dynamic_unroll_layer.DynamicUnroll
      ):
          network_kwargs["reset_mask"] = tf.equal(
              step_type, time_step.StepType.FIRST, name="mask"
          )
  
      # Unroll over the time sequence.
      output = self._lstm_network(
          inputs=joint,
          initial_state=network_state,
          training=training,
          **network_kwargs,
      )
      if isinstance(
          self._lstm_network, dynamic_unroll_layer.DynamicUnroll
      ):
          joint, network_state = output
      else:
          joint = output[0]
          network_state = tf.nest.pack_sequence_as(
              self._lstm_network.cell.state_size,
              tf.nest.flatten(output[1:]),
          )
  
      output = batch_squash.flatten(
          joint
      )  # [B, T, ...] -> [B x T, ...]
  
      for layer in self._output_layers:
          output = layer(output, training=training)
  
      q_value = tf.reshape(output, [-1])
      q_value = batch_squash.unflatten(
          q_value
      )  # [B x T, ...] -> [B, T, ...]
      if not has_time_dim:
          q_value = tf.squeeze(q_value, axis=1)
  
      return q_value, network_state
  
file_path: agents/tf_agents/agents/ddpg/critic_rnn_network.py
imports: import gin
  import tensorflow
  from tf_agents.keras_layers import dynamic_unroll_layer
  from tf_agents.networks import network
  from tf_agents.networks import utils
  from tf_agents.specs import tensor_spec
  from tf_agents.trajectories import time_step
  from tf_agents.utils import nest_utils
label_desc: Use image node_id 2 for calling the CriticRnnNetwork obj's underlying member method code with example usage: obj.call(inputs, step_type, network_state, training) and returns: q_value,  network_state