code: def memory_tune_config(
      config, dataset, model_category, row_count, backend
  ):
      backend = initialize_backend(backend)
  
      fits_in_memory = False
      tried_reduce_seq_len = False
      config_obj = ModelConfig.from_dict(config)
      raw_config = config_obj.to_dict()
      training_set_metadata = get_trainingset_metadata(
          raw_config, dataset, backend
      )
      modified_hyperparam_search_space = copy.deepcopy(
          raw_config[HYPEROPT]["parameters"]
      )
      current_param_values = {}
      param_list = []
      model_type = get_model_type(raw_config)
      if model_type in RANKED_MODIFIABLE_PARAM_LIST:
          params_to_modify = RANKED_MODIFIABLE_PARAM_LIST[model_type]
          if len(params_to_modify.keys()) > 0:
              param_list = list(params_to_modify.keys())
              max_memory = _get_machine_memory()
              initialize_pytorch()
  
      while param_list:
          # compute memory utilization
          current_param_values = get_new_params(
              current_param_values,
              modified_hyperparam_search_space,
              params_to_modify,
          )
          temp_config = sub_new_params(raw_config, current_param_values)
          config_obj = ModelConfig.from_dict(temp_config)
          mem_use = compute_memory_usage(
              config_obj, training_set_metadata, model_category
          )
          if (
              mem_use > max_memory
              and model_category == TEXT
              and not tried_reduce_seq_len
          ):
              tried_reduce_seq_len = True
              if reduce_text_feature_max_length(
                  config, training_set_metadata
              ):
                  reduce_text_feature_max_length(
                      temp_config, training_set_metadata
                  )
                  config_obj = ModelConfig.from_dict(temp_config)
                  mem_use = compute_memory_usage(
                      config_obj, training_set_metadata, model_category
                  )
          logger.info(
              f"Checking model estimated mem use {mem_use} against memory size {max_memory}"
          )
          if mem_use <= max_memory:
              fits_in_memory = True
              break
          # check if we have exhausted tuning of current param (e.g. we can no longer reduce the param value)
          param, min_value = (
              param_list[0],
              params_to_modify[param_list[0]],
          )
  
          if param in modified_hyperparam_search_space.keys():
              param_space = modified_hyperparam_search_space[param][
                  "space"
              ]
              if param_space == "choice":
                  if (
                      len(
                          modified_hyperparam_search_space[param][
                              "categories"
                          ]
                      )
                      >= 2
                      and modified_hyperparam_search_space[param][
                          "categories"
                      ][-2]
                      >= min_value
                  ):
                      modified_hyperparam_search_space[param][
                          "categories"
                      ] = modified_hyperparam_search_space[param][
                          "categories"
                      ][
                          :-1
                      ]
                  else:
                      param_list.pop(
                          0
                      )  # exhausted reduction of this parameter
              else:
                  # reduce by 10%
                  upper_bound, lower_bound = (
                      modified_hyperparam_search_space[param]["upper"],
                      modified_hyperparam_search_space[param]["lower"],
                  )
                  reduction_val = (upper_bound - lower_bound) * 0.1
                  new_upper_bound = upper_bound - reduction_val
                  if (
                      new_upper_bound
                  ) > lower_bound and new_upper_bound > min_value:
                      modified_hyperparam_search_space[param][
                          "upper"
                      ] = new_upper_bound
                  else:
                      param_list.pop(
                          0
                      )  # exhausted reduction of this parameter
          else:
              param_list.pop(0)  # param not in hyperopt search space
  
      if (
          model_category == TEXT
          and row_count > AUTOML_LARGE_TEXT_DATASET
      ):
          if (
              "checkpoints_per_epoch" not in config[TRAINER]
              and "steps_per_checkpoint" not in config[TRAINER]
          ):
              checkpoints_per_epoch = max(
                  2,
                  math.floor(
                      row_count / AUTOML_MAX_ROWS_PER_CHECKPOINT
                  ),
              )
              config[TRAINER][
                  "checkpoints_per_epoch"
              ] = checkpoints_per_epoch  # decrease latency to get model accuracy signal
          if "evaluate_training_set" not in config[TRAINER]:
              config[TRAINER][
                  "evaluate_training_set"
              ] = False  # reduce overhead for increased evaluation frequency
          if not fits_in_memory:
              # Switch to smaller pre-trained model encoder for large datasets.
              _update_text_encoder(
                  config["input_features"],
                  AUTOML_DEFAULT_TEXT_ENCODER,
                  AUTOML_SMALLER_TEXT_ENCODER,
              )
  
      modified_config = copy.deepcopy(config)
  
      modified_config[HYPEROPT][
          "parameters"
      ] = modified_hyperparam_search_space
      modified_config[HYPEROPT]["executor"][
          "num_samples"
      ] = _update_num_samples(
          modified_config[HYPEROPT]["executor"]["num_samples"],
          modified_hyperparam_search_space,
      )
      return modified_config, fits_in_memory
  
imports: import copy
  import logging
  import math
  from collections import OrderedDict
  from typing import List
  import psutil
  from ludwig.api import LudwigModel
  from ludwig.backend import initialize_backend
  from ludwig.constants import AUTO, AUTOML_DEFAULT_TEXT_ENCODER, AUTOML_LARGE_TEXT_DATASET, AUTOML_MAX_ROWS_PER_CHECKPOINT, AUTOML_SMALLER_TEXT_ENCODER, AUTOML_SMALLER_TEXT_LENGTH, AUTOML_TEXT_ENCODER_MAX_TOKEN_LEN, HYPEROPT, MINIMUM_BATCH_SIZE, PREPROCESSING, SPACE, TEXT, TRAINER
  from ludwig.data.preprocessing import preprocess_for_training
  from ludwig.features.feature_registries import update_config_with_metadata
  from ludwig.schema.model_config import ModelConfig
  from ludwig.utils.automl.utils import get_model_type
  from ludwig.utils.torch_utils import initialize_pytorch
label_desc: Use image node_id 12 for calling a global function with example usage: memory_tune_config(config, dataset, model_category, row_count, backend) and returns: modified_config,  fits_in_memory