class_docstr: The framework-agnostic base class for all RLlib encoders.
  
  Encoders are used to transform observations to a latent space.
  Therefore, their `input_specs` contains the observation space dimensions.
  Similarly, their `output_specs` contains the latent space dimensions.
  Encoders can be recurrent, in which case the state should be part of input- and
  output_specs. The latent vectors produced by an encoder are fed into subsequent
  "heads". Any implementation of Encoder should also be callable. This should be done
  by also inheriting from a framework-specific model base-class, s.a. TorchModel or
  TfModel.
  
  Abstract illustration of typical flow of tensors:
  
  Inputs
  |
  Encoder
  |          Head1  Head2
  |      /
  Outputs
  
  Outputs of encoders are generally of shape (B, latent_dim) or (B, T, latent_dim).
  That is, for time-series data, we encode into the latent space for each time step.
  This should be reflected in the `output_specs`.
  
  Usage example together with a ModelConfig:
  
  .. testcode::
  
      from dataclasses import dataclass
      import numpy as np
  
      from ray.rllib.core.models.base import Encoder, ENCODER_OUT, STATE_IN, STATE_OUT
      from ray.rllib.core.models.configs import ModelConfig
      from ray.rllib.policy.sample_batch import SampleBatch
  
      class NumpyEncoder(Encoder):
          def __init__(self, config):
              super().__init__(config)
              self.factor = config.factor
  
          @check_input_specs("input_specs")
          @check_output_specs("output_specs")
          def __call__(self, *args, **kwargs):
              # This is a dummy method to do checked forward passes.
              return self._forward(*args, **kwargs)
  
          def _forward(self, input_dict, **kwargs):
              obs = input_dict[SampleBatch.OBS]
              return {
                  ENCODER_OUT: np.array(obs) * self.factor,
                  STATE_OUT: np.array(input_dict[STATE_IN]) * self.factor,
              }
  
      @dataclass
      class NumpyEncoderConfig(ModelConfig):
          factor: int = None
  
          def build(self, framework: str):
              return NumpyEncoder(self)
  
      config = NumpyEncoderConfig(factor=2)
      encoder = NumpyEncoder(config)
      print(encoder({SampleBatch.OBS: 1, STATE_IN: 2}))
  
  .. testoutput::
  
      {'encoder_out': 2, 'state_out': 4}
class_docstr_tok: ["The","framework-agnostic","base","class","for","all","RLlib","encoders",".","Encoders","are","used","to","transform","observations","to","a","latent","space",".","Therefore",",","their","`","input_specs","`","contains","the","observation","space","dimensions",".","Similarly",",","their","`","output_specs","`","contains","the","latent","space","dimensions",".","Encoders","can","be","recurrent",",","in","which","case","the","state","should","be","part","of","input-","and","output_specs",".","The","latent","vectors","produced","by","an","encoder","are","fed","into","subsequent","''","heads","''",".","Any","implementation","of","Encoder","should","also","be","callable",".","This","should","be","done","by","also","inheriting","from","a","framework-specific","model","base-class",",","s.a.","TorchModel","or","TfModel",".","Abstract","illustration","of","typical","flow","of","tensors",":","Inputs","|","Encoder","|","Head1","Head2","|","\/","Outputs","Outputs","of","encoders","are","generally","of","shape","(","B",",","latent_dim",")","or","(","B",",","T",",","latent_dim",")",".","That","is",",","for","time-series","data",",","we","encode","into","the","latent","space","for","each","time","step",".","This","should","be","reflected","in","the","`","output_specs","`",".","Usage","example","together","with","a","ModelConfig",":","..","testcode",":",":","from","dataclasses","import","dataclass","import","numpy","as","np","from","ray.rllib.core.models.base","import","Encoder",",","ENCODER_OUT",",","STATE_IN",",","STATE_OUT","from","ray.rllib.core.models.configs","import","ModelConfig","from","ray.rllib.policy.sample_batch","import","SampleBatch","class","NumpyEncoder","(","Encoder",")",":","def","__init__","(","self",",","config",")",":","super","(",")",".__init__","(","config",")","self.factor","=","config.factor","@","check_input_specs","(","``","input_specs","''",")","@","check_output_specs","(","``","output_specs","''",")","def","__call__","(","self",",","*","args",",","*","*","kwargs",")",":","#","This","is","a","dummy","method","to","do","checked","forward","passes",".","return","self._forward","(","*","args",",","*","*","kwargs",")","def","_forward","(","self",",","input_dict",",","*","*","kwargs",")",":","obs","=","input_dict","[","SampleBatch.OBS","]","return","{","ENCODER_OUT",":","np.array","(","obs",")","*","self.factor",",","STATE_OUT",":","np.array","(","input_dict","[","STATE_IN","]",")","*","self.factor",",","}","@","dataclass","class","NumpyEncoderConfig","(","ModelConfig",")",":","factor",":","int","=","None","def","build","(","self",",","framework",":","str",")",":","return","NumpyEncoder","(","self",")","config","=","NumpyEncoderConfig","(","factor=2",")","encoder","=","NumpyEncoder","(","config",")","print","(","encoder","(","{","SampleBatch.OBS",":","1",",","STATE_IN",":","2","}",")",")","..","testoutput",":",":","{","'encoder_out","'",":","2",",","'state_out","'",":","4","}"]
code: def get_input_specs(self) -> Optional[Spec]:
      return [SampleBatch.OBS]
  
imports: import abc
  from typing import List, Optional, Tuple, Union
  from ray.rllib.core.models.configs import ModelConfig
  from ray.rllib.core.models.specs.specs_base import Spec
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.policy.rnn_sequencing import get_fold_unfold_fns
  from ray.rllib.utils.annotations import ExperimentalAPI, DeveloperAPI
  from ray.rllib.utils.annotations import override
  from ray.rllib.utils.typing import TensorType
label_desc: Use image node_id 1 for calling the Encoder obj's underlying member method code with example usage: obj.get_input_specs() and returns: list