code: def test_lr_scheduler_reduce_on_plateau():
      total_eval_steps = 100
      base_lr = 1.0
      reduce_limit = 3
  
      module = NumberInputFeature(
          NumberInputFeatureConfig(
              name="num1", encoder=DenseEncoderConfig()
          )
      )
      output1 = NumberOutputFeature(
          ECDNumberOutputFeatureConfig(name="output1", input_size=10),
          output_features={},
      )
  
      optimizer = SGD(module.parameters(), lr=base_lr)
      config = LRSchedulerConfig(
          warmup_evaluations=0,
          decay=None,
          reduce_on_plateau=reduce_limit,
          reduce_on_plateau_patience=10,
          reduce_on_plateau_rate=0.1,
      )
      scheduler = LRScheduler(
          config=config,
          optimizer=optimizer,
          steps_per_checkpoint=0,
          total_steps=0,
      )
  
      progress_tracker = get_new_progress_tracker(
          batch_size=64,
          best_eval_metric_value=float("inf"),
          best_increase_batch_size_eval_metric=float("inf"),
          learning_rate=base_lr,
          output_features={"output1": output1},
      )
  
      num_reductions = 0
  
      last_lr = optimizer.param_groups[0]["lr"]
      steps_to_plateau = 5
      loss = 10.0
      for epoch in range(total_eval_steps):
          for i in range(100):
              # Simulate batch-wise steps. If we make a mistake, then this will reset
              # the learning rate.
              scheduler.step()
  
          steps_to_plateau -= 1
          if steps_to_plateau > 0:
              loss -= 0.1
  
          progress_tracker.train_metrics["output1"]["loss"].append(
              TrainerMetric(epoch=epoch, step=epoch * 100, value=loss)
          )
          scheduler.eval_step(progress_tracker, "output1")
          lr = optimizer.param_groups[0]["lr"]
          if lr < last_lr:
              # Reset steps to plateau
              steps_to_plateau = 5
              num_reductions += 1
          last_lr = lr
  
      assert num_reductions == reduce_limit
  
      # 3 reductions that multiply by 0.1 each time
      assert np.isclose(lr, 0.001)
  
file_path: ludwig/tests/ludwig/modules/test_lr_scheduler.py
imports: import math
  import numpy
  from torch.optim import SGD
  from ludwig.features.number_feature import NumberInputFeature, NumberOutputFeature
  from ludwig.modules.lr_scheduler import LRScheduler
  from ludwig.schema.encoders.base import DenseEncoderConfig
  from ludwig.schema.features.number_feature import ECDNumberOutputFeatureConfig, NumberInputFeatureConfig
  from ludwig.schema.lr_scheduler import LRSchedulerConfig
  from ludwig.utils.metric_utils import TrainerMetric
  from ludwig.utils.trainer_utils import get_new_progress_tracker
label_desc: Use image node_id 2 for calling a global function with example usage: test_lr_scheduler_reduce_on_plateau() without return types