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: Args:
      optimizer: wrapped optimizer.
      noise_multiplier: noise multiplier
      max_grad_norm: max grad norm used for gradient clipping
      expected_batch_size: batch_size used for averaging gradients. When using
          Poisson sampling averaging denominator can't be inferred from the
          actual batch size. Required is ``loss_reduction="mean"``, ignored if
          ``loss_reduction="sum"``
      loss_reduction: Indicates if the loss reduction (for aggregating the gradients)
          is a sum or a mean operation. Can take values "sum" or "mean"
      generator: torch.Generator() object used as a source of randomness for
          the noise
      secure_mode: if ``True`` uses noise generation approach robust to floating
          point arithmetic attacks.
          See :meth:`~opacus.optimizers.optimizer._generate_noise` for details
docstr_tok: ["Args",":","optimizer",":","wrapped","optimizer",".","noise_multiplier",":","noise","multiplier","max_grad_norm",":","max","grad","norm","used","for","gradient","clipping","expected_batch_size",":","batch_size","used","for","averaging","gradients",".","When","using","Poisson","sampling","averaging","denominator","ca","n't","be","inferred","from","the","actual","batch","size",".","Required","is","``","loss_reduction=","''","mean","''","``",",","ignored","if","``","loss_reduction=","''","sum","''","``","loss_reduction",":","Indicates","if","the","loss","reduction","(","for","aggregating","the","gradients",")","is","a","sum","or","a","mean","operation",".","Can","take","values","``","sum","''","or","``","mean","''","generator",":","torch.Generator","(",")","object","used","as","a","source","of","randomness","for","the","noise","secure_mode",":","if","``","True","``","uses","noise","generation","approach","robust","to","floating","point","arithmetic","attacks",".","See",":","meth",":","`","~opacus.optimizers.optimizer._generate_noise","`","for","details"]
code: def __init__(
      self,
      optimizer: Optimizer,
      *,
      noise_multiplier: float,
      max_grad_norm: float,
      expected_batch_size: Optional[int],
      loss_reduction: str = "mean",
      generator=None,
      secure_mode: bool = False,
  ):
      """
  
      Args:
          optimizer: wrapped optimizer.
          noise_multiplier: noise multiplier
          max_grad_norm: max grad norm used for gradient clipping
          expected_batch_size: batch_size used for averaging gradients. When using
              Poisson sampling averaging denominator can't be inferred from the
              actual batch size. Required is ``loss_reduction="mean"``, ignored if
              ``loss_reduction="sum"``
          loss_reduction: Indicates if the loss reduction (for aggregating the gradients)
              is a sum or a mean operation. Can take values "sum" or "mean"
          generator: torch.Generator() object used as a source of randomness for
              the noise
          secure_mode: if ``True`` uses noise generation approach robust to floating
              point arithmetic attacks.
              See :meth:`~opacus.optimizers.optimizer._generate_noise` for details
      """
      if loss_reduction not in ("mean", "sum"):
          raise ValueError(
              f"Unexpected value for loss_reduction: {loss_reduction}"
          )
  
      if loss_reduction == "mean" and expected_batch_size is None:
          raise ValueError(
              "You must provide expected batch size of the loss reduction is mean"
          )
  
      self.original_optimizer = optimizer
      self.noise_multiplier = noise_multiplier
      self.max_grad_norm = max_grad_norm
      self.loss_reduction = loss_reduction
      self.expected_batch_size = expected_batch_size
      self.step_hook = None
      self.generator = generator
      self.secure_mode = secure_mode
  
      self.param_groups = self.original_optimizer.param_groups
      self.defaults = self.original_optimizer.defaults
      self.state = self.original_optimizer.state
      self._step_skip_queue = []
      self._is_last_step_skipped = False
  
      for p in self.params:
          p.summed_grad = None
  
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 1 to create a new DPOptimizer object from inherited base classes: Optimizer with example: obj = DPOptimizer(optimizer)