code: def _backprop_to_all(outputs, retain_grad, loss_scale):
      """Backprop to all input variables
  
      Args:
          outputs (list of tuple): each tuple is (y_node, y_grad_var).
              y_grad_var should not be None.
          retain_grad (bool): see docstring of Variable.backward
          loss_scale (float): see docstring of Variable.backward
  
      """
      OrderedDict = (
          chainer.utils._collections.OrderedDict
      )  # fix py2 memory leak
  
      cand_funcs = []
      seen_set = set()
  
      def add_cand(cand):
          if cand not in seen_set:
              # Negate since heapq is min-heap
              heapq.heappush(
                  cand_funcs, (-cand.rank, len(seen_set), cand)
              )
              seen_set.add(cand)
  
      grads = _backprop_utils.GradTable(accumulate_grad_inputs=True)
  
      leaf_nodes = set()
  
      for y, gy in outputs:
          grads.accumulate(y, gy)
  
          func = y.creator_node
          if func is None:  # leaf
              leaf_nodes.add(y)
          else:
              add_cand(func)
  
      # Fix F812 (Python 2)
      y = None
      del y
  
      is_debug = chainer.is_debug()
      base_hooks = chainer.get_function_hooks().values()
      while cand_funcs:
          _, _, func = heapq.heappop(cand_funcs)
          inputs = func.inputs
          target_input_indexes = tuple(
              [i for i, x in enumerate(inputs) if x.requires_grad]
          )
          outputs = [y() for y in func.outputs]  # access via weak ref
          out_grad = tuple(
              [
                  grads.pop(y)
                  if y is not None and y.creator_node is not None
                  else None
                  for y in outputs
              ]
          )
          if not target_input_indexes:
              continue
  
          in_data = [x.data for x in inputs]
          out_grad_array = [
              None if g is None else g.raw_array for g in out_grad
          ]
          if func._n_local_function_hooks != 0:
              local_hooks = collections.OrderedDict(
                  chainer.get_function_hooks()
              )
              local_hooks.update(func.local_function_hooks)
              hooks = local_hooks.values()  # avoid six for performance
          else:
              hooks = base_hooks
  
          with chainer.using_device(
              backend.get_device_from_array(*(in_data + out_grad_array))
          ):
              for hook in hooks:
                  hook.backward_preprocess(
                      func, tuple(in_data), tuple(out_grad_array)
                  )
  
              # Collect the current input gradients.
              target_inputs = [inputs[i] for i in target_input_indexes]
              # Keep the order for the portability, rather than
              # in_grad = {x: grads.get_as_list(x)
              #            for x in set(target_inputs)}
              in_grad = OrderedDict()
              for x in target_inputs:
                  if x not in in_grad:
                      in_grad[x] = grads.get_as_list(x)
  
              _backprop_utils.backprop_step(
                  func,
                  target_input_indexes,
                  out_grad,
                  in_grad,
                  is_debug,
              )
  
              for hook in hooks:
                  hook.backward_postprocess(
                      func, tuple(in_data), tuple(out_grad_array)
                  )
  
          if retain_grad:
              # The gradients of the outputs of `func` are final. Store them if
              # retain_grad=True.
              for y, gy in six.moves.zip(outputs, out_grad):
                  if y is not None:
                      y._set_grad_var_if_available(gy)
              del gy  # to reduce memory usage
          del out_grad  # to reduce memory usage
  
          for x, gx in in_grad.items():
              if not gx:  # gradient == None
                  continue
  
              for gx_elem in gx:
                  if gx_elem is not None:
                      chainer.variable._check_grad_type(
                          func, x, True, gx_elem.raw_array
                      )
              del gx_elem  # to reduce memory usage
  
              if x.creator_node is None:  # leaf
                  leaf_nodes.add(x)
              else:
                  add_cand(x.creator_node)
          del gx, in_grad  # to reduce memory usage
  
      for x in leaf_nodes:
          x_var = x.get_variable_or_none()
          gx = grads.pop(x)
          if x_var is not None:
              x_var._set_grad_var_without_check(gx)
              x_var._loss_scale = loss_scale
      grads.assert_no_grads()
  
file_path: chainer/chainer/_backprop.py
imports: from __future__ import absolute_import
  import collections
  import heapq
  import warnings
  import six
  import chainer
  from chainer import _backprop_utils
  from chainer import backend
  from chainer.utils import argument
  import chainerx
label_desc: Use image node_id 2 for calling a global function with example usage: _backprop_to_all(outputs, retain_grad, loss_scale) without return types