code: def check_ray_backend_in_memory_preprocessing(
      config: "ModelConfig",
  ) -> None:  # noqa: F821
      """Checks that in memory preprocessing is used with Ray backend."""
      if config.backend is None:
          return
      if not hasattr(config.trainer, "preprocessing") or not hasattr(
          config.trainer.preprocessing, IN_MEMORY
      ):
          return
  
      if (
          config.backend.type == "ray"
          and not config.trainer.preprocessing.in_memory
      ):
          raise ConfigValidationError(
              "RayBackend does not support lazy loading of data files at train time. "
              "Set preprocessing config `in_memory: True`"
          )
  
      for input_feature in config.input_features:
          if input_feature.type == AUDIO or input_feature.type == IMAGE:
              if (
                  not input_feature.preprocessing.in_memory
                  and config.backend.type != "ray"
              ):
                  raise ConfigValidationError(
                      "RayBackend does not support lazy loading of data files at train time. "
                      f"Set preprocessing config `in_memory: True` for input feature {input_feature.name}"
                  )
  
imports: from abc import ABC, abstractmethod
  from re import findall
  from typing import Callable, TYPE_CHECKING
  from transformers import AutoConfig
  from ludwig.api_annotations import DeveloperAPI
  from ludwig.constants import AUDIO, BINARY, CATEGORY, IMAGE, IN_MEMORY, MIN_QUANTIZATION_BITS_FOR_MERGE_AND_UNLOAD, MODEL_ECD, MODEL_GBM, MODEL_LLM, NUMBER, SEQUENCE, SET, TEXT, TIMESERIES, VECTOR
  from ludwig.error import ConfigValidationError
  from ludwig.utils.metric_utils import get_feature_to_metric_names_map_from_feature_collection
  from ludwig.utils.misc_utils import merge_dict
label_desc: Use image node_id 8 for calling a global function with example usage: check_ray_backend_in_memory_preprocessing(config) without return types