parameters: (op_descs, block_idx)
return_statement: return op_descs
docstring: In backward part, an variable may be the output of more than one ops.
      And one op may yield its multiple outputs to the same variable.
      In these cases, the variable should be the accumulation of all the outputs.
      `sum_op`s are added to implement the accumulate.
docstring_summary: In backward part, an variable may be the output of more than one ops.
      And one op may yield its multiple outputs to the same variable.
      In these cases, the variable should be the accumulation of all the outputs.
      `sum_op`s are added to implement the accumulate.
docstring_tokens: In backward part an variable may be the output of more than one ops . And one op may yield its multiple outputs to the same variable . In these cases the variable should be the accumulation of all the outputs . sum_op s are added to implement the accumulate .
function: def _addup_repetitive_outputs_(op_descs, block_idx):
      """
      In backward part, an variable may be the output of more than one ops.
      And one op may yield its multiple outputs to the same variable.
      In these cases, the variable should be the accumulation of all the outputs.
      `sum_op`s are added to implement the accumulate.
      """
      _MAX_ADD_NUM_ = framework._global_flags()['FLAGS_max_inplace_grad_add']
      #pending_sum_ops = []
      pending_sum_ops = collections.OrderedDict()
      var_rename_count = collections.defaultdict(int)
      renamed_vars = collections.defaultdict(list)
      renamed_var_start_idx = collections.defaultdict(list)
      var_device = collections.defaultdict(str)
      for idx, op_desc in enumerate(op_descs):
          op_device_attr_name = core.op_proto_and_checker_maker.kOpDeviceAttrName(
          )
          op_device = ""
          if op_desc.has_attr(op_device_attr_name):
              op_device = op_desc.attr(op_device_attr_name)
          for var_name in op_desc.input_arg_names():
              if "@GRAD" not in var_name:
                  continue
              if len(renamed_vars[var_name]) > 1:
                  if len(renamed_vars[var_name]) > _MAX_ADD_NUM_:
                      _accumulate_gradients_by_sum_op_(var_name, renamed_vars,
                                                       pending_sum_ops, idx,
                                                       var_device[var_name])
                  else:
                      _accumulate_gradients_by_add_ops_(var_name, renamed_vars,
                                                        pending_sum_ops, idx,
                                                        var_device[var_name])
  
          for param_idx, param_name in enumerate(op_desc.output_names()):
              arg_names = op_desc.output(param_name)
              for arg_idx, var_name in enumerate(arg_names):
                  if "@GRAD" not in var_name:
                      continue
                  # if "@RENAME@" in var_name:
                  #    continue
                  if var_name == core.empty_var_name(
                  ) or var_name in op_desc.input_arg_names():
                      # empty variable or inplace op
                      continue
                  if len(renamed_vars[var_name]) == 0:
                      # it's the first time we get the variable
                      renamed_vars[var_name] = [var_name]
                      renamed_var_start_idx[var_name] = idx
                  else:
                      if len(renamed_vars[var_name]) == 1:
                          new_name = var_name + "@RENAME@block" + str(block_idx) + "@" + \
                              str(var_rename_count[var_name])
                          var_rename_count[var_name] += 1
                          # rename original var_name
                          renamed_vars[var_name][0] = new_name
                          # before change: _rename_arg_(op_descs, var_name,
                          #                             new_name, 0, idx)
                          # rename arg from idx of the first appearance
                          # in backward, not always from 0
                          _rename_arg_(op_descs, var_name, new_name,
                                       renamed_var_start_idx[var_name], idx)
                          _rename_arg_(pending_sum_ops, var_name, new_name)
  
                          for p in op_desc.output_names()[:param_idx]:
                              p_arg_names = op_desc.output(p)
                              if var_name in p_arg_names:
                                  op_desc.set_output(p, [
                                      new_name if x == var_name else x
                                      for x in p_arg_names
                                  ])
  
                          arg_names = [
                              new_name if x == var_name else x
                              for x in arg_names[:arg_idx]
                          ] + arg_names[arg_idx:]
  
                      new_name = var_name + "@RENAME@block" + str(block_idx) + "@" + \
                          str(var_rename_count[var_name])
                      var_rename_count[var_name] += 1
                      arg_names[arg_idx] = new_name
                      op_desc.set_output(param_name, arg_names)
                      renamed_vars[var_name].append(new_name)
                      # record the latest device
                      var_device[var_name] = op_device
  
      for var_name, inputs in six.iteritems(renamed_vars):
          if len(renamed_vars[var_name]) > 1:
              if len(renamed_vars[var_name]) > _MAX_ADD_NUM_:
                  _accumulate_gradients_by_sum_op_(
                      var_name, renamed_vars, pending_sum_ops,
                      len(op_descs), var_device[var_name])
              else:
                  _accumulate_gradients_by_add_ops_(
                      var_name, renamed_vars, pending_sum_ops,
                      len(op_descs), var_device[var_name])
  
      # sum_op descs are sorted according to their insert position
      for key, value in collections.OrderedDict(
              reversed(list(pending_sum_ops.items()))).items():
  
          # NOTE(zhiqiu): Since reversed, the idx of op_descs to be inserted will remains correct.
          # For example, [0, 1, 2], and we want to insert 'a' at idx 1, 'b' at idx 2, and the expected result is [0, 1, 'a', 2, 'b'].
          # If reversed, we first insert 'b' at idx 2, it becomes [0, 1, 2, 'b'], and then insert 'a' at idx 1, it becomes [0, 1, 'a', 2, 'b'].
          # If not reverse, we first insert 'a' at idx 1, it becomes [0, 1, 'a', 2], and then insert 'b' at idx 2, it becomes [0, 1, 'a', 'b', 2].
          idx = key
          for i, op in enumerate(value):
              op_descs.insert(idx + i, op)
  
      return op_descs
