class_docstr: ``torch.optim.Optimizer`` wrapper that adds additional functionality to clip per
  sample gradients and add Gaussian noise.
  
  Can be used with any ``torch.optim.Optimizer`` subclass as an underlying optimizer.
  ``DPOptimzer`` assumes that parameters over which it performs optimization belong
  to GradSampleModule and therefore have the ``grad_sample`` attribute.
  
  On a high level ``DPOptimizer``'s step looks like this:
  1) Aggregate ``p.grad_sample`` over all parameters to calculate per sample norms
  2) Clip ``p.grad_sample`` so that per sample norm is not above threshold
  3) Aggregate clipped per sample gradients into ``p.grad``
  4) Add Gaussian noise to ``p.grad`` calibrated to a given noise multiplier and
  max grad norm limit (``std = noise_multiplier * max_grad_norm``).
  5) Call underlying optimizer to perform optimization step
  
  Examples:
      >>> module = MyCustomModel()
      >>> optimizer = torch.optim.SGD(module.parameters(), lr=0.1)
      >>> dp_optimizer = DPOptimizer(
      ...     optimizer=optimizer,
      ...     noise_multiplier=1.0,
      ...     max_grad_norm=1.0,
      ...     expected_batch_size=4,
      ... )
docstr: Checks if next step should be skipped by the optimizer.
  This is for large Poisson batches that get split into smaller physical batches
  to fit on the device. Batches that do not correspond to the end of a Poisson
  batch or thus `skipped` as their gradient gets accumulated for one big step.
docstr_tok: ["Checks","if","next","step","should","be","skipped","by","the","optimizer",".","This","is","for","large","Poisson","batches","that","get","split","into","smaller","physical","batches","to","fit","on","the","device",".","Batches","that","do","not","correspond","to","the","end","of","a","Poisson","batch","or","thus","`","skipped","`","as","their","gradient","gets","accumulated","for","one","big","step","."]
code: def _check_skip_next_step(self, pop_next=True):
      """
      Checks if next step should be skipped by the optimizer.
      This is for large Poisson batches that get split into smaller physical batches
      to fit on the device. Batches that do not correspond to the end of a Poisson
      batch or thus `skipped` as their gradient gets accumulated for one big step.
      """
      if self._step_skip_queue:
          if pop_next:
              return self._step_skip_queue.pop(0)
          else:
              return self._step_skip_queue[0]
      else:
          return False
  
imports: from __future__ import annotations
  import logging
  from typing import Callable, List, Optional, Union
  import torch
  from opacus.optimizers.utils import params
  from opt_einsum.contract import contract
  from torch import nn
  from torch.optim import Optimizer
label_desc: Use image node_id 4 for calling the DPOptimizer obj's underlying member method code with example usage: obj._check_skip_next_step(pop_next) and returns: False, self, self