code: def test_tune_batch_size_lr_cpu(
      tmpdir,
      ray_cluster_2cpu,
      max_batch_size,
      expected_final_learning_rate,
  ):
      config = {
          "input_features": [
              number_feature(normalization="zscore"),
              set_feature(),
              binary_feature(),
          ],
          "output_features": [
              category_feature(
                  decoder={"vocab_size": 2}, reduce_input="sum"
              )
          ],
          "combiner": {"type": "concat", "output_size": 14},
          TRAINER: {
              "epochs": 2,
              "batch_size": "auto",
              "learning_rate": "auto",
              "max_batch_size": max_batch_size,
          },
      }
  
      backend_config = copy.deepcopy(RAY_BACKEND_CONFIG)
  
      num_samples = 200
      csv_filename = os.path.join(tmpdir, "dataset.csv")
      dataset_csv = generate_data(
          config["input_features"],
          config["output_features"],
          csv_filename,
          num_examples=num_samples,
      )
      dataset_parquet = create_data_set_to_use("parquet", dataset_csv)
      model = run_api_experiment(
          config,
          dataset=dataset_parquet,
          backend_config=backend_config,
          evaluate=False,
      )
  
      num_train_samples = num_samples * DEFAULT_PROBABILITIES[0]
      max_batch_size_by_train_examples = (
          MAX_BATCH_SIZE_DATASET_FRACTION * num_train_samples
      )
      max_batch_size = (
          max_batch_size_by_train_examples
          if max_batch_size is None
          else min(max_batch_size_by_train_examples, max_batch_size)
      )
      assert 2 < model.config[TRAINER]["batch_size"] <= max_batch_size
      assert (
          model.config[TRAINER]["learning_rate"]
          == expected_final_learning_rate
      )
  
imports: import copy
  import os
  import tempfile
  from typing import Literal, Optional, Union
  import numpy
  import pandas
  import pytest
  import torch
  from ludwig.api import LudwigModel
  from ludwig.backend import create_ray_backend, initialize_backend, LOCAL_BACKEND
  from ludwig.constants import AUDIO, BAG, BALANCE_PERCENTAGE_TOLERANCE, BATCH_SIZE, BFILL, BINARY, CATEGORY, COLUMN, DATE, H3, IMAGE, MAX_BATCH_SIZE_DATASET_FRACTION, NAME, NUMBER, PREPROCESSING, SEQUENCE, SET, SPLIT, TEXT, TIMESERIES, TRAINER, VECTOR
  from ludwig.data.preprocessing import balance_data
  from ludwig.data.split import DEFAULT_PROBABILITIES
  from ludwig.utils.data_utils import read_parquet
  from ludwig.utils.misc_utils import merge_dict
  from tests.integration_tests.utils import audio_feature, augment_dataset_with_none, bag_feature, binary_feature, category_feature, create_data_set_to_use, date_feature, generate_data, h3_feature, image_feature, number_feature, RAY_BACKEND_CONFIG, sequence_feature, set_feature, text_feature, timeseries_feature, train_with_backend, vector_feature
  import dask
  import ray
  import ray.exceptions
  from ray.air.config import DatasetConfig
  from ray.data import Dataset, DatasetPipeline
  from ray.train._internal.dataset_spec import DataParallelIngestSpec
  from ludwig.backend.ray import get_trainer_kwargs, RayBackend
  from ludwig.data.dataframe.dask import DaskEngine
label_desc: Use image node_id 26 for calling a global function with example usage: test_tune_batch_size_lr_cpu(tmpdir, ray_cluster_2cpu, max_batch_size, expected_final_learning_rate) without return types