docstr: Build the whole network graph with Torch.FX.
code: def build_fx_graph(
      cls,
      model,
      dump_fx_graph=False,
      save_dumped_fx_graph="./model_fx_graph.json",
  ):
      """Build the whole network graph with Torch.FX."""
  
      network_fx_graph = {}
      success = True
      torch_version = str(torch.__version__)
      torch_version_major = int(torch_version.split(".")[0])
      torch_version_minor = int(torch_version.split(".")[1])
      try:
          torch_version_minimum = int(torch_version.split(".")[2])
      except ValueError:  # support the none standard version
          torch_version_minimum = torch_version.split(".")[2]
      if cls.__verbosity > 2:
          print(
              "[build_fx_graph] The torch version is: {}, version major is: {}, version minor is: {}, version minimum is: {}".format(
                  torch_version,
                  torch_version_major,
                  torch_version_minor,
                  torch_version_minimum,
              )
          )
  
      if torch_version_major >= 2 or (
          torch_version_major >= 1 and torch_version_minor >= 8
      ):
          if cls.__verbosity > 1:
              print("[build_fx_graph] The Torch.FX is supported.")
      else:  # Torch.FX is introduced in torch 1.8.0
          if cls.__verbosity >= 0:
              print(
                  "[build_fx_graph] The Torch.FX is not supported. So cannot build the Torch.FX graph."
              )
          success = False
          return network_fx_graph, success
  
      if cls.__verbosity > 2:
          print(
              "\n[build_fx_graph] Print the model structure with pure PyTorch function"
          )
          print(model)
  
      graph_module = cls.trace_and_print_raw_fx_graph(
          model, print_tabular=cls.__verbosity > 1
      )  # needs "tabulate" library
      if graph_module is None:
          success = False
          return network_fx_graph, success
  
      if cls.__verbosity > 0:
          print(
              "\n[build_fx_graph] Build the module name and type dictionary"
          )
  
      module_name_type_dict = {}
      module_name_group_conv_dict = {}
      module_name_C_dict = {}
      module_name_K_dict = {}
      for name, mod in model.named_modules():
          if cls.__verbosity > 1:
              print(
                  "[build_fx_graph] module_name: {}, module type: {}".format(
                      name, type(mod)
                  )
              )
          module_name_type_dict[name] = str(type(mod)).split("'")[1]
          try:
              module_name_C_dict[name] = str(mod.in_channels)
          except:
              try:
                  module_name_C_dict[name] = str(mod.in_features)
              except:
                  try:
                      module_name_C_dict[name] = str(mod.embed_dim)
                  except:
                      module_name_C_dict[name] = "None"
  
          try:
              module_name_K_dict[name] = str(mod.out_channels)
          except:
              try:
                  module_name_K_dict[name] = str(mod.out_features)
              except:
                  try:
                      module_name_K_dict[name] = str(mod.embed_dim)
                  except:
                      module_name_K_dict[name] = "None"
  
          try:
              module_name_group_conv_dict[name] = str(mod.groups)
              if cls.__verbosity > 1:
                  print(
                      "[build_fx_graph] this module has 'group' param with value: {}".format(
                          mod.groups
                      )
                  )
          except:
              module_name_group_conv_dict[name] = "None"
              continue
  
      # keep track of children and parents for each layer (could be call_module or call_function)
      if cls.__verbosity > 0:
          print(
              "\n[build_fx_graph] Print the children and parents relationship for each layer"
          )
      network_fx_graph = {}
      for node in graph_module.graph.nodes:
          if node.op == "placeholder":
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'input' node: {:}".format(
                          node.target
                      )
                  )
              continue
          elif node.op == "get_attr":
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'get_attr' node: {:}".format(
                          node.target
                      )
                  )
              node_parent, node_children = get_node_parent_children(
                  node
              )
              converted_node_name = convert_fx_node_name(node.target)
  
              network_fx_graph[converted_node_name] = {}
              network_fx_graph[converted_node_name][
                  "parents"
              ] = node_parent
              network_fx_graph[converted_node_name][
                  "children"
              ] = node_children
              network_fx_graph[converted_node_name][
                  "module_type"
              ] = "get_attr"
              network_fx_graph[converted_node_name][
                  "groups_param"
              ] = "None"
  
              # inspired by https://pytorch.org/docs/stable/fx.html
              def fetch_attr(target: str, mod):
                  target_atoms = target.split(".")
                  attr_itr = mod
                  for i, atom in enumerate(target_atoms):
                      if not hasattr(attr_itr, atom):
                          raise RuntimeError(
                              f"Node referenced nonexistant target {'.'.join(target_atoms[:i])}"
                          )
                      attr_itr = getattr(attr_itr, atom)
                  return attr_itr
  
              attr = fetch_attr(node.target, graph_module)
              network_fx_graph[converted_node_name]["C_param"] = 1
              network_fx_graph[converted_node_name]["K_param"] = -1
              network_fx_graph[converted_node_name]["attr"] = attr
  
          elif (
              node.op == "call_function"
          ):  # e.g. 'adaptive.avg.pool2d', 'add', 'cat', 'flatten', 'floordiv', 'getattr', 'getitem', 'hardsigmoid', 'mean', 'mul', 'relu', 'transpose'
              node_parent, node_children = get_node_parent_children(
                  node
              )
              converted_node_name = convert_fx_node_name(node.name)
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'call_function' node: {:}, its parent list: {:}, its children list: {:}".format(
                          converted_node_name,
                          node_parent,
                          node_children,
                      )
                  )
              network_fx_graph[converted_node_name] = {}
              network_fx_graph[converted_node_name][
                  "parents"
              ] = node_parent
              network_fx_graph[converted_node_name][
                  "children"
              ] = node_children
              network_fx_graph[converted_node_name][
                  "fx_op"
              ] = "call_function"
  
              ### "convert" some ops to modules
  
              # concatenating along K can be handled by reducing the size of the childrens' C appropriately
              # see fixup_concats, if no dim arg, default is 0 (handled automatically)
              if (
                  node.target == torch.cat
                  and len(node.args) > 1
                  and node.args[1] == 1
              ):
                  network_fx_graph[converted_node_name][
                      "fx_op"
                  ] = "call_module"
                  network_fx_graph[converted_node_name][
                      "module_type"
                  ] = "concat"
                  network_fx_graph[converted_node_name][
                      "groups_param"
                  ] = "N/A"  # just need placeholders
                  network_fx_graph[converted_node_name][
                      "C_param"
                  ] = "N/A"
                  network_fx_graph[converted_node_name][
                      "K_param"
                  ] = "N/A"
  
          elif (
              node.op == "call_method"
          ):  # e.g. 'chunk', 'contiguous', 'mean', 'size', 'unsqueeze', 'view'
              node_parent, node_children = get_node_parent_children(
                  node
              )
              converted_node_name = convert_fx_node_name(node.name)
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'call_method' node: {:}, its parent list: {:}, its children list: {:}".format(
                          converted_node_name,
                          node_parent,
                          node_children,
                      )
                  )
              network_fx_graph[converted_node_name] = {}
              network_fx_graph[converted_node_name][
                  "parents"
              ] = node_parent
              network_fx_graph[converted_node_name][
                  "children"
              ] = node_children
              network_fx_graph[converted_node_name][
                  "fx_op"
              ] = "call_method"
              continue
  
          elif node.op == "call_module":
              node_parent, node_children = get_node_parent_children(
                  node
              )
              converted_node_name = convert_fx_node_name(node.name)
              # check whether the converted_node_name is same as node.target, especially for ReLU case
              if converted_node_name != node.target:
                  if cls.__verbosity > 2:
                      print(
                          "[build_fx_graph][warning] The target name from Torch.FX is '{:}', the manually converted node name is '{:}', not the same one, choose the converted node name".format(
                              node.target, converted_node_name
                          )
                      )
  
              # assume the modules share the same target name have the same type, because converted_node_name may not be obtained by model.named_modules(), like some ReLU (defined in forward function)
              node_type = module_name_type_dict[node.target]
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'call_module' node: {:}, its parent list: {:}, its children list: {:}, its type: {:}".format(
                          converted_node_name,
                          node_parent,
                          node_children,
                          node_type,
                      )
                  )
              network_fx_graph[converted_node_name] = {}
              network_fx_graph[converted_node_name][
                  "parents"
              ] = node_parent
              network_fx_graph[converted_node_name][
                  "children"
              ] = node_children
              network_fx_graph[converted_node_name][
                  "fx_op"
              ] = "call_module"
              network_fx_graph[converted_node_name][
                  "module_type"
              ] = node_type
              network_fx_graph[converted_node_name][
                  "groups_param"
              ] = module_name_group_conv_dict[node.target]
              network_fx_graph[converted_node_name][
                  "C_param"
              ] = module_name_C_dict[node.target]
              network_fx_graph[converted_node_name][
                  "K_param"
              ] = module_name_K_dict[node.target]
  
          elif node.op == "output":
              if cls.__verbosity > 2:
                  print(
                      "[build_fx_graph] This is the 'output' node: {:}".format(
                          node.target
                      )
                  )
              continue
  
      if dump_fx_graph:
          if cls.__verbosity > 0:
              print(
                  "\n[build_fx_graph] Dump the overall dict for children and parents relationship into JSON file"
              )
          cls.save_graph_to_json(
              network_fx_graph,
              save_dumped_graph_path_with_name=save_dumped_fx_graph,
          )
  
      return network_fx_graph, success
  
imports: import os
  import torch
  import json
  import string
  import time
  import numpy
  import sys
  import builtins
  import io
label_desc: Use image node_id 39 for calling the Permutation obj's underlying member method code with example usage: obj.build_fx_graph(cls, model, dump_fx_graph, save_dumped_fx_graph) and returns: network_fx_graph,  success, network_fx_graph,  success, network_fx_graph,  success, attr_itr