class_docstr: Abstract baseclass and interface definitions for model composers.
  
  Model composers encapsulate the set of policy and critic networks along with the distribution mapper.
  
  :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.
class_docstr_tok: ["Abstract","baseclass","and","interface","definitions","for","model","composers",".","Model","composers","encapsulate","the","set","of","policy","and","critic","networks","along","with","the","distribution","mapper",".",":","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","."]
docstr: Save the policies and critics as pdfs.
docstr_tok: ["Save","the","policies","and","critics","as","pdfs","."]
code: def save_models(self) -> None:
      """Save the policies and critics as pdfs."""
  
      def plot_inference_graphs(nets_type, nets):
          """Draw inference graphs."""
          for net_name, net_model in nets.items():
              if not os.path.exists(f"{nets_type}_{net_name}"):
                  if isinstance(net_model, InferenceBlock):
                      InferenceGraph(net_model).save(
                          f"{nets_type}_{net_name}", "./"
                      )
                  else:
                      children = net_model.children()
                      inference_blocks = list(
                          filter(
                              lambda cc: isinstance(cc, InferenceBlock),
                              children,
                          )
                      )
                      if len(inference_blocks) == 1:
                          InferenceGraph(inference_blocks[0]).save(
                              f"{nets_type}_{net_name}", "./"
                          )
                      elif len(inference_blocks) > 1:
                          BColors.print_colored(
                              f"More than one inference block was found for"
                              f" {nets_type}-{net_name}, please revisit the model and make "
                              f"sure only one is present",
                              BColors.WARNING,
                          )
                      else:
                          BColors.print_colored(
                              f"No inference block could be found in "
                              f"{nets_type}-{net_name}, thus no visual representation "
                              f"(of the model) could be created or saved",
                              BColors.WARNING,
                          )
  
      try:
          if self.policy:
              plot_inference_graphs("policy", self.policy.networks)
          if self.critic:
              plot_inference_graphs("critic", self.critic.networks)
      # a PermissionError might be raised when loading a model from a read-only experiment directory
      except (ImportError, PermissionError) as e:
          BColors.print_colored(
              f"Models graphical representation could not be saved: {e}",
              BColors.WARNING,
          )
  
file_path: maze/maze/perception/models/model_composer.py
imports: import os
  from abc import abstractmethod, ABC
  from typing import Dict, Optional
  import gym
  from maze.core.agent.torch_policy import TorchPolicy
  from maze.core.agent.torch_state_critic import TorchStateCritic
  from maze.core.env.structured_env import StepKeyType
  from maze.core.utils.factory import ConfigType
  from maze.core.utils.structured_env_utils import flat_structured_space
  from maze.distributions.distribution_mapper import DistributionMapper
  from maze.perception.blocks.inference import InferenceGraph, InferenceBlock
  from maze.utils.bcolors import BColors
label_desc: Use image node_id 6 for calling the BaseModelComposer obj's underlying member method code with example usage: obj.save_models() without return types