parameters: (self, graph, func, var_node, op)
return_statement: return target_out_node
docstring: Insert a tmp program that returned by func between var_node and op.
  
          Args:
              graph(IrGraph): target graph to insert tmp program.
              func(Function): function to define a tmp program
              var_node(IrVarNode): node in target graph.
              op(IrOpNode): op in target graph.
          Returns:
              op's new input that replaces var_node
docstring_summary: Insert a tmp program that returned by func between var_node and op.
docstring_tokens: Insert a tmp program that returned by func between var_node and op .
function: def _insert_func(self, graph, func, var_node, op):
          """
          Insert a tmp program that returned by func between var_node and op.
  
          Args:
              graph(IrGraph): target graph to insert tmp program.
              func(Function): function to define a tmp program
              var_node(IrVarNode): node in target graph.
              op(IrOpNode): op in target graph.
          Returns:
              op's new input that replaces var_node
          """
          tmp_program = Program()
          startup_program = Program()
          with program_guard(tmp_program, startup_program):
              with unique_name.guard(var_node.name() + "_"):
                  in_node = data(
                      var_node.name() + '_tmp_input',
                      shape=var_node.shape(),
                      dtype='float32')
                  out_node = func(in_node)
                  graph.out_node_mapping_table[out_node.name] = var_node.name()
                  # loss shape must be 1 when minimize
                  loss = mean(out_node)
                  if not graph._for_test:
                      assert self._optimizer, "optimizer_func must be set when graph is test graph"
                      in_node.stop_gradient = False
                      optimizer = self._optimizer()
                      optimizer.minimize(loss)
          with scope_guard(self._scope):
              self._exe.run(startup_program)
  
          tmp_graph = IrGraph(
              core.Graph(tmp_program.desc), for_test=graph._for_test)
          in_node = tmp_graph._find_node_by_name(tmp_graph.all_var_nodes(),
                                                 in_node.name)
          out_node = tmp_graph._find_node_by_name(tmp_graph.all_var_nodes(),
                                                  out_node.name)
  
          in_node_params = []
          in_op_node = []
          # copy tmp graph to graph, after that, we can insert tmp graph's copy to graph.
          for node in tmp_graph.all_var_nodes():
              if node.inputs == [] and node.persistable():
                  in_node_params.append(node)
          for node in tmp_graph.all_op_nodes():
              if node.inputs == []:
                  in_op_node.append(node)
          for node in in_node.outputs:
              self._copy_graph(graph, tmp_graph, node)
          for node in in_node_params:
              for op_node in node.outputs:
                  self._copy_graph(graph, tmp_graph, op_node)
          for node in in_op_node:
              self._copy_graph(graph, tmp_graph, node)
  
          target_in_node = graph._find_node_by_name(graph.all_var_nodes(),
                                                    in_node.name())
          target_out_node = graph._find_node_by_name(graph.all_var_nodes(),
                                                     out_node.name())
          loss_node = graph._find_node_by_name(graph.all_var_nodes(), loss.name)
          outputs = target_in_node.outputs
          for node in outputs:
              graph.update_input_link(target_in_node, var_node, node)
          graph.update_input_link(var_node, target_out_node, op)
  
          # update grad
          if not graph._for_test:
              op_out = op.outputs[0]
              op_out_grad = graph._find_node_by_name(graph.all_var_nodes(),
                                                     op_out.name() + "@GRAD")
              # find op's gradient op, such as conv2d_grad
              op_grad = op_out_grad.outputs[0]
              target_out_grad_node = graph._find_node_by_name(
                  graph.all_var_nodes(), target_out_node.name() + "@GRAD")
              in_node_grad = graph._find_node_by_name(
                  graph.all_var_nodes(), target_in_node.name() + "@GRAD")
              in_node_grad_op = in_node_grad.inputs
              # update op_grad's input
              graph.update_input_link(var_node, target_out_node, op_grad)
  
              op_grad_out = None
              # find var_node's corresponding grad node
              for node in op_grad.outputs:
                  if var_node.name() + "@GRAD" in node.name():
                      op_grad_out = node
              # update op_grad's output
              if op_grad_out is not None:
                  graph.update_output_link(op_grad_out, target_out_grad_node,
                                           op_grad)
              else:
                  graph.link_to(op_grad, target_out_grad_node)
  
              for node in in_node_grad_op:
                  graph.update_input_link(target_in_node, var_node, node)
                  if op_grad_out:
                      graph.update_output_link(in_node_grad, op_grad_out, node)
              # remove useless nodes
              mean_grad = target_out_grad_node.inputs[0]
              mean_out_grad = mean_grad.inputs[0]
              fill_constant_node = mean_out_grad.inputs[0]
              graph.safe_remove_nodes(mean_grad)
              graph.safe_remove_nodes(mean_out_grad)
              graph.safe_remove_nodes(fill_constant_node)
              graph.safe_remove_nodes(in_node_grad)
  
          graph.safe_remove_nodes(loss_node.inputs[0])
          graph.safe_remove_nodes(loss_node)
          graph.safe_remove_nodes(target_in_node)
          return target_out_node
