code: def _backprop(
      outputs, inputs, grad_required, retain_grad, grads, loss_scale
  ):
      (
          candidate_funcs,
          push_candidate,
          pop_candidate,
      ) = _get_ordered_func_heap()
  
      for y in outputs:
          creator = y.creator_node
          if creator is not None:
              push_candidate(creator)
  
      input_nodes = set(x.node for x in inputs)
      ret_dict = {}
  
      is_debug = chainer.is_debug()
      base_hooks = chainer.get_function_hooks().values()
      while candidate_funcs:
          func = pop_candidate()
  
          # Collect the gradients w.r.t. the outputs
          ys = [y() for y in func.outputs]  # access via weak ref
          gys = tuple(
              [
                  grads.pop(y)
                  if y is not None and y.creator_node is not None
                  else None
                  for y in ys
              ]
          )
  
          for node, gy in six.moves.zip(ys, gys):
              if node is not None:
                  if node in input_nodes:
                      ret_dict[node] = gy
  
                  if retain_grad:
                      y = node.get_variable_or_none()
                      if y is not None:
                          y.grad_var = gy
                          y._loss_scale = loss_scale
  
          # Collect the gradients w.r.t. the inputs
          input_indexes = []
          x_grads = collections.OrderedDict()
          for i, x in enumerate(func.inputs):
              if x not in grad_required:
                  continue
              input_indexes.append(i)
              if x not in x_grads:
                  x_grads[x] = grads.get_as_list(x)
          if not input_indexes:
              continue
          input_indexes = tuple(input_indexes)
  
          # Do backward
  
          # Call pre-backward hooks
          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
  
          in_data = [x.data for x in func.inputs]
          out_grad_data = [None if g is None else g.data for g in gys]
  
          with chainer.using_device(
              backend.get_device_from_array(*in_data)
          ):
              for hook in hooks:
                  hook.backward_preprocess(
                      func, tuple(in_data), tuple(out_grad_data)
                  )
  
              _backprop_utils.backprop_step(
                  func, input_indexes, gys, x_grads, is_debug
              )
  
              # Call post-backward hooks
              for hook in hooks:
                  hook.backward_postprocess(
                      func, tuple(in_data), tuple(out_grad_data)
                  )
  
          # Update grads
          for node, g in x_grads.items():
              if not g:  # gradient == None
                  continue
  
              creator = node.creator_node
              if creator is not None:
                  push_candidate(creator)
  
      for x in input_nodes:
          if x not in ret_dict:
              ret_dict[x] = grads.pop(x)
      return ret_dict
  
imports: import collections
  import contextlib
  import heapq
  import inspect
  import traceback
  import weakref
  import six
  import chainer
  from chainer import _backprop_utils
  from chainer import backend
  from chainer.backends import cuda
  from chainer import configuration
  from chainer import function_hook
  from chainer.graph_optimizations.static_graph_utilities import static_forward_optimizations
  from chainer import utils
  from chainer.utils import type_check
  from chainer import variable
  import chainerx
label_desc: Use image node_id 3 for calling a global function with example usage: _backprop(outputs, inputs, grad_required, retain_grad, grads, loss_scale) and returns: ret_dict