class_docstr: An invertible autograd function. This allows for automatic
  backpropagation in a reversible fashion so that the memory of intermediate
  results can be freed during the forward pass and be constructed on-the-fly
  during the bachward pass.
  
  Args:
      ctx (torch.autograd.function.InvertibleFunctionBackward):
          A context object that can be used to stash information for backward
          computation.
      fn (torch.nn.Module): The forward function.
      fn_inverse (torch.nn.Module): The inverse function to recompute the
          freed input.
      num_bwd_passes (int): Number of backward passes to retain a link
          with the output. After the last backward pass the output is
          discarded and memory is freed.
      num_inputs (int): The number of inputs to the forward function.
      *args (tuple): Inputs and weights.
class_docstr_tok: ["An","invertible","autograd","function",".","This","allows","for","automatic","backpropagation","in","a","reversible","fashion","so","that","the","memory","of","intermediate","results","can","be","freed","during","the","forward","pass","and","be","constructed","on-the-fly","during","the","bachward","pass",".","Args",":","ctx","(","torch.autograd.function.InvertibleFunctionBackward",")",":","A","context","object","that","can","be","used","to","stash","information","for","backward","computation",".","fn","(","torch.nn.Module",")",":","The","forward","function",".","fn_inverse","(","torch.nn.Module",")",":","The","inverse","function","to","recompute","the","freed","input",".","num_bwd_passes","(","int",")",":","Number","of","backward","passes","to","retain","a","link","with","the","output",".","After","the","last","backward","pass","the","output","is","discarded","and","memory","is","freed",".","num_inputs","(","int",")",":","The","number","of","inputs","to","the","forward","function",".","*","args","(","tuple",")",":","Inputs","and","weights","."]
code: def backward(ctx, *grad_outputs):
      if len(ctx.outputs) == 0:
          raise RuntimeError(
              f"Trying to perform a backward pass on the "
              f"'InvertibleFunction' for more than '{ctx.num_bwd_passes}' "
              f"times. Try raising 'num_bwd_passes'."
          )
  
      inputs = ctx.inputs.pop()
      outputs = ctx.outputs.pop()
  
      # Recompute input by swapping out the first argument:
      with torch.no_grad():
          inputs_inverted = ctx.fn_inverse(*(outputs + inputs[1:]))
          if len(ctx.outputs) == 0:  # Clear memory from outputs:
              for element in outputs:
                  if torch_geometric.typing.WITH_PT20:
                      element.untyped_storage().resize_(0)
                  else:  # pragma: no cover
                      element.storage().resize_(0)
  
          if not isinstance(inputs_inverted, tuple):
              inputs_inverted = (inputs_inverted,)
  
          for elem_orig, elem_inv in zip(inputs, inputs_inverted):
              if torch_geometric.typing.WITH_PT20:
                  elem_orig.untyped_storage().resize_(
                      int(np.prod(elem_orig.size()))
                      * elem_orig.element_size()
                  )
              else:  # pragma: no cover
                  elem_orig.storage().resize_(
                      int(np.prod(elem_orig.size()))
                  )
              elem_orig.set_(elem_inv)
  
      # Compute gradients with grad enabled:
      with torch.set_grad_enabled(True):
          detached_inputs = []
          for element in inputs:
              if isinstance(element, torch.Tensor):
                  detached_inputs.append(element.detach())
              else:
                  detached_inputs.append(element)
          detached_inputs = tuple(detached_inputs)
          for x, req_grad in zip(
              detached_inputs, ctx.input_requires_grad
          ):
              if isinstance(x, torch.Tensor):
                  x.requires_grad = req_grad
          tmp_output = ctx.fn(*detached_inputs)
  
      if not isinstance(tmp_output, tuple):
          tmp_output = (tmp_output,)
  
      filtered_detached_inputs = tuple(
          filter(
              lambda x: x.requires_grad
              if isinstance(x, torch.Tensor)
              else False,
              detached_inputs,
          )
      )
      gradients = torch.autograd.grad(
          outputs=tmp_output,
          inputs=filtered_detached_inputs + ctx.weights,
          grad_outputs=grad_outputs,
      )
  
      input_gradients = []
      i = 0
      for rg in ctx.input_requires_grad:
          if rg:
              input_gradients.append(gradients[i])
              i += 1
          else:
              input_gradients.append(None)
  
      gradients = (
          tuple(input_gradients) + gradients[-len(ctx.weights) :]
      )
  
      return (None, None, None, None) + gradients
  
imports: import copy
  from abc import ABC, abstractmethod
  from typing import Any, List, Optional, Union
  import numpy
  import torch
  from torch import Tensor
  import torch_geometric.typing
  from torch_geometric.typing import Adj
label_desc: Use image node_id 2 for calling the InvertibleFunction obj's underlying member method code with example usage: obj.backward(ctx) and returns: unknown