function_tokens: def _insert_func ( self , graph , func , var_node , op ) : tmp_program = Program ( ) startup_program = Program ( ) with program_guard ( tmp_program , startup_program ) : with unique_name . guard ( var_node . name ( ) + "_" ) : in_node = data ( var_node . name ( ) + '_tmp_input' , shape = var_node . shape ( ) , dtype = 'float32' ) out_node = func ( in_node ) graph . out_node_mapping_table [ out_node . name ] = var_node . name ( ) # loss shape must be 1 when minimize loss = mean ( out_node ) if not graph . _for_test : assert self . _optimizer , "optimizer_func must be set when graph is test graph" in_node . stop_gradient = False optimizer = self . _optimizer ( ) optimizer . minimize ( loss ) with scope_guard ( self . _scope ) : self . _exe . run ( startup_program ) tmp_graph = IrGraph ( core . Graph ( tmp_program . desc ) , for_test = graph . _for_test ) in_node = tmp_graph . _find_node_by_name ( tmp_graph . all_var_nodes ( ) , in_node . name ) out_node = tmp_graph . _find_node_by_name ( tmp_graph . all_var_nodes ( ) , out_node . name ) in_node_params = [ ] in_op_node = [ ] # copy tmp graph to graph, after that, we can insert tmp graph's copy to graph. for node in tmp_graph . all_var_nodes ( ) : if node . inputs == [ ] and node . persistable ( ) : in_node_params . append ( node ) for node in tmp_graph . all_op_nodes ( ) : if node . inputs == [ ] : in_op_node . append ( node ) for node in in_node . outputs : self . _copy_graph ( graph , tmp_graph , node ) for node in in_node_params : for op_node in node . outputs : self . _copy_graph ( graph , tmp_graph , op_node ) for node in in_op_node : self . _copy_graph ( graph , tmp_graph , node ) target_in_node = graph . _find_node_by_name ( graph . all_var_nodes ( ) , in_node . name ( ) ) target_out_node = graph . _find_node_by_name ( graph . all_var_nodes ( ) , out_node . name ( ) ) loss_node = graph . _find_node_by_name ( graph . all_var_nodes ( ) , loss . name ) outputs = target_in_node . outputs for node in outputs : graph . update_input_link ( target_in_node , var_node , node ) graph . update_input_link ( var_node , target_out_node , op ) # update grad if not graph . _for_test : op_out = op . outputs [ 0 ] op_out_grad = graph . _find_node_by_name ( graph . all_var_nodes ( ) , op_out . name ( ) + "@GRAD" ) # find op's gradient op, such as conv2d_grad op_grad = op_out_grad . outputs [ 0 ] target_out_grad_node = graph . _find_node_by_name ( graph . all_var_nodes ( ) , target_out_node . name ( ) + "@GRAD" ) in_node_grad = graph . _find_node_by_name ( graph . all_var_nodes ( ) , target_in_node . name ( ) + "@GRAD" ) in_node_grad_op = in_node_grad . inputs # update op_grad's input graph . update_input_link ( var_node , target_out_node , op_grad ) op_grad_out = None # find var_node's corresponding grad node for node in op_grad . outputs : if var_node . name ( ) + "@GRAD" in node . name ( ) : op_grad_out = node # update op_grad's output if op_grad_out is not None : graph . update_output_link ( op_grad_out , target_out_grad_node , op_grad ) else : graph . link_to ( op_grad , target_out_grad_node ) for node in in_node_grad_op : graph . update_input_link ( target_in_node , var_node , node ) if op_grad_out : graph . update_output_link ( in_node_grad , op_grad_out , node ) # remove useless nodes mean_grad = target_out_grad_node . inputs [ 0 ] mean_out_grad = mean_grad . inputs [ 0 ] fill_constant_node = mean_out_grad . inputs [ 0 ] graph . safe_remove_nodes ( mean_grad ) graph . safe_remove_nodes ( mean_out_grad ) graph . safe_remove_nodes ( fill_constant_node ) graph . safe_remove_nodes ( in_node_grad ) graph . safe_remove_nodes ( loss_node . inputs [ 0 ] ) graph . safe_remove_nodes ( loss_node ) graph . safe_remove_nodes ( target_in_node ) return target_out_node