class_docstr: Execute an FX graph Node-by-Node with meta tensor and
  record the memory usage, FLOPs, and type of the result
  into the corresponding node.
  
  Usage:
      BATCH_SIZE = 2
      DIM_IN = 4
      DIM_HIDDEN = 16
      DIM_OUT = 16
      model = torch.nn.Sequential(
          torch.nn.Linear(DIM_IN, DIM_HIDDEN),
          torch.nn.Linear(DIM_HIDDEN, DIM_OUT),
          )
      input_sample = torch.rand(BATCH_SIZE, DIM_IN)
      gm = symbolic_trace(model)
      interp = MetaInfoProp(gm)
      interp.run(input_sample)
      print(interp.summary(format='kb'))    # don't panic if some statistics are 0.00 MB
  
  
      # output of above code is
          Op type       Op    Forward FLOPs    Backward FLOPs    FWD_OUT    FWD_TMP    BWD_OUT    BWD_TMP
      -----------  -------  ---------------  ----------------  ---------  ---------  ---------  ---------
      placeholder  input_1          0 FLOPs           0 FLOPs    0.00 KB    0.00 KB    0.00 KB    0.00 KB
      call_module       _0        128 FLOPs         288 FLOPs    0.12 KB    0.00 KB    0.34 KB    0.00 KB
      call_module       _1        512 FLOPs       1,056 FLOPs    0.12 KB    0.00 KB    1.19 KB    0.00 KB
           output   output          0 FLOPs           0 FLOPs    0.00 KB    0.00 KB    0.00 KB    0.00 KB
  Args:
       module (GraphModule): The module to be executed
docstr: Run a specific node ``n`` and return the result.
  Calls into placeholder, get_attr, call_function,
  call_method, call_module, or output depending
  on ``node.op``
  
  Args:
      n (Node): The Node to execute
  
  Returns:
      Any: The result of executing ``n``
docstr_tok: ["Run","a","specific","node","``","n","``","and","return","the","result",".","Calls","into","placeholder",",","get_attr",",","call_function",",","call_method",",","call_module",",","or","output","depending","on","``","node.op","``","Args",":","n","(","Node",")",":","The","Node","to","execute","Returns",":","Any",":","The","result","of","executing","``","n","``"]
code: def run_node(self, n: Node) -> Any:
      """
      Run a specific node ``n`` and return the result.
      Calls into placeholder, get_attr, call_function,
      call_method, call_module, or output depending
      on ``node.op``
  
      Args:
          n (Node): The Node to execute
  
      Returns:
          Any: The result of executing ``n``
      """
      self._is_proped = True
      result, meta_info = super().run_node(n)
  
      def extract_tensor_meta(obj):
          if isinstance(obj, torch.Tensor):
              return _extract_tensor_metadata(obj)
          else:
              return TensorMetadata(None, None, False, None, 0, False)
  
      tensor_meta = tree_map(extract_tensor_meta, result)
      n.meta["tensor_meta"] = tensor_meta
      n.meta = {
          **n.meta,
          **asdict(meta_info),
      }  # extend MetaInfo to `n.meta`
      # TODO: the attribute node_size should be removed in the future
      setattr(
          n,
          "node_size",
          activation_size(n.meta.get("fwd_out", 0))
          + activation_size(n.meta.get("fwd_tmp", 0)),
      )
      setattr(n, "fwd_flop", n.meta.get("fwd_flop", 0))
      setattr(n, "bwd_flop", n.meta.get("bwd_flop", 0))
      n.meta["type"] = type(result)
  
      # retain the autograd graph
      for param in self.module.parameters():
          param.grad = None
  
      return result
  
imports: from dataclasses import asdict
  from typing import Any, Dict, List, NamedTuple, Tuple
  import torch
  import torch.fx
  from torch.fx.node import Argument, Node, Target
  from torch.utils._pytree import tree_map
  from colossalai.fx._compatibility import compatibility, is_compatible_with_meta
  from colossalai.fx.profiler import GraphInfo, activation_size, calculate_fwd_in, calculate_fwd_out, calculate_fwd_tmp, profile_function, profile_method, profile_module
label_desc: Use image node_id 1 for calling the MetaInfoProp obj's underlying member method code with example usage: obj.run_node(n) and returns: result, _extract_tensor_metadata, TensorMetadata