code: def test_update_scheduler_on_epoch(self):
      base_lr = 0.1
      gamma = 0.9
      conf = os.path.join(DIR, "test_config/lr_scheduler.yaml")
      opt = OmegaConf.load(conf)
      opt.update_lr_scheduler_on = "on_epoch"
      model = DifferentiableMockModel(opt)
      model.instantiate_optimizers(opt)
      model.schedulers.__repr__()
  
      data = Data(pos=torch.randn((1, 3)))
      model.set_input(data, torch.device("cpu"))
  
      num_epochs = 5
      num_samples_epoch = 32
      batch_size = 4
      steps = num_samples_epoch // batch_size
  
      for epoch in range(num_epochs):
          for step in range(steps):
              model.optimize_parameters(epoch, batch_size)
      self.assertAlmostEqual(
          get_lr(model._optimizer), base_lr * gamma ** (num_epochs - 1)
      )
  
file_path: torch-points3d/test/test_lr_scheduler.py
imports: import os
  import sys
  from omegaconf import OmegaConf
  import torch
  import unittest
  import logging
  from torch_geometric.data import Data
  from torch_points3d.models.base_model import BaseModel
  from test.mock_models import DifferentiableMockModel
label_desc: Use image node_id 1 for calling the TestLrScheduler obj's underlying member method code with example usage: obj.test_update_scheduler_on_epoch() without return types