code: def export_tf(
      sess,
      folder,
      inputs,
      outputs,
      generate_backward=False,
      allow_non_differentiable_input=True,
  ):
      """
      Export the frozen tensorflow graph as well as the inputs/outputs information
      to the folder for inference.
  
      This function will
      1. freeze the graph (replace all variables with constants)
      2. strip all unused node as specified by inputs and outputs
      3. add placeholder nodes as needed
      4. write the frozen graph and inputs/outputs names to the folder
  
      Note: There should not be any queuing operation between inputs and outputs
  
      :param sess: tensorflow session holding the variables to be saved
      :param folder: the folder where graph file and inputs/outputs information are saved
      :param inputs: a list of tensorflow tensors that will be fed during inference
      :param outputs: a list of tensorflow tensors that will be fetched during inference
      :return:
      """
  
      from tensorflow.python.platform import gfile
      import tensorflow as tf
  
      output_node_names = list({t.op.name for t in outputs})
  
      graph_def = sess.graph_def
      graph = sess.graph
  
      # clear device specifications
      for node in graph_def.node:
          node.device = ""
  
      non_placeholder_input_names = []
      type_enums = []
      for input_tensor in inputs:
          if input_tensor.op.type not in [
              "Placeholder",
              "PlaceholderWithDefault",
          ]:
              non_placeholder_input_names.append(input_tensor.name)
              type_enums.append(input_tensor.dtype.as_datatype_enum)
  
      output_names = [o.name for o in outputs]
  
      all_variables = graph.get_collection(
          tf.GraphKeys.TRAINABLE_VARIABLES
      )
  
      import bigdl.dllib.utils.tf_graph_util as graph_util
  
      # freeze graph
      frozen_graph_def = graph_util.convert_variables_to_constants(
          sess, graph_def, output_node_names
      )
  
      optimized_graph_def, old_names2new = strip_unused(
          frozen_graph_def,
          non_placeholder_input_names,
          output_names,
          type_enums,
      )
  
      nodes_of_graph = []
      for node in optimized_graph_def.node:
          nodes_of_graph.append(node.name + ":0")
      nodes_of_graph_set = set(nodes_of_graph)
  
      new_input_names = []
      error_input_nodes = []
      for t in inputs:
          if t.name in old_names2new:
              if old_names2new[t.name] not in nodes_of_graph_set:
                  error_input_nodes.append('"' + (t.name)[0:-2] + '"')
              new_input_names.append(old_names2new[t.name])
          else:
              if t.name not in nodes_of_graph_set:
                  error_input_nodes.append('"' + (t.name)[0:-2] + '"')
              new_input_names.append(t.name)
  
      if error_input_nodes:
          error_nodes_name = " and ".join(error_input_nodes)
          invalidInputError(
              False,
              "Node %s doesn't exist in the graph"
              % str(error_nodes_name),
          )
  
      # check all placeholder in the graph are listed in the new_input_names:
      new_input_nodes = {name.split(":")[0] for name in new_input_names}
      for node in optimized_graph_def.node:
          if (
              node.op == "Placeholder"
              and node.name not in new_input_nodes
          ):
              invalidInputError(
                  False,
                  "Node %s is a Placeholder but not listed in inputs, inputs are %s"
                  % (node.name, inputs),
              )
  
      temp_tensors = None
      used_variables = []
      grad_variables = []
      grad_inputs = []
      if generate_backward:
          nodes = set([n.name for n in optimized_graph_def.node])
          for v in all_variables:
              if v.op.name in nodes:
                  used_variables.append(v.name)
  
          with tf.Graph().as_default() as g:
              tf.import_graph_def(optimized_graph_def, name="")
              output_tensors = [
                  g.get_tensor_by_name(x) for x in output_names
              ]
              grad_output_placeholders = [
                  tf.placeholder(
                      dtype=x.dtype,
                      name=x.name.split(":")[0] + "_grad",
                      shape=x.shape,
                  )
                  for x in output_tensors
              ]
  
              variables = [
                  g.get_tensor_by_name(x) for x in used_variables
              ]
  
              inputs = [
                  g.get_tensor_by_name(x) for x in new_input_names
              ]
              grads = tf.gradients(
                  output_tensors,
                  variables + inputs,
                  grad_ys=grad_output_placeholders,
              )
  
              grads = [process_grad(grad) for grad in grads]
  
              temp_tensors = _find_temp_tensors(grads, nodes)
  
              grad_variables = [
                  x.name for x in grads[0 : len(variables)]
              ]
  
              grad_inputs = []
              for i in range(len(variables), len(grads)):
                  grad = grads[i]
                  if grad is not None:
                      grad_inputs.append(grad.name)
                  else:
                      # if input is not differentiable, we just return zero
                      input_tensor = inputs[i - len(variables)]
                      if allow_non_differentiable_input:
                          zero_grad = tf.zeros(
                              shape=tf.shape(input_tensor)
                          )
                          grad_inputs.append(zero_grad.name)
                      else:
                          invalidInputError(
                              False,
                              "input tensor: %s is not differentiable"
                              % input_tensor.name,
                          )
  
              optimized_graph_def = g.as_graph_def()
  
      if not os.path.isdir(folder):
          os.makedirs(folder)
  
      with gfile.GFile(
          os.path.join(folder, "frozen_inference_graph.pb"), "wb"
      ) as f:
          f.write(optimized_graph_def.SerializeToString())
  
      meta = {
          "input_names": new_input_names,
          "output_names": output_names,
      }
  
      if generate_backward:
          meta["temp_tensors"] = list(temp_tensors)
          meta["variables"] = used_variables
          meta["grad_variables"] = grad_variables
          meta["grad_inputs"] = grad_inputs
  
      with open(os.path.join(folder, "graph_meta.json"), "w") as f:
          f.write(json.dumps(meta))
  
file_path: BigDL/python/dllib/src/bigdl/dllib/utils/tf.py
imports: import os
  import json
  import copy
  import tempfile
  import re
  import shutil
  from bigdl.dllib.utils.file_utils import put_local_file_to_remote, get_remote_file_to_local, get_file_list, is_local_path
  from bigdl.dllib.utils.log4Error import *
label_desc: Use image node_id 4 for calling a global function with example usage: export_tf(sess, folder, inputs, outputs, generate_backward, allow_non_differentiable_input) without return types