code: def serial(*layers: Layer) -> InternalLayer:
      """Combinator for composing layers in serial.
  
      Based on :obj:`jax.example_libraries.stax.serial`.
  
      Args:
        *layers:
          a sequence of layers, each an `(init_fn, apply_fn, kernel_fn)` triple.
  
      See Also:
        :obj:`~neural_tangents.stax.repeat` for compiled repeated composition.
  
      Returns:
        A new layer, meaning an `(init_fn, apply_fn, kernel_fn)` triple,
        representing the serial composition of the given sequence of layers.
      """
      init_fns, apply_fns, kernel_fns = zip(*layers)
      init_fn, apply_fn = ostax.serial(*zip(init_fns, apply_fns))
  
      @requires(**_get_input_req_attr(kernel_fns, fold=op.rshift))
      def kernel_fn(k: NTTree[Kernel], **kwargs) -> NTTree[Kernel]:
          # TODO(xlc): if we drop `x1_is_x2` and use `rng` instead, need split key
          # inside kernel functions here and parallel below.
          for f in kernel_fns:
              k = f(k, **kwargs)
          return k
  
      return init_fn, apply_fn, kernel_fn
  
imports: import operator
  from typing import Any, Callable
  import warnings
  import frozendict
  import jax
  from jax import lax
  from jax import random
  import jax.example_libraries.stax
  from ..utils.kernel import Kernel
  from ..utils.typing import InternalLayer
  from ..utils.typing import Layer
  from ..utils.typing import LayerKernelFn
  from ..utils.typing import NTTree
  from ..utils.typing import NTTrees
  from ..utils.typing import Shapes
  from .requirements import Diagonal
  from .requirements import get_req
  from .requirements import layer
  from .requirements import requires
label_desc: Use image node_id 1 for calling a global function with example usage: serial() and returns: init_fn,  apply_fn,  kernel_fn, k