code: def test_multiple_optimizers_basefinetuning(tmpdir):
      class TestModel(BoringModel):
          def __init__(self):
              super().__init__()
              self.automatic_optimization = False
              self.backbone = torch.nn.Sequential(
                  torch.nn.Linear(32, 32),
                  torch.nn.Linear(32, 32),
                  torch.nn.Linear(32, 32),
                  torch.nn.ReLU(True),
              )
              self.layer = torch.nn.Linear(32, 2)
  
          def training_step(self, batch, batch_idx):
              opt1, opt2, opt3 = self.optimizers()
  
              # optimizer 1
              loss = self.step(batch)
              self.manual_backward(loss)
              opt1.step()
              opt1.zero_grad()
  
              # optimizer 2
              loss = self.step(batch)
              self.manual_backward(loss)
              opt2.step()
              opt2.zero_grad()
  
              # optimizer 3
              loss = self.step(batch)
              self.manual_backward(loss)
              opt3.step()
              opt3.zero_grad()
  
          def on_train_epoch_end(self) -> None:
              lr_sched1, lr_sched2 = self.lr_schedulers()
              lr_sched1.step()
              lr_sched2.step()
  
          def forward(self, x):
              return self.layer(self.backbone(x))
  
          def configure_optimizers(self):
              parameters = list(
                  filter(lambda p: p.requires_grad, self.parameters())
              )
              opt = optim.SGD(parameters, lr=0.1)
              opt_2 = optim.Adam(parameters, lr=0.1)
              opt_3 = optim.AdamW(parameters, lr=0.1)
              optimizers = [opt, opt_2, opt_3]
              schedulers = [
                  optim.lr_scheduler.StepLR(
                      opt, step_size=1, gamma=0.5
                  ),
                  optim.lr_scheduler.StepLR(
                      opt_2, step_size=1, gamma=0.5
                  ),
              ]
              return optimizers, schedulers
  
      class Check(Callback):
          def on_train_epoch_start(self, trainer, pl_module) -> None:
              num_param_groups = sum(
                  len(opt.param_groups) for opt in trainer.optimizers
              )
  
              if trainer.current_epoch == 0:
                  assert num_param_groups == 3
              elif trainer.current_epoch == 1:
                  assert num_param_groups == 4
                  assert list(lr_monitor.lrs) == [
                      "lr-Adam",
                      "lr-AdamW",
                      "lr-SGD/pg1",
                      "lr-SGD/pg2",
                  ]
              elif trainer.current_epoch == 2:
                  assert num_param_groups == 5
                  assert list(lr_monitor.lrs) == [
                      "lr-AdamW",
                      "lr-SGD/pg1",
                      "lr-SGD/pg2",
                      "lr-Adam/pg1",
                      "lr-Adam/pg2",
                  ]
              else:
                  expected = [
                      "lr-AdamW",
                      "lr-SGD/pg1",
                      "lr-SGD/pg2",
                      "lr-Adam/pg1",
                      "lr-Adam/pg2",
                      "lr-Adam/pg3",
                  ]
                  assert list(lr_monitor.lrs) == expected
  
      class TestFinetuning(BackboneFinetuning):
          def freeze_before_training(self, pl_module):
              self.freeze(pl_module.backbone[0])
              self.freeze(pl_module.backbone[1])
              self.freeze(pl_module.layer)
  
          def finetune_function(self, pl_module, epoch: int, optimizer):
              """Called when the epoch begins."""
              if epoch == 1 and isinstance(optimizer, torch.optim.SGD):
                  self.unfreeze_and_add_param_group(
                      pl_module.backbone[0], optimizer, lr=0.1
                  )
              if epoch == 2 and isinstance(optimizer, torch.optim.Adam):
                  self.unfreeze_and_add_param_group(
                      pl_module.layer, optimizer, lr=0.1
                  )
  
              if epoch == 3 and isinstance(optimizer, torch.optim.Adam):
                  assert len(optimizer.param_groups) == 2
                  self.unfreeze_and_add_param_group(
                      pl_module.backbone[1], optimizer, lr=0.1
                  )
                  assert len(optimizer.param_groups) == 3
  
      lr_monitor = LearningRateMonitor()
      trainer = Trainer(
          default_root_dir=tmpdir,
          max_epochs=5,
          limit_val_batches=0,
          limit_train_batches=2,
          callbacks=[TestFinetuning(), lr_monitor, Check()],
          logger=CSVLogger(tmpdir),
          enable_progress_bar=False,
          enable_model_summary=False,
          enable_checkpointing=False,
      )
      model = TestModel()
      trainer.fit(model)
  
      expected = [0.1, 0.1, 0.1, 0.1, 0.1]
      assert lr_monitor.lrs["lr-AdamW"] == expected
  
      expected = [0.1, 0.05, 0.025, 0.0125, 0.00625]
      assert lr_monitor.lrs["lr-SGD/pg1"] == expected
  
      expected = [0.1, 0.05, 0.025, 0.0125]
      assert lr_monitor.lrs["lr-SGD/pg2"] == expected
  
      expected = [0.1, 0.05, 0.025, 0.0125, 0.00625]
      assert lr_monitor.lrs["lr-Adam/pg1"] == expected
  
      expected = [0.1, 0.05, 0.025]
      assert lr_monitor.lrs["lr-Adam/pg2"] == expected
  
      expected = [0.1, 0.05]
      assert lr_monitor.lrs["lr-Adam/pg3"] == expected
  
imports: import pytest
  import torch
  from lightning.pytorch import Trainer
  from lightning.pytorch.callbacks import EarlyStopping, LearningRateMonitor
  from lightning.pytorch.callbacks.callback import Callback
  from lightning.pytorch.callbacks.finetuning import BackboneFinetuning
  from lightning.pytorch.demos.boring_classes import BoringModel
  from lightning.pytorch.loggers import CSVLogger
  from lightning.pytorch.utilities.exceptions import MisconfigurationException
  from torch import optim
  from tests_pytorch.helpers.datamodules import ClassifDataModule
  from tests_pytorch.helpers.runif import RunIf
  from tests_pytorch.helpers.simple_models import ClassificationModel
label_desc: Use image node_id 14 for calling a global function with example usage: test_multiple_optimizers_basefinetuning(tmpdir) and returns: self, optimizers,  schedulers