code: def _gradients_layer(
      model: Union[tf.keras.models.Model],
      layer: Union[tf.keras.layers.Layer],
      orig_call: Callable,
      orig_dummy_input: Union[list, np.ndarray],
      x: Union[List[tf.Tensor], tf.Tensor],
      target: Union[None, tf.Tensor],
      forward_kwargs: Optional[dict] = None,
      compute_layer_inputs_gradients: bool = False,
  ) -> tf.Tensor:
      """
      Calculates the gradients of the target class output (or the output if the output dimension is equal to 1)
      with respect to each element of `layer`.
  
      Parameters
      ----------
      model
          `tensorflow` model.
      layer
          Layer of the model with respect to which the gradients are calculated.
      orig_call
          Original `call` method of the layer. This is necessary since the call method is modified by the function
          in order to make the layer output visible to the `GradientTape`.
      x
          Input data point.
      target
          Target for which the gradients are calculated if the output dimension is higher than 1.
      forward_kwargs
          Input keyword args.
      compute_layer_inputs_gradients
          If ``True``, gradients are computed with respect to the layer's inputs.
          If ``False``, they are computed with respect to the layer's outputs.
  
      Returns
      -------
      Gradients for each element of layer.
  
      """
  
      def watch_layer(layer, tape):
          """
          Make an intermediate hidden `layer` watchable by the `tape`.
          After calling this function, you can obtain the gradient with
          respect to the output of the `layer` by calling:
  
              grads = tape.gradient(..., layer.result)
  
          """
  
          def decorator(func):
              def wrapper(*args, **kwargs):
                  # Store the result and the input of `layer.call` internally.
                  if compute_layer_inputs_gradients:
                      layer.inp = x
                      layer.result = func(*x, **kwargs)
                      # From this point onwards, watch this tensor.
                      tape.watch(layer.inp)
                  else:
                      layer.inp = args
                      layer.result = x
                      # From this point onwards, watch this tensor.
                      tape.watch(layer.result)
                  # Return the result to continue with the forward pass.
                  return layer.result
  
              return wrapper
  
          layer.call = decorator(layer.call)
  
      #  Repeating the dummy input needed to initiate the model's forward call in order to ensure that
      #  the number of dummy instances is the same as the number of real instances.
      #  This is necessary in case `forward_kwargs` is not None. In that case, the model forward call  would crash
      #  if the number of instances in `orig_dummy_input` is different from the number of instances in `forward_kwargs`.
      #  The number of instances in `forward_kwargs` is the same as the number of instances in `x` by construction.
      if isinstance(orig_dummy_input, list):
          if isinstance(x, list):
              orig_dummy_input = [
                  np.repeat(inp, x[0].shape[0], axis=0)
                  for inp in orig_dummy_input
              ]
          else:
              orig_dummy_input = [
                  np.repeat(inp, x.shape[0], axis=0)
                  for inp in orig_dummy_input
              ]
      else:
          if isinstance(x, list):
              orig_dummy_input = np.repeat(
                  orig_dummy_input, x[0].shape[0], axis=0
              )
          else:
              orig_dummy_input = np.repeat(
                  orig_dummy_input, x.shape[0], axis=0
              )
  
      if forward_kwargs is None:
          forward_kwargs = {}
      #  Calculating the gradients with respect to the layer.
      with tf.GradientTape() as tape:
          watch_layer(layer, tape)
          preds = _run_forward(
              model,
              orig_dummy_input,
              target,
              forward_kwargs=forward_kwargs,
          )
  
      if compute_layer_inputs_gradients:
          grads = tape.gradient(preds, layer.inp)
      else:
          grads = tape.gradient(preds, layer.result)
  
      delattr(layer, "inp")
      delattr(layer, "result")
      layer.call = orig_call
  
      return grads
  
imports: import copy
  import logging
  import string
  import warnings
  from enum import Enum
  from typing import Callable, List, Optional, Tuple, Union, cast
  import numpy
  import tensorflow
  from alibi.api.defaults import DEFAULT_DATA_INTGRAD, DEFAULT_META_INTGRAD
  from alibi.api.interfaces import Explainer, Explanation
  from alibi.utils.approximation_methods import approximation_parameters
label_desc: Use image node_id 8 for calling a global function with example usage: _gradients_layer(model, layer, orig_call, orig_dummy_input, x, target, forward_kwargs, compute_layer_inputs_gradients) and returns: grads, wrapper, layer