code: def get_preprocess_fn(
      pp_pipeline, remove_tpu_dtypes=True, log_data=True
  ):
      """Transform an input string into the preprocessing function.
  
      The minilanguage is as follows:
  
        fn1|fn2(arg, arg2,...)|...
  
      And describes the successive application of the various `fn`s to the input,
      where each function can optionally have one or more arguments, which are
      either positional or key/value, as dictated by the `fn`.
  
      The output preprocessing function expects a dictinary as input. This
      dictionary should have a key "image" that corresponds to a 3D tensor
      (height x width x channel).
  
      Args:
        pp_pipeline: A string describing the pre-processing pipeline. If empty or
          None, no preprocessing will be executed, but removing unsupported TPU
          dtypes will still be called if `remove_tpu_dtypes` is True.
        remove_tpu_dtypes: Whether to remove TPU incompatible types of data.
        log_data: Whether to log the data before and after preprocessing. Note:
          Remember set to `False` in eager mode to avoid too many log messages.
  
      Returns:
        preprocessing function.
  
      Raises:
        ValueError: if preprocessing function name is unknown
      """
  
      ops = []
      if pp_pipeline:
          for fn_name in pp_pipeline.split("|"):
              try:
                  ops.append(
                      registry.Registry.lookup(
                          f"preprocess_ops.{fn_name}"
                      )()
                  )
              except SyntaxError as err:
                  raise ValueError(
                      f"Syntax error on: {fn_name}"
                  ) from err
  
      def _preprocess_fn(data):
          """The preprocessing function that is returned."""
  
          # Validate input
          if not isinstance(data, dict):
              raise ValueError(
                  "Argument `data` must be a dictionary, "
                  "not %s" % str(type(data))
              )
  
          # Apply all the individual steps in sequence.
          if log_data:
              logging.info("Data before pre-processing:\n%s", data)
          for op in ops:
              data = op(data)
  
          if remove_tpu_dtypes:
              # Remove data that are TPU-incompatible (e.g. filename of type tf.string).
              for key in list(data.keys()):
                  if data[key].dtype not in TPU_SUPPORTED_DTYPES:
                      tf.logging.warning(
                          "Removing key %s from data dict because its dtype %s is not in "
                          " the supported dtypes: %s",
                          key,
                          data[key].dtype,
                          TPU_SUPPORTED_DTYPES,
                      )
                      data = pp_ops.get_delete_field(key)(data)
          if log_data:
              logging.info("Data after pre-processing:\n%s", data)
          return data
  
      return _preprocess_fn
  
imports: from absl import logging
  from scenic.dataset_lib.big_transfer import registry
  from scenic.dataset_lib.big_transfer.preprocessing import ops
  import tensorflow.compat.v1
label_desc: Use image node_id 1 for calling a global function with example usage: get_preprocess_fn(pp_pipeline, remove_tpu_dtypes, log_data) and returns: _preprocess_fn, data