code: def infer_shape(outs, inputs, input_shapes):
      """
      Compute the shape of the outputs given the shape of the inputs of an PyTensor
      graph.
  
      We do it this way to avoid compiling the inner function just to get
      the shape. Changes to ShapeFeature could require changes in this function.
  
      """
      # We use a ShapeFeature because it has all the necessary logic
      # inside.  We don't use the full ShapeFeature interface, but we
      # let it initialize itself with an empty fgraph, otherwise we will
      # need to do it manually
      for inp, inp_shp in zip(inputs, input_shapes):
          if inp_shp is not None and len(inp_shp) != inp.type.ndim:
              assert len(inp_shp) == inp.type.ndim
  
      shape_feature = ShapeFeature()
      shape_feature.on_attach(FunctionGraph([], []))
  
      # Initialize shape_of with the input shapes
      for inp, inp_shp in zip(inputs, input_shapes):
          shape_feature.set_shape(inp, inp_shp)
  
      def local_traverse(out):
          """
          Go back in the graph, from out, adding computable shapes to shape_of.
  
          """
          if out in shape_feature.shape_of:
              # Its shape is already known
              return
          elif out.owner is None:
              # This is an input of the graph
              shape_feature.init_r(out)
          else:
              # Recurse over inputs
              for inp in out.owner.inputs:
                  if inp not in shape_feature.shape_of:
                      local_traverse(inp)
  
              # shape_feature.on_import does not actually use an fgraph
              # It will call infer_shape and set_shape appropriately
              dummy_fgraph = None
              shape_feature.on_import(
                  dummy_fgraph, out.owner, reason="dummy"
              )
  
      ret = []
      for o in outs:
          local_traverse(o)
          ret.append(shape_feature.shape_of[o])
      return ret
  
imports: from collections import OrderedDict
  from collections.abc import Sequence
  from copy import copy
  from functools import partial
  from typing import Optional, cast
  import pytensor.tensor
  from pytensor import function
  from pytensor.compile.function.pfunc import rebuild_collect_shared
  from pytensor.compile.mode import optdb
  from pytensor.compile.sharedvalue import SharedVariable
  from pytensor.configdefaults import config
  from pytensor.gradient import DisconnectedType, Rop, grad
  from pytensor.graph.basic import Apply, Constant, NominalVariable, Variable, graph_inputs, io_connection_pattern
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.null_type import NullType
  from pytensor.graph.op import HasInnerGraph, Op
  from pytensor.graph.replace import clone_replace
  from pytensor.graph.rewriting.basic import in2out, node_rewriter
  from pytensor.graph.utils import MissingInputError
  from pytensor.tensor.rewriting.shape import ShapeFeature
label_desc: Use image node_id 1 for calling a global function with example usage: infer_shape(outs, inputs, input_shapes) and returns: ret