code: def _connect_on_gradient_graph(self, grad_vars, f):
      # 1. accumulate variables used more than one or do nothing
      vf_vb_map = grad_vars.pop(f)  # {VO_fwd: [VI_bwd]}
      grad_inputs = []
      for o in f.outputs:
          # address `floating` variables; no function takes it as input.
          # e.g., when dx, db, dg = dBN(...), (db, dg) are not used afterwards.
          # [0] is not enough, e.g., F.concatenate
          v = vf_vb_map.get(o, [F.constant(0.0, o.shape)])
          if len(v) > 1:
              grad_inputs += [sum(v)]
              # grad_inputs += [F.add_n(v)]
          else:
              grad_inputs += v
  
      # 2. lookup the backward function
      f_fwd_name = f.info.type_name
      if f_fwd_name not in registry:
          raise ValueError(
              "{} is not in the backward function registry".format(
                  f_fwd_name
              )
          )
      backward_func = registry[f_fwd_name]
  
      # 3. connect
      # Only grad-depending inputs are passed to the backward function because
      # the other inputs are probably cleared before.
      grad_depending_inputs = [None for inp in f.inputs]
      input_shapes = [inp.shape for inp in f.inputs]
      for i in range(len(f.inputs)):
          for j, inp in enumerate(f.inputs):
              if f.grad_depends_input_data(
                  i, j
              ) or f.auto_grad_depends_input_data(i, j):
                  grad_depending_inputs[j] = inp
  
      grad_depending_outputs = [None for outp in f.outputs]
      output_shapes = [outp.shape for outp in f.outputs]
      for i in range(len(f.inputs)):
          for o, outp in enumerate(f.outputs):
              if f.grad_depends_output_data(
                  i, o
              ) or f.auto_grad_depends_output_data(i, o):
                  grad_depending_outputs[o] = outp
  
      ctx = nn.get_current_context()
      with nn.context_scope(ctx):
          grad_outputs = backward_func(
              grad_inputs,
              grad_depending_inputs,
              input_shapes,
              grad_depending_outputs,
              output_shapes,
              **f.info.args,
          )
      grad_outputs = self._force_list(grad_outputs)
  
      # 4. put grad_output as grad_input to a corresponding function
      for inp, grad_out in zip(f.inputs, grad_outputs):
          if grad_out is None:
              continue
          if inp.parent not in grad_vars:
              grad_vars[inp.parent] = OrderedDict()
          if inp not in grad_vars[inp.parent]:
              grad_vars[inp.parent][inp] = [grad_out]
          else:
              grad_vars[inp.parent][inp] += [grad_out]
      return grad_outputs
  
imports: import numpy
  from collections import OrderedDict
  import nnabla
  import nnabla.functions
  from nnabla.function import PythonFunction
  from .backward_functions import registry
label_desc: Use image node_id 3 for calling the Grad obj's underlying member method code with example usage: obj._connect_on_gradient_graph(grad_vars, f) and returns: grad_outputs