code: def test_step_with_optimizer_closure_with_different_frequencies(
      mock_sgd_step, mock_adam_step, tmpdir
  ):
      class TestModel(BoringModel):
          def __init__(self):
              super().__init__()
              self.automatic_optimization = False
  
          def on_train_start(self) -> None:
              mock_sgd_step.reset_mock()
              mock_adam_step.reset_mock()
  
          def training_step(self, batch, batch_idx):
              # emulate gans training
              opt_gen, opt_dis = self.optimizers()
  
              # Note: Be careful, don't log on the same key in self.log in both closure
              # as they will be aggregated together on epoch_end
  
              def compute_loss():
                  x = batch[0]
                  x = F.dropout(x, 0.1)
                  predictions = self(x)
                  predictions = F.dropout(predictions, 0.1)
                  return self.loss(predictions)
  
              def gen_closure():
                  loss_gen = compute_loss()
                  self.log(
                      "loss_gen", loss_gen, on_step=True, on_epoch=True
                  )
                  self.manual_backward(loss_gen)
  
              def dis_closure():
                  loss_dis = compute_loss()
                  self.log(
                      "loss_dis", loss_dis, on_step=True, on_epoch=True
                  )
                  self.manual_backward(loss_dis)
  
              # this will accumulate gradients for 2 batches and then call opt_gen.step()
              gen_closure()
              if batch_idx % 2 == 0:
                  # passing a custom kwarg
                  opt_gen.step(closure=gen_closure, optim="sgd")
                  opt_gen.zero_grad()
  
              # update discriminator every 4 baches
              # therefore, no gradient accumulation for discriminator
              if batch_idx % 4 == 0:
                  opt_dis.step(closure=dis_closure)
                  opt_dis.zero_grad()
  
          def configure_optimizers(self):
              optimizer_gen = torch.optim.SGD(
                  self.layer.parameters(), lr=0.1
              )
              optimizer_dis = torch.optim.Adam(
                  self.layer.parameters(), lr=0.001
              )
              return [optimizer_gen, optimizer_dis]
  
      model = TestModel()
      model.val_dataloader = None
  
      limit_train_batches = 8
      trainer = Trainer(
          default_root_dir=tmpdir,
          limit_train_batches=limit_train_batches,
          limit_val_batches=2,
          max_epochs=1,
          log_every_n_steps=1,
      )
  
      trainer.fit(model)
      assert mock_sgd_step.mock_calls == [
          call(closure=ANY, optim="sgd") for _ in range(4)
      ]
      assert mock_adam_step.mock_calls == [
          call(closure=ANY) for _ in range(2)
      ]
      assert trainer.global_step == 4 + 2
  
imports: import collections
  import contextlib
  from copy import deepcopy
  from unittest import mock
  from unittest.mock import ANY, call, patch
  import pytest
  import torch
  import torch.distributed
  import torch.nn.functional
  from lightning.fabric.utilities.exceptions import MisconfigurationException
  from lightning.fabric.utilities.imports import _TORCH_GREATER_EQUAL_2_0
  from lightning.pytorch import Trainer, seed_everything
  from lightning.pytorch.demos.boring_classes import BoringModel, ManualOptimBoringModel
  from lightning.pytorch.strategies import Strategy
  from tests_pytorch.helpers.runif import RunIf
label_desc: Use image node_id 10 for calling a global function with example usage: test_step_with_optimizer_closure_with_different_frequencies(mock_sgd_step, mock_adam_step, tmpdir) and returns: list, self