code: def convert_variables_to_constants(
      sess,
      input_graph_def,
      output_node_names,
      variable_names_whitelist=None,
      variable_names_blacklist=None,
  ):
      """Replaces all the variables in a graph with constants of the same values.
      If you have a trained graph containing Variable ops, it can be convenient to
      convert them all to Const ops holding the same values. This makes it possible
      to describe the network fully with a single GraphDef file, and allows the
      removal of a lot of ops related to loading and saving the variables.
      Args:
        sess: Active TensorFlow session containing the variables.
        input_graph_def: GraphDef object holding the network.
        output_node_names: List of name strings for the result nodes of the graph.
        variable_names_whitelist: The set of variable names to convert (by default,
                                  all variables are converted).
        variable_names_blacklist: The set of variable names to omit converting
                                  to constants.
      Returns:
        GraphDef containing a simplified version of the original.
      """
  
      def trace_back_find_variable(origin_name, name_to_nodes):
          nodes_in_path = set()
          control_ops = ["Enter", "Exit", "NextIteration", "Switch"]
  
          current_name = origin_name
          while name_to_nodes[current_name].op != "VarHandleOp":
              nodes_in_path.add(current_name)
              current_node = name_to_nodes[current_name]
              op_name = current_node.op
              if op_name in control_ops or op_name == "Identity":
                  curr_input_name = _node_name(current_node.input[0])
              else:
                  invalidInputError(
                      False,
                      "Op type %s should not be in the path "
                      "between ReadVariableOp and VarHandleOp"
                      % current_node.op,
                  )
              current_name = curr_input_name
  
          return current_name, nodes_in_path
  
      def create_const_op(node_name, dtype, data, data_shape=None):
          """Creates a Const op."""
          output_node = node_def_pb2.NodeDef()
          output_node.op = "Const"
          output_node.name = node_name
          output_node.attr["dtype"].CopyFrom(dtype)
          output_node.attr["value"].CopyFrom(
              attr_value_pb2.AttrValue(
                  tensor=tensor_util.make_tensor_proto(
                      data, dtype=dtype.type, shape=data_shape
                  )
              )
          )
          return output_node
  
      # This graph only includes the nodes needed to evaluate the output nodes, and
      # removes unneeded nodes like those involved in saving and assignment.
      inference_graph = extract_sub_graph(
          input_graph_def, output_node_names
      )
  
      # Identify the ops in the graph.
      map_name_to_node = {
          node.name: node for node in inference_graph.node
      }
  
      # Get list of variables.
      variable_names = []
      variable_dict_names = []
      resource_identity_types = {}
      read_variable_op_types = {}
      for node in inference_graph.node:
          if node.op in ["Variable", "VariableV2", "VarHandleOp"]:
              variable_name = node.name
              if (
                  variable_names_whitelist is not None
                  and variable_name not in variable_names_whitelist
              ) or (
                  variable_names_blacklist is not None
                  and variable_name in variable_names_blacklist
              ):
                  continue
              variable_dict_names.append(variable_name)
              if node.op == "VarHandleOp":
                  variable_names.append(
                      variable_name + "/Read/ReadVariableOp:0"
                  )
              else:
                  variable_names.append(variable_name + ":0")
          elif node.op in [
              "ReadVariableOp",
              "ResourceGather",
              "VariableShape",
          ]:
              # There can be one or more Identity or control flow ops in between the ReadVariableOp
              # and VarHandleOp.  Store them with the associated dtypes.
              source_op_name, nodes_in_path = trace_back_find_variable(
                  _node_name(node.input[0]), map_name_to_node
              )
              dtype = map_name_to_node[source_op_name].attr["dtype"]
              for node_name in nodes_in_path:
                  resource_identity_types[node_name] = dtype
              read_variable_op_types[node.name] = dtype
  
      # Gets map of variables and the associated data.
      if variable_names:
          returned_variables = sess.run(variable_names)
      else:
          returned_variables = []
      variables_data_map = dict(
          zip(variable_dict_names, returned_variables)
      )
      logging.info("Froze %d variables.", len(returned_variables))
  
      # Reconstruct the graph with constants in place of variables.
      output_graph_def = graph_pb2.GraphDef()
      how_many_converted = 0
      for input_node in inference_graph.node:
          output_node = node_def_pb2.NodeDef()
          if input_node.name in variables_data_map:
              data = variables_data_map[input_node.name]
              output_node = create_const_op(
                  input_node.name,
                  input_node.attr["dtype"],
                  data,
                  data.shape,
              )
              how_many_converted += 1
          elif input_node.name in resource_identity_types:
              # Converts the Identities of type RESOURCE_DT to the appropriate type
              # based on the input they are referencing.
              output_node.CopyFrom(input_node)
              output_node.attr["T"].CopyFrom(
                  resource_identity_types[input_node.name]
              )
          elif input_node.op == "ReadVariableOp":
              # The first branch converts all VarHandleOps of ResourceVariables to
              # constants, so we need to convert the associated ReadVariableOps to
              # Identity ops.
              output_node.op = "Identity"
              output_node.name = input_node.name
              output_node.input.extend([input_node.input[0]])
              output_node.attr["T"].CopyFrom(input_node.attr["dtype"])
              if "_class" in input_node.attr:
                  output_node.attr["_class"].CopyFrom(
                      input_node.attr["_class"]
                  )
          elif input_node.op == "ResourceGather":
              # The first branch converts all VarHandleOps of ResourceGather to
              # constants, so we need to convert the associated ResourceGather to Gather
              # ops with a Const axis feeding into it.
              if input_node.attr["batch_dims"].i != 0:
                  invalidInputError(
                      False,
                      "batch_dims != 0 is not supported by freeze_graph.",
                  )
              axis_data = input_node.attr["batch_dims"].i
              axis_node_name = input_node.name + "/axis"
              axis_dtype = input_node.attr["Tindices"]
              output_axis_node = create_const_op(
                  axis_node_name, axis_dtype, axis_data
              )
              output_graph_def.node.extend([output_axis_node])
  
              output_node.op = "GatherV2"
              output_node.name = input_node.name
              output_node.input.extend(
                  [
                      input_node.input[0],
                      input_node.input[1],
                      axis_node_name,
                  ]
              )
              output_node.attr["Tparams"].CopyFrom(
                  input_node.attr["dtype"]
              )
              output_node.attr["Tindices"].CopyFrom(
                  input_node.attr["Tindices"]
              )
              output_node.attr["Taxis"].CopyFrom(axis_dtype)
              if "_class" in input_node.attr:
                  output_node.attr["_class"].CopyFrom(
                      input_node.attr["_class"]
                  )
          elif input_node.op == "VariableShape":
              output_node.op = "Shape"
              output_node.name = input_node.name
              output_node.input.extend([input_node.input[0]])
              output_node.attr["T"].CopyFrom(
                  read_variable_op_types[input_node.name]
              )
              output_node.attr["out_type"].CopyFrom(
                  input_node.attr["out_type"]
              )
          else:
              output_node.CopyFrom(input_node)
          output_graph_def.node.extend([output_node])
  
      output_graph_def.library.CopyFrom(inference_graph.library)
      logging.info(
          "Converted %d variables to const ops.", how_many_converted
      )
      return output_graph_def
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import copy
  import re
  import six
  from tensorflow.core.framework import attr_value_pb2
  from tensorflow.core.framework import graph_pb2
  from tensorflow.core.framework import node_def_pb2
  from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import tensor_util
  from tensorflow.python.platform import tf_logging
  from tensorflow.python.util import deprecation
  from tensorflow.python.util.tf_export import tf_export
  from bigdl.dllib.utils.log4Error import *
label_desc: Use image node_id 9 for calling a global function with example usage: convert_variables_to_constants(sess, input_graph_def, output_node_names, variable_names_whitelist, variable_names_blacklist) and returns: output_graph_def, current_name,  nodes_in_path, output_node