code: def apply_mapping_to_fused_bn_layer(
      mapping, fuse_mode: str = "one_linear"
  ) -> Callable:
      """
      Applies a mapping to a linearized Batch Normalization layer.
  
      :param mapping: The mapping to be applied.
        Should take parameters layer and reverse_state and
        return a mapping function.
      :param fuse_mode: Either 'one_linear': apply the mapping
        to a once linearized layer, or
        'two_linear': apply to twice to a twice linearized layer.
      """
      if fuse_mode not in ["one_linear", "two_linear"]:
          raise ValueError(
              "fuse_mode can only be 'one_linear' or 'two_linear'"
          )
  
      # TODO (alber): remove this workaround and make a proper class
      def get_scale_layer(kernel, bias):
          _kernel = kernel
          _bias = bias
  
          class ScaleLayer(klayers.Layer):
              def __init__(self, use_bias=True, **kwargs):
                  self._kernel_to_be = _kernel
                  self._bias_to_be = _bias
                  self.use_bias = use_bias
                  super().__init__(**kwargs)
  
              def get_config(self):
                  config = super().get_config()
                  config["use_bias"] = self.use_bias
                  return config
  
              def build(self, input_shape):
                  def kernel_initializer(_shape, dtype=None):
                      if dtype is not None:
                          warnings.warn(
                              f"Ignore dtype {dtype} as bias type."
                          )
                      return self._kernel_to_be
  
                  self.kernel = self.add_weight(
                      name="kernel",
                      shape=kbackend.int_shape(self._kernel_to_be),
                      initializer=kernel_initializer,
                      trainable=False,
                  )
                  if self.use_bias:
  
                      def bias_initializer(_shape, dtype=None):
                          if dtype is not None:
                              warnings.warn(
                                  f"Ignore dtype {dtype} as bias type."
                              )
                          return self._bias_to_be
  
                      self.bias = self.add_weight(
                          name="bias",
                          shape=kbackend.int_shape(self._bias_to_be),
                          initializer=bias_initializer,
                          trainable=False,
                      )
                  super().build(input_shape)
  
              def call(self, inputs, *_args, **_kwargs):
                  ret = inputs * self.kernel
                  if self.use_bias:
                      ret += self.bias
                  return ret
  
          return ScaleLayer()
  
      def meta_mapping(layer: Layer, reverse_state: dict):
          # get bn params
          weights = layer.weights.copy()
          if layer.scale:
              gamma = weights.pop(0)
          else:
              gamma = kbackend.ones_like(weights[0])
          if layer.center:
              beta = weights.pop(0)
          else:
              beta = kbackend.zeros_like(weights[0])
          mean, variance = weights
  
          if fuse_mode == "one_linear":
              tmp = kbackend.sqrt(variance**2 + layer.epsilon)
              tmp_k = gamma / tmp
              tmp_b = -mean / tmp + beta
  
              inputs = layer.get_input_at(0)
              surrogate_layer = get_scale_layer(tmp_k, tmp_b)
              # init layer
              surrogate_layer(inputs)
              actual_mapping = mapping(
                  surrogate_layer, reverse_state
              ).apply
          else:
              tmp = kbackend.sqrt(variance**2 + layer.epsilon)
              tmp_k1 = 1 / tmp
              tmp_b1 = -mean / tmp
              tmp_k2 = gamma
              tmp_b2 = beta
  
              inputs = layer.get_input_at(0)
              surrogate_layer1 = get_scale_layer(tmp_k1, tmp_b1)
              surrogate_layer2 = get_scale_layer(tmp_k2, tmp_b2)
              # init layers
              surrogate_layer1(inputs)
              surrogate_layer2(inputs)
              # TODO (alber): update reverse state
              actual_mapping_1 = mapping(
                  surrogate_layer1, reverse_state
              ).apply
              actual_mapping_2 = mapping(
                  surrogate_layer2, reverse_state
              ).apply
  
              def actual_mapping(
                  Xs: list[Tensor],
                  Ys: list[Tensor],
                  reversed_Ys: list[Tensor],
                  reverse_state,
              ):
                  X2s = ibackend.apply(surrogate_layer1, Xs)
                  # Apply first mapping
                  # TODO (alber): update reverse state
                  reversed_X2s = actual_mapping_2(
                      X2s, Ys, reversed_Ys, reverse_state
                  )
                  return actual_mapping_1(
                      Xs, X2s, reversed_X2s, reverse_state
                  )
  
          return actual_mapping
  
      return meta_mapping
  
imports: from __future__ import annotations
  import inspect
  import warnings
  from abc import ABCMeta, abstractmethod
  from typing import Any, Callable
  import numpy
  import tensorflow.keras.backend
  import tensorflow.keras.layers
  import tensorflow.keras.models
  import innvestigate.backend
  import innvestigate.backend.checks
  import innvestigate.layers
  from innvestigate.backend.types import Layer, LayerCheck, Model, NodeDict, OptionalList, ReverseTensorDict, Tensor
label_desc: Use image node_id 14 for calling a global function with example usage: apply_mapping_to_fused_bn_layer(mapping, fuse_mode) and returns: meta_mapping, ScaleLayer, actual_mapping, config, ret, actual_mapping_1, self, self