class_docstr: Composes template models from configs.
  
  :param action_spaces_dict: Dict of sub-step id to action space.
  :param observation_spaces_dict: Dict of sub-step id to observation space.
  :param distribution_mapper_config: Distribution mapper configuration.
  :param model_builder: The model builder (template) to create the model from.
  :param policy: Specifies the policy type as a configType.
      E.g. {'type': maze.perception.models.policies.ProbabilisticPolicyComposer} specifies a probabilistic policy.
  :param critic: Specifies the critic type as a configType.
      E.g. {'type': maze.perception.models.critics.StateCriticComposer} specifies the single step state critic.
class_docstr_tok: ["Composes","template","models","from","configs",".",":","param","action_spaces_dict",":","Dict","of","sub-step","id","to","action","space",".",":","param","observation_spaces_dict",":","Dict","of","sub-step","id","to","observation","space",".",":","param","distribution_mapper_config",":","Distribution","mapper","configuration",".",":","param","model_builder",":","The","model","builder","(","template",")","to","create","the","model","from",".",":","param","policy",":","Specifies","the","policy","type","as","a","configType",".","E.g",".","{","'type","'",":","maze.perception.models.policies.ProbabilisticPolicyComposer","}","specifies","a","probabilistic","policy",".",":","param","critic",":","Specifies","the","critic","type","as","a","configType",".","E.g",".","{","'type","'",":","maze.perception.models.critics.StateCriticComposer","}","specifies","the","single","step","state","critic","."]
docstr: Compiles a template value network.
  
  :param observation_space: The input observations for the perception network.
  :param shared_embedding_keys: The shared embedding keys for this substep's model (input)
  :param perception_net: The embedding network of the policy network if shared keys have been specified, in order
      reuse the block and share the embedding.
  :return: A value network (critic) InferenceBlock.
docstr_tok: ["Compiles","a","template","value","network",".",":","param","observation_space",":","The","input","observations","for","the","perception","network",".",":","param","shared_embedding_keys",":","The","shared","embedding","keys","for","this","substep","'s","model","(","input",")",":","param","perception_net",":","The","embedding","network","of","the","policy","network","if","shared","keys","have","been","specified",",","in","order","reuse","the","block","and","share","the","embedding",".",":","return",":","A","value","network","(","critic",")","InferenceBlock","."]
code: def template_value_net(
      self,
      observation_space: Optional[spaces.Dict],
      shared_embedding_keys: List[str] = None,
      perception_net: Optional[InferenceBlock] = None,
  ) -> InferenceBlock:
      """Compiles a template value network.
  
      :param observation_space: The input observations for the perception network.
      :param shared_embedding_keys: The shared embedding keys for this substep's model (input)
      :param perception_net: The embedding network of the policy network if shared keys have been specified, in order
          reuse the block and share the embedding.
      :return: A value network (critic) InferenceBlock.
      """
  
      shared_embedding_keys = (
          [] if shared_embedding_keys is None else shared_embedding_keys
      )
      # # build perception net
      if perception_net is None:
          assert len(shared_embedding_keys) == 0
          perception_net = self.template_perception_net(
              observation_space
          )
          perception_dict = perception_net.perception_dict
          inference_block_in_keys = perception_net.in_keys
          inference_block_in_shapes = perception_net.in_shapes
      else:
          assert len(shared_embedding_keys) > 0
          perception_dict = dict()
          _block_not_present_in_perception_net = list(
              filter(
                  lambda x: x not in perception_net.perception_dict,
                  shared_embedding_keys,
              )
          )
          assert len(_block_not_present_in_perception_net) == 0, (
              f"All given latent keys, must be present in the default perception dict (created for the policy)."
              f"But the following keys {_block_not_present_in_perception_net} was not found."
          )
          _blocks_with_more_outputs = list(
              filter(
                  lambda x: len(
                      perception_net.perception_dict[x].out_shapes()
                  )
                  > 1,
                  shared_embedding_keys,
              )
          )
          assert len(_blocks_with_more_outputs) == 0, (
              f"All given latent keys, must refer to a block with only a single output. But the following keys "
              f"have more than one output {_blocks_with_more_outputs}."
          )
  
          new_perception_net = self.template_perception_net(
              observation_space
          )
          new_perception_dict = new_perception_net.perception_dict
          start_adding_blocks = False
          for idx, block_keys in perception_net.execution_plan.items():
              if start_adding_blocks:
                  for block_key in block_keys:
                      perception_dict[block_key] = new_perception_dict[
                          block_key
                      ]
              if any(
                  [
                      block_key in shared_embedding_keys
                      for block_key in block_keys
                  ]
              ):
                  assert all(
                      [
                          [
                              block_key in shared_embedding_keys
                              for block_key in block_keys
                          ]
                      ]
                  ), (
                      f"In the template model composer, all shared embedding keys given must be on the same level"
                      f"in the execution plan of the inference block."
                  )
                  start_adding_blocks = True
  
          inference_block_in_keys = shared_embedding_keys
          inference_block_in_shapes = sum(
              [
                  perception_net.perception_dict[key].out_shapes()
                  for key in shared_embedding_keys
              ],
              [],
          )
  
      # build value head
      value_net = LinearOutputBlock(
          in_keys="latent",
          out_keys="value",
          in_shapes=perception_net.perception_dict[
              "latent"
          ].out_shapes(),
          output_units=1,
      )
  
      module_init = make_module_init_normc(std=0.01)
      value_net.apply(module_init)
  
      # extent perception dictionary
      perception_dict["value"] = value_net
  
      # compile inference model
      net = InferenceBlock(
          in_keys=inference_block_in_keys,
          out_keys="value",
          in_shapes=inference_block_in_shapes,
          perception_blocks=perception_dict,
      )
  
      return net
  
imports: import functools
  from typing import Optional, Dict, Union, Type, Tuple, List
  from gym import spaces
  from maze.core.agent.torch_policy import TorchPolicy
  from maze.core.agent.torch_state_action_critic import TorchSharedStateActionCritic, TorchStateActionCritic, TorchStepStateActionCritic
  from maze.core.agent.torch_state_critic import TorchStateCritic, TorchSharedStateCritic, TorchStepStateCritic, TorchDeltaStateCritic
  from maze.core.annotations import override
  from maze.core.env.structured_env import StepKeyType
  from maze.core.utils.factory import ConfigType, Factory
  from maze.core.utils.structured_env_utils import flat_structured_space
  from maze.core.wrappers.observation_preprocessing.preprocessors.one_hot import OneHotPreProcessor
  from maze.perception.blocks.inference import InferenceBlock
  from maze.perception.blocks.output.linear import LinearOutputBlock
  from maze.perception.builders.base import BaseModelBuilder
  from maze.perception.models.critics import SharedStateCriticComposer, DeltaStateCriticComposer, StepStateCriticComposer
  from maze.perception.models.critics.critic_composer_interface import CriticComposerInterface
  from maze.perception.models.critics.shared_state_action_critics_composer import SharedStateActionCriticComposer
  from maze.perception.models.critics.step_state_action_critic_composer import StepStateActionCriticComposer
  from maze.perception.models.model_composer import BaseModelComposer
  from maze.perception.models.policies.base_policy_composer import BasePolicyComposer
  from maze.perception.models.policies.probabilistic_policy_composer import ProbabilisticPolicyComposer
  from maze.perception.weight_init import make_module_init_normc
  from maze.utils.bcolors import BColors
label_desc: Use image node_id 5 for calling the TemplateModelComposer obj's underlying member method code with example usage: obj.template_value_net(observation_space, shared_embedding_keys, perception_net) and returns: net