code: def training_loop(
      closure: Callable[[], tf.Tensor],
      optimizer: Optional[tf.optimizers.Optimizer] = None,
      var_list: Optional[List[tf.Variable]] = None,
      maxiter: int = 1_000,
      compile: bool = False,
  ) -> None:
      """
      Simple generic training loop. At each iteration uses a GradientTape to compute
      the gradients of a loss function with respect to a set of variables.
  
      :param closure: Callable that constructs a loss function based on data and model being trained
      :param optimizer: tf.optimizers or tf.keras.optimizers that updates variables by applying the
          corresponding loss gradients. Adam is a default optimizer with default settings.
      :param var_list: List of model variables to be learnt during training
      :param maxiter: Maximum number of
      :return:
      """
  
      safe_optimizer = (
          tf.optimizers.Adam() if optimizer is None else optimizer
      )
      safe_var_list = [] if var_list is None else var_list
  
      def optimization_step() -> None:
          with tf.GradientTape(watch_accessed_variables=False) as tape:
              tape.watch(safe_var_list)
              loss = closure()
          grads = tape.gradient(loss, safe_var_list)
          safe_optimizer.apply_gradients(zip(grads, safe_var_list))
  
      if compile:
          optimization_step = tf.function(optimization_step)
  
      for _ in range(maxiter):
          optimization_step()
  
file_path: GPflow/gpflow/utilities/misc.py
imports: from typing import Callable, Iterable, List, Optional, Union
  import tensorflow
  import tensorflow_probability
  from check_shapes import check_shapes
  from ..base import TensorData
  from ..config import default_float, default_int
label_desc: Use image node_id 5 for calling a global function with example usage: training_loop(closure, optimizer, var_list, maxiter, compile) without return types