class_docstr: A recurrent GRU encoder.
  
  This encoder has...
  - Zero or one tokenizers.
  - One or more GRU layers.
  - One linear output layer.
code: def __init__(self, config: RecurrentEncoderConfig) -> None:
      TfModel.__init__(self, config)
  
      # Maybe create a tokenizer
      if config.tokenizer_config is not None:
          self.tokenizer = config.tokenizer_config.build(
              framework="tf2"
          )
          # For our first input dim, we infer from the tokenizer.
          # This is necessary because we need to build the layers in order to be
          # able to get/set weights directly after instantiation.
          input_dims = (1,) + tuple(
              self.tokenizer.output_specs[ENCODER_OUT].full_shape
          )
      else:
          self.tokenizer = None
          input_dims = (
              1,
              1,
          ) + tuple(config.input_dims)
  
      gru_weights_initializer = get_initializer_fn(
          config.hidden_weights_initializer, framework="tf2"
      )
      gru_bias_initializer = get_initializer_fn(
          config.hidden_bias_initializer, framework="tf2"
      )
  
      # Create the tf GRU layers.
      self.grus = []
      for _ in range(config.num_layers):
          layer = tf.keras.layers.GRU(
              config.hidden_dim,
              time_major=not config.batch_major,
              # Note, if the initializer is `None`, we want TensorFlow
              # to use its default one. So we pass in `None`.
              kernel_initializer=(
                  gru_weights_initializer(
                      **config.hidden_weights_initializer_config
                  )
                  if config.hidden_weights_initializer_config
                  else gru_weights_initializer
              ),
              use_bias=config.use_bias,
              bias_initializer=(
                  gru_bias_initializer(
                      **config.hidden_bias_initializer_config
                  )
                  if config.hidden_bias_initializer_config
                  else gru_bias_initializer
              ),
              return_sequences=True,
              return_state=True,
          )
          layer.build(input_dims)
          input_dims = (1, 1, config.hidden_dim)
          self.grus.append(layer)
  
imports: from typing import Optional
  import tree
  from ray.rllib.core.models.base import Encoder, ActorCriticEncoder, StatefulActorCriticEncoder, STATE_IN, STATE_OUT, ENCODER_OUT, tokenize
  from ray.rllib.core.models.base import Model
  from ray.rllib.core.models.configs import ActorCriticEncoderConfig, CNNEncoderConfig, MLPEncoderConfig, RecurrentEncoderConfig
  from ray.rllib.core.models.tf.base import TfModel
  from ray.rllib.core.models.tf.primitives import TfMLP, TfCNN
  from ray.rllib.core.models.specs.specs_base import Spec
  from ray.rllib.core.models.specs.specs_dict import SpecDict
  from ray.rllib.core.models.specs.specs_base import TensorSpec
  from ray.rllib.models.utils import get_initializer_fn
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.utils.annotations import override
  from ray.rllib.utils.framework import try_import_tf
  from ray.rllib.utils.nested_dict import NestedDict
label_desc: Use image node_id 1 to create a new TfGRUEncoder object from inherited base classes: TfModel, Encoder with example: obj = TfGRUEncoder(config)