# Path: tf_slim/ops/arg_scope.py
# @tf_contextlib.contextmanager
# def arg_scope(list_ops_or_scope, **kwargs):
#   """Stores the default arguments for the given set of list_ops.
# 
#   For usage, please see examples at top of the file.
# 
#   Args:
#     list_ops_or_scope: List or tuple of operations to set argument scope for or
#       a dictionary containing the current scope. When list_ops_or_scope is a
#       dict, kwargs must be empty. When list_ops_or_scope is a list or tuple,
#       then every op in it need to be decorated with @add_arg_scope to work.
#     **kwargs: keyword=value that will define the defaults for each op in
#               list_ops. All the ops need to accept the given set of arguments.
# 
#   Yields:
#     the current_scope, which is a dictionary of {op: {arg: value}}
#   Raises:
#     TypeError: if list_ops is not a list or a tuple.
#     ValueError: if any op in list_ops has not be decorated with @add_arg_scope.
#   """
#   if isinstance(list_ops_or_scope, dict):
#     # Assumes that list_ops_or_scope is a scope that is being reused.
#     if kwargs:
#       raise ValueError('When attempting to re-use a scope by suppling a'
#                        'dictionary, kwargs must be empty.')
#     current_scope = list_ops_or_scope.copy()
#     try:
#       _get_arg_stack().append(current_scope)
#       yield current_scope
#     finally:
#       _get_arg_stack().pop()
#   else:
#     # Assumes that list_ops_or_scope is a list/tuple of ops with kwargs.
#     if not isinstance(list_ops_or_scope, (list, tuple)):
#       raise TypeError('list_ops_or_scope must either be a list/tuple or reused '
#                       'scope (i.e. dict)')
#     try:
#       current_scope = current_arg_scope().copy()
#       for op in list_ops_or_scope:
#         key = arg_scope_func_key(op)
#         if not has_arg_scope(op):
#           raise ValueError('%s is not decorated with @add_arg_scope',
#                            _name_op(op))
#         if key in current_scope:
#           current_kwargs = current_scope[key].copy()
#           current_kwargs.update(kwargs)
#           current_scope[key] = current_kwargs
#         else:
#           current_scope[key] = kwargs.copy()
#       _get_arg_stack().append(current_scope)
#       yield current_scope
#     finally:
#       _get_arg_stack().pop()


import functools
import re
import numpy as np
import six
import tensorflow.compat.v1 as tf
from six.moves import xrange  # pylint: disable=redefined-builtin
from tf_slim.ops import arg_scope as arg_scope_lib
from tensorflow.python import tf2
from tensorflow.python.eager import backprop
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops as framework_ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import control_flow_util
from tensorflow.python.ops import custom_gradient
from tensorflow.python.ops import gradients_impl
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import variable_scope
from tensorflow.python.ops import variables as variables_lib
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.util import nest
from tensorflow.python.util import tf_inspect

def _is_on_tpu():
  return control_flow_util.GraphOrParentsInXlaContext(
      framework_ops.get_default_graph())


def _recomputing_grad_fn(compute_fn,
                         original_args,
                         original_vars,
                         output_grads,
                         grad_fn_variables,
                         use_data_dep,
                         tupleize_grads,
                         arg_scope,
                         var_scope,
                         has_is_recompute_kwarg):
  """Grad fn for recompute_grad."""
  variables = grad_fn_variables or []

  # Identity ops around the inputs ensures correct gradient graph-walking.
  inputs = [array_ops.identity(x) for x in list(original_args)]

  # Recompute outputs
  # Use a control dependency to ensure that the recompute is not eliminated by
  # CSE and that it happens on the backwards pass.
  ctrl_dep_grads = [g for g in output_grads if g is not None]
  with framework_ops.control_dependencies(ctrl_dep_grads):
    if use_data_dep:
      inputs = _force_data_dependency(output_grads, inputs)
    # Re-enter scopes

