code: def test_ecd_tune_batch_size_and_lr(
      tmpdir, eval_batch_size, effective_batch_size, is_cpu
  ):
      input_features = [
          sequence_feature(encoder={"reduce_output": "sum"})
      ]
      output_features = [
          category_feature(
              decoder={"vocab_size": 2}, reduce_input="sum"
          ),
          number_feature(),
          binary_feature(),
          vector_feature(),
      ]
  
      num_samples = 30
      csv_filename = os.path.join(tmpdir, "training.csv")
      data_csv = generate_data(
          input_features,
          output_features,
          csv_filename,
          num_examples=num_samples,
      )
      val_csv = shutil.copyfile(
          data_csv, os.path.join(tmpdir, "validation.csv")
      )
      test_csv = shutil.copyfile(
          data_csv, os.path.join(tmpdir, "test.csv")
      )
  
      trainer = {
          EPOCHS: 2,
          EFFECTIVE_BATCH_SIZE: effective_batch_size,
          BATCH_SIZE: "auto",
          "gradient_accumulation_steps": "auto",
          "learning_rate": "auto",
      }
  
      if eval_batch_size:
          trainer[EVAL_BATCH_SIZE] = eval_batch_size
  
      config = {
          INPUT_FEATURES: input_features,
          OUTPUT_FEATURES: output_features,
          "combiner": {"type": "concat", "output_size": 14},
          TRAINER: trainer,
      }
  
      model = LudwigModel(
          config, backend=LocalTestBackend(), logging_level=logging.INFO
      )
  
      # check preconditions
      assert (
          model.config_obj.trainer.effective_batch_size
          == effective_batch_size
      )
      assert model.config_obj.trainer.batch_size == "auto"
      assert (
          model.config_obj.trainer.gradient_accumulation_steps == "auto"
      )
      assert model.config_obj.trainer.eval_batch_size == eval_batch_size
      assert model.config_obj.trainer.learning_rate == "auto"
  
      with mock.patch(
          "ludwig.trainers.trainer.Trainer.is_cpu_training"
      ) as mock_fn:
          mock_fn.return_value = is_cpu
          _, _, output_directory = model.train(
              training_set=data_csv,
              validation_set=val_csv,
              test_set=test_csv,
              output_directory=tmpdir,
          )
  
      def check_postconditions(model):
          # check batch size
          assert (
              model.config_obj.trainer.effective_batch_size
              == effective_batch_size
          )
          assert model.config_obj.trainer.batch_size != "auto"
          assert model.config_obj.trainer.batch_size > 1
  
          # check gradient accumulation
          assert (
              model.config_obj.trainer.gradient_accumulation_steps
              != "auto"
          )
          if effective_batch_size == "auto":
              assert (
                  model.config_obj.trainer.gradient_accumulation_steps
                  == 1
              )
          else:
              batch_size = model.config_obj.trainer.batch_size
              assert (
                  model.config_obj.trainer.gradient_accumulation_steps
                  == effective_batch_size // batch_size
              )
  
          # 4 is the largest possible batch size for this dataset (20% of dataset size)
          assert (
              model.config_obj.trainer.batch_size
              <= MAX_BATCH_SIZE_DATASET_FRACTION * num_samples
          )
  
          assert model.config_obj.trainer.eval_batch_size != "auto"
          assert model.config_obj.trainer.eval_batch_size > 1
  
          if eval_batch_size in ("auto", None):
              assert (
                  model.config_obj.trainer.batch_size
                  == model.config_obj.trainer.eval_batch_size
              )
          else:
              assert (
                  model.config_obj.trainer.eval_batch_size
                  == eval_batch_size
              )
  
          # check learning rate
          assert (
              model.config_obj.trainer.learning_rate == 0.0001
          )  # has sequence feature
  
      check_postconditions(model)
  
      model = LudwigModel.load(os.path.join(output_directory, "model"))
  
      # loaded model should retain the tuned params
      check_postconditions(model)
  
imports: import logging
  import os
  import shutil
  from unittest import mock
  import numpy
  import pandas
  import pytest
  import torch
  from packaging.version import parse
  from ludwig.api import LudwigModel
  from ludwig.callbacks import Callback
  from ludwig.constants import BATCH_SIZE, EFFECTIVE_BATCH_SIZE, EPOCHS, EVAL_BATCH_SIZE, INPUT_FEATURES, MAX_BATCH_SIZE_DATASET_FRACTION, OUTPUT_FEATURES, TRAINER
  from ludwig.distributed import init_dist_strategy
  from tests.integration_tests.utils import binary_feature, category_feature, generate_data, LocalTestBackend, number_feature, RAY_BACKEND_CONFIG, sequence_feature, text_feature, vector_feature
label_desc: Use image node_id 2 for calling a global function with example usage: test_ecd_tune_batch_size_and_lr(tmpdir, eval_batch_size, effective_batch_size, is_cpu) without return types