function_tokens: def _addup_repetitive_outputs_ ( op_descs , block_idx ) : _MAX_ADD_NUM_ = framework . _global_flags ( ) [ 'FLAGS_max_inplace_grad_add' ] #pending_sum_ops = [] pending_sum_ops = collections . OrderedDict ( ) var_rename_count = collections . defaultdict ( int ) renamed_vars = collections . defaultdict ( list ) renamed_var_start_idx = collections . defaultdict ( list ) var_device = collections . defaultdict ( str ) for idx , op_desc in enumerate ( op_descs ) : op_device_attr_name = core . op_proto_and_checker_maker . kOpDeviceAttrName ( ) op_device = "" if op_desc . has_attr ( op_device_attr_name ) : op_device = op_desc . attr ( op_device_attr_name ) for var_name in op_desc . input_arg_names ( ) : if "@GRAD" not in var_name : continue if len ( renamed_vars [ var_name ] ) > 1 : if len ( renamed_vars [ var_name ] ) > _MAX_ADD_NUM_ : _accumulate_gradients_by_sum_op_ ( var_name , renamed_vars , pending_sum_ops , idx , var_device [ var_name ] ) else : _accumulate_gradients_by_add_ops_ ( var_name , renamed_vars , pending_sum_ops , idx , var_device [ var_name ] ) for param_idx , param_name in enumerate ( op_desc . output_names ( ) ) : arg_names = op_desc . output ( param_name ) for arg_idx , var_name in enumerate ( arg_names ) : if "@GRAD" not in var_name : continue # if "@RENAME@" in var_name: #    continue if var_name == core . empty_var_name ( ) or var_name in op_desc . input_arg_names ( ) : # empty variable or inplace op continue if len ( renamed_vars [ var_name ] ) == 0 : # it's the first time we get the variable renamed_vars [ var_name ] = [ var_name ] renamed_var_start_idx [ var_name ] = idx else : if len ( renamed_vars [ var_name ] ) == 1 : new_name = var_name + "@RENAME@block" + str ( block_idx ) + "@" + str ( var_rename_count [ var_name ] ) var_rename_count [ var_name ] += 1 # rename original var_name renamed_vars [ var_name ] [ 0 ] = new_name # before change: _rename_arg_(op_descs, var_name, #                             new_name, 0, idx) # rename arg from idx of the first appearance # in backward, not always from 0 _rename_arg_ ( op_descs , var_name , new_name , renamed_var_start_idx [ var_name ] , idx ) _rename_arg_ ( pending_sum_ops , var_name , new_name ) for p in op_desc . output_names ( ) [ : param_idx ] : p_arg_names = op_desc . output ( p ) if var_name in p_arg_names : op_desc . set_output ( p , [ new_name if x == var_name else x for x in p_arg_names ] ) arg_names = [ new_name if x == var_name else x for x in arg_names [ : arg_idx ] ] + arg_names [ arg_idx : ] new_name = var_name + "@RENAME@block" + str ( block_idx ) + "@" + str ( var_rename_count [ var_name ] ) var_rename_count [ var_name ] += 1 arg_names [ arg_idx ] = new_name op_desc . set_output ( param_name , arg_names ) renamed_vars [ var_name ] . append ( new_name ) # record the latest device var_device [ var_name ] = op_device for var_name , inputs in six . iteritems ( renamed_vars ) : if len ( renamed_vars [ var_name ] ) > 1 : if len ( renamed_vars [ var_name ] ) > _MAX_ADD_NUM_ : _accumulate_gradients_by_sum_op_ ( var_name , renamed_vars , pending_sum_ops , len ( op_descs ) , var_device [ var_name ] ) else : _accumulate_gradients_by_add_ops_ ( var_name , renamed_vars , pending_sum_ops , len ( op_descs ) , var_device [ var_name ] ) # sum_op descs are sorted according to their insert position for key , value in collections . OrderedDict ( reversed ( list ( pending_sum_ops . items ( ) ) ) ) . items ( ) : # NOTE(zhiqiu): Since reversed, the idx of op_descs to be inserted will remains correct. # For example, [0, 1, 2], and we want to insert 'a' at idx 1, 'b' at idx 2, and the expected result is [0, 1, 'a', 2, 'b']. # If reversed, we first insert 'b' at idx 2, it becomes [0, 1, 2, 'b'], and then insert 'a' at idx 1, it becomes [0, 1, 'a', 2, 'b']. # If not reverse, we first insert 'a' at idx 1, it becomes [0, 1, 'a', 2], and then insert 'b' at idx 2, it becomes [0, 1, 'a', 'b', 2]. idx = key for i , op in enumerate ( value ) : op_descs . insert ( idx + i , op ) return op_descs