class_docstr: Precision plugin for training with Fully Sharded Data Parallel (FSDP).
  
  .. warning::  This is an :ref:`experimental <versioning:Experimental API>` feature.
  
  Args:
      precision: Full precision (32-true), half precision (16-true, bf16-true) or
          mixed precision (16-mixed, bf16-mixed).
      scaler: An optional :class:`torch.distributed.fsdp.sharded_grad_scaler.ShardedGradScaler` to use.
  
  Raises:
      ValueError:
          If unsupported ``precision`` is provided.
class_docstr_tok: ["Precision","plugin","for","training","with","Fully","Sharded","Data","Parallel","(","FSDP",")",".","..","warning",":",":","This","is","an",":","ref",":","`","experimental","<","versioning",":","Experimental","API",">","`","feature",".","Args",":","precision",":","Full","precision","(","32-true",")",",","half","precision","(","16-true",",","bf16-true",")","or","mixed","precision","(","16-mixed",",","bf16-mixed",")",".","scaler",":","An","optional",":","class",":","`","torch.distributed.fsdp.sharded_grad_scaler.ShardedGradScaler","`","to","use",".","Raises",":","ValueError",":","If","unsupported","``","precision","``","is","provided","."]
code: def optimizer_step(  # type: ignore[override]
      self,
      optimizer: Optimizable,
      model: "pl.LightningModule",
      closure: Callable[[], Any],
      **kwargs: Any,
  ) -> Any:
      if self.scaler is None:
          # skip scaler logic, as bfloat16 does not require scaler
          return super().optimizer_step(
              optimizer, model=model, closure=closure, **kwargs
          )
      closure_result = closure()
  
      if not _optimizer_handles_unscaling(optimizer):
          # Unscaling needs to be performed here in case we are going to apply gradient clipping.
          # Optimizers that perform unscaling in their `.step()` method are not supported (e.g., fused Adam).
          # Note: `unscale` happens after the closure is executed, but before the `on_before_optimizer_step` hook.
          self.scaler.unscale_(optimizer)  # type: ignore[arg-type]
  
      self._after_closure(model, optimizer)
      skipped_backward = closure_result is None
      # in manual optimization, the closure does not return a value
      if not model.automatic_optimization or not skipped_backward:
          # note: the scaler will skip the `optimizer.step` if nonfinite gradients are found
          step_output = self.scaler.step(optimizer, **kwargs)  # type: ignore[arg-type]
          self.scaler.update()
          return step_output
      return closure_result
  
imports: from typing import TYPE_CHECKING, Any, Callable, ContextManager, Dict, Optional
  import torch
  from lightning_utilities import apply_to_collection
  from torch import Tensor
  from typing_extensions import get_args, override
  import lightning.pytorch
  from lightning.fabric.plugins.precision.amp import _optimizer_handles_unscaling
  from lightning.fabric.plugins.precision.fsdp import _PRECISION_INPUT
  from lightning.fabric.plugins.precision.utils import _convert_fp_tensor, _DtypeContextManager
  from lightning.fabric.utilities.imports import _TORCH_GREATER_EQUAL_2_0
  from lightning.fabric.utilities.types import Optimizable
  from lightning.pytorch.plugins.precision.precision import Precision
  from lightning.pytorch.utilities.exceptions import MisconfigurationException
label_desc: Use image node_id 10 for calling the FSDPPrecision obj's underlying member method code with example usage: obj.optimizer_step(optimizer, model, closure) and returns: closure_result, super, step_output