# Path: tf_slim/ops/arg_scope.py
# @tf_contextlib.contextmanager
# def arg_scope(list_ops_or_scope, **kwargs):
#   """Stores the default arguments for the given set of list_ops.
# 
#   For usage, please see examples at top of the file.
# 
#   Args:
#     list_ops_or_scope: List or tuple of operations to set argument scope for or
#       a dictionary containing the current scope. When list_ops_or_scope is a
#       dict, kwargs must be empty. When list_ops_or_scope is a list or tuple,
#       then every op in it need to be decorated with @add_arg_scope to work.
#     **kwargs: keyword=value that will define the defaults for each op in
#               list_ops. All the ops need to accept the given set of arguments.
# 
#   Yields:
#     the current_scope, which is a dictionary of {op: {arg: value}}
#   Raises:
#     TypeError: if list_ops is not a list or a tuple.
#     ValueError: if any op in list_ops has not be decorated with @add_arg_scope.
#   """
#   if isinstance(list_ops_or_scope, dict):
#     # Assumes that list_ops_or_scope is a scope that is being reused.
#     if kwargs:
#       raise ValueError('When attempting to re-use a scope by suppling a'
#                        'dictionary, kwargs must be empty.')
#     current_scope = list_ops_or_scope.copy()
#     try:
#       _get_arg_stack().append(current_scope)
#       yield current_scope
#     finally:
#       _get_arg_stack().pop()
#   else:
#     # Assumes that list_ops_or_scope is a list/tuple of ops with kwargs.
#     if not isinstance(list_ops_or_scope, (list, tuple)):
#       raise TypeError('list_ops_or_scope must either be a list/tuple or reused '
#                       'scope (i.e. dict)')
#     try:
#       current_scope = current_arg_scope().copy()
#       for op in list_ops_or_scope:
#         key = arg_scope_func_key(op)
#         if not has_arg_scope(op):
#           raise ValueError('%s is not decorated with @add_arg_scope',
#                            _name_op(op))
#         if key in current_scope:
#           current_kwargs = current_scope[key].copy()
#           current_kwargs.update(kwargs)
#           current_scope[key] = current_kwargs
#         else:
#           current_scope[key] = kwargs.copy()
#       _get_arg_stack().append(current_scope)
#       yield current_scope
#     finally:
#       _get_arg_stack().pop()


# Path: tf_slim/layers/rev_block_lib.py
import functools
import re
import numpy as np
import six
import tensorflow.compat.v1 as tf
from six.moves import xrange  # pylint: disable=redefined-builtin
from tf_slim.ops import arg_scope as arg_scope_lib
from tensorflow.python import tf2
from tensorflow.python.eager import backprop
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops as framework_ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import control_flow_util
from tensorflow.python.ops import custom_gradient
from tensorflow.python.ops import gradients_impl
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import variable_scope
from tensorflow.python.ops import variables as variables_lib
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.util import nest
from tensorflow.python.util import tf_inspect


def _is_on_tpu():
  return control_flow_util.GraphOrParentsInXlaContext(
      framework_ops.get_default_graph())


def _recomputing_grad_fn(compute_fn,
                         original_args,
                         original_vars,
                         output_grads,
                         grad_fn_variables,
                         use_data_dep,
                         tupleize_grads,
                         arg_scope,
                         var_scope,
                         has_is_recompute_kwarg):
  """Grad fn for recompute_grad."""
  variables = grad_fn_variables or []

  # Identity ops around the inputs ensures correct gradient graph-walking.
  inputs = [array_ops.identity(x) for x in list(original_args)]

  # Recompute outputs
  # Use a control dependency to ensure that the recompute is not eliminated by
  # CSE and that it happens on the backwards pass.
  ctrl_dep_grads = [g for g in output_grads if g is not None]
  with framework_ops.control_dependencies(ctrl_dep_grads):
    if use_data_dep:
      inputs = _force_data_dependency(output_grads, inputs)
    # Re-enter scopes

    with arg_scope_lib.arg_scope(arg_scope):