class_docstr: Models a perception module inference graph.
          Conditions on using the InferenceGraph object:
              1. All keys of the perception_blocks dictionary have to be unique
              2. All out_keys used when creating the blocks have to be unique
              3. All out_keys of a given block have to be sub-strings of the blocks key in the perception_blocks dict
  
  :param inference_block: An inference perception block to build the graph for.
class_docstr_tok: ["Models","a","perception","module","inference","graph",".","Conditions","on","using","the","InferenceGraph","object",":","1",".","All","keys","of","the","perception_blocks","dictionary","have","to","be","unique","2",".","All","out_keys","used","when","creating","the","blocks","have","to","be","unique","3",".","All","out_keys","of","a","given","block","have","to","be","sub-strings","of","the","blocks","key","in","the","perception_blocks","dict",":","param","inference_block",":","An","inference","perception","block","to","build","the","graph","for","."]
docstr: Recursively compiles the perception inference graph.
  
  :param out_keys: The out keys to start depth search from.
  :param parent: The parent key we are coming from.
docstr_tok: ["Recursively","compiles","the","perception","inference","graph",".",":","param","out_keys",":","The","out","keys","to","start","depth","search","from",".",":","param","parent",":","The","parent","key","we","are","coming","from","."]
code: def _build_inference_graph(
      self, out_keys: List[str], parent: Optional[str] = None
  ) -> None:
      """Recursively compiles the perception inference graph.
  
      :param out_keys: The out keys to start depth search from.
      :param parent: The parent key we are coming from.
      """
      # iterate out keys
      for out_key in out_keys:
          # Retrieve the key (w.r.t. the perception_blocks dict) of the block the given output (out_key) was computed
          #   in
          block_key = self._get_block_name_for_out_key(out_key)
  
          # Add output node if not present in the graph
          created_output_node = False
          if out_key not in self.node_graph.nodes():
              if block_key in self.perception_blocks:
                  out_index = self.perception_blocks[
                      block_key
                  ].out_keys.index(out_key)
                  shape = self.perception_blocks[
                      block_key
                  ].out_shapes()[out_index]
                  label = f"{out_key}\nshapes: {shape}"
              else:
                  shape = self.in_key_shapes[out_key]
                  label = f"{out_key}\nshape: {shape}"
  
              self.node_graph.add_node(
                  out_key, label=label, is_block=False, num_params=0
              )
              created_output_node = True
  
          # Add edge from parent to output node if parent is given (not network output)
          if parent is not None:
              self.node_graph.add_edge(out_key, parent)
  
          # Continue if the block key is in perception_blocks (that is if this is an input) and if the given
          #   output node is already in the node graph (that is if we join paths)
          if (
              block_key in self.perception_blocks
              and created_output_node
          ):
              # Add the block node to the graph
              curr_block, block_id = self._add_node_to_node_graph(
                  block_key
              )
              # Connect the block node to the output node
              self.node_graph.add_edge(block_id, out_key)
  
              # collect in key shapes
              for i, in_key in enumerate(curr_block.in_keys):
                  self.in_key_shapes[in_key] = curr_block.in_shapes[i]
  
              self._build_inference_graph(
                  out_keys=curr_block.in_keys, parent=block_id
              )
  
imports: import os
  import pickle
  from typing import Union, List, Dict, Optional, Sequence, Tuple
  import networkx
  import torch
  from matplotlib import pyplot
  from torch import nn
  from maze.core.annotations import override
  from maze.perception.blocks.base import PerceptionBlock
label_desc: Use image node_id 7 for calling the InferenceGraph obj's underlying member method code with example usage: obj._build_inference_graph(out_keys, parent) without return types