class_docstr: Learning rate finder handler for supervised trainers.
  
  While attached, the handler increases the learning rate in between two
  boundaries in a linear or exponential manner. It provides valuable
  information on how well the network can be trained over a range of learning
  rates and what can be an optimal learning rate.
  
  Examples:
      .. code-block:: python
  
          from ignite.handlers import FastaiLRFinder
  
          trainer = ...
          model = ...
          optimizer = ...
  
          lr_finder = FastaiLRFinder()
          to_save = {"model": model, "optimizer": optimizer}
  
          with lr_finder.attach(trainer, to_save=to_save) as trainer_with_lr_finder:
              trainer_with_lr_finder.run(dataloader)
  
          # Get lr_finder results
          lr_finder.get_results()
  
          # Plot lr_finder results (requires matplotlib)
          lr_finder.plot()
  
          # get lr_finder suggestion for lr
          lr_finder.lr_suggestion()
  
  
  Note:
      When context manager is exited all LR finder's handlers are removed.
  
  Note:
      Please, also keep in mind that all other handlers attached the trainer will be executed during LR finder's run.
  
  Note:
      This class may require `matplotlib` package to be installed to plot learning rate range test:
  
      .. code-block:: bash
  
          pip install matplotlib
  
  
  References:
  
      Cyclical Learning Rates for Training Neural Networks:
      https://arxiv.org/abs/1506.01186
  
      fastai/lr_find: https://github.com/fastai/fastai
  
  .. versionadded:: 0.4.6
docstr: Attaches lr_finder to a given trainer. It also resets model and optimizer at the end of the run.
  
  Args:
      trainer: lr_finder is attached to this trainer. Please, keep in mind that all attached handlers
          will be executed.
      to_save: dictionary with optimizer and other objects that needs to be restored after running
          the LR finder. For example, ``to_save={'optimizer': optimizer, 'model': model}``.
          It should contain "optimizer" key for the optimizer.
          Also all objects should implement ``state_dict`` and ``load_state_dict`` methods.
      output_transform: function that transforms the trainer's ``state.output`` after each
          iteration. It must return the loss of that iteration.
      num_iter: number of iterations for lr schedule between base lr and end_lr. Default, it will
          run for ``trainer.state.epoch_length * trainer.state.max_epochs``.
      start_lr: lower bound for lr search. Default, Learning Rate specified with the optimizer.
      end_lr: upper bound for lr search. Default, 10.0.
      step_mode: "exp" or "linear", which way should the lr be increased from ``start_lr``
          to ``end_lr``. Default, "exp".
      smooth_f: loss smoothing factor in range ``[0, 1)``. Default, 0.05
      diverge_th: Used for stopping the search when ``current loss > diverge_th * best_loss``.
          Default, 5.0.
  
  Returns:
      trainer_with_lr_finder (trainer used for finding the lr)
  
  Examples:
      .. code-block:: python
  
          to_save = {"model": model, "optimizer": optimizer}
          with lr_finder.attach(trainer, to_save=to_save) as trainer_with_lr_finder:
              trainer_with_lr_finder.run(dataloader)
  
  Note:
      lr_finder cannot be attached to more than one trainer at a time.
docstr_tok: ["Attaches","lr_finder","to","a","given","trainer",".","It","also","resets","model","and","optimizer","at","the","end","of","the","run",".","Args",":","trainer",":","lr_finder","is","attached","to","this","trainer",".","Please",",","keep","in","mind","that","all","attached","handlers","will","be","executed",".","to_save",":","dictionary","with","optimizer","and","other","objects","that","needs","to","be","restored","after","running","the","LR","finder",".","For","example",",","``","to_save=","{","'optimizer","'",":","optimizer",",","'model","'",":","model","}","``",".","It","should","contain","``","optimizer","''","key","for","the","optimizer",".","Also","all","objects","should","implement","``","state_dict","``","and","``","load_state_dict","``","methods",".","output_transform",":","function","that","transforms","the","trainer","'s","``","state.output","``","after","each","iteration",".","It","must","return","the","loss","of","that","iteration",".","num_iter",":","number","of","iterations","for","lr","schedule","between","base","lr","and","end_lr",".","Default",",","it","will","run","for","``","trainer.state.epoch_length","*","trainer.state.max_epochs","``",".","start_lr",":","lower","bound","for","lr","search",".","Default",",","Learning","Rate","specified","with","the","optimizer",".","end_lr",":","upper","bound","for","lr","search",".","Default",",","10.0.","step_mode",":","``","exp","''","or","``","linear","''",",","which","way","should","the","lr","be","increased","from","``","start_lr","``","to","``","end_lr","``",".","Default",",","``","exp","''",".","smooth_f",":","loss","smoothing","factor","in","range","``","[","0",",","1",")","``",".","Default",",","0.05","diverge_th",":","Used","for","stopping","the","search","when","``","current","loss",">","diverge_th","*","best_loss","``",".","Default",",","5.0",".","Returns",":","trainer_with_lr_finder","(","trainer","used","for","finding","the","lr",")","Examples",":","..","code-block",":",":","python","to_save","=","{","``","model","''",":","model",",","``","optimizer","''",":","optimizer","}","with","lr_finder.attach","(","trainer",",","to_save=to_save",")","as","trainer_with_lr_finder",":","trainer_with_lr_finder.run","(","dataloader",")","Note",":","lr_finder","can","not","be","attached","to","more","than","one","trainer","at","a","time","."]
code: def attach(
      self,
      trainer: Engine,
      to_save: Mapping,
      output_transform: Callable = lambda output: output,
      num_iter: Optional[int] = None,
      start_lr: Optional[Union[float, List[float]]] = None,
      end_lr: Optional[Union[float, List[float]]] = 10.0,
      step_mode: str = "exp",
      smooth_f: float = 0.05,
      diverge_th: float = 5.0,
  ) -> Any:
      """Attaches lr_finder to a given trainer. It also resets model and optimizer at the end of the run.
  
      Args:
          trainer: lr_finder is attached to this trainer. Please, keep in mind that all attached handlers
              will be executed.
          to_save: dictionary with optimizer and other objects that needs to be restored after running
              the LR finder. For example, ``to_save={'optimizer': optimizer, 'model': model}``.
              It should contain "optimizer" key for the optimizer.
              Also all objects should implement ``state_dict`` and ``load_state_dict`` methods.
          output_transform: function that transforms the trainer's ``state.output`` after each
              iteration. It must return the loss of that iteration.
          num_iter: number of iterations for lr schedule between base lr and end_lr. Default, it will
              run for ``trainer.state.epoch_length * trainer.state.max_epochs``.
          start_lr: lower bound for lr search. Default, Learning Rate specified with the optimizer.
          end_lr: upper bound for lr search. Default, 10.0.
          step_mode: "exp" or "linear", which way should the lr be increased from ``start_lr``
              to ``end_lr``. Default, "exp".
          smooth_f: loss smoothing factor in range ``[0, 1)``. Default, 0.05
          diverge_th: Used for stopping the search when ``current loss > diverge_th * best_loss``.
              Default, 5.0.
  
      Returns:
          trainer_with_lr_finder (trainer used for finding the lr)
  
      Examples:
          .. code-block:: python
  
              to_save = {"model": model, "optimizer": optimizer}
              with lr_finder.attach(trainer, to_save=to_save) as trainer_with_lr_finder:
                  trainer_with_lr_finder.run(dataloader)
  
      Note:
          lr_finder cannot be attached to more than one trainer at a time.
      """
      if not isinstance(to_save, Mapping):
          raise TypeError(
              f"Argument to_save should be a mapping, but given {type(to_save)}"
          )
  
      Checkpoint._check_objects(to_save, "state_dict")
      Checkpoint._check_objects(to_save, "load_state_dict")
  
      if "optimizer" not in to_save:
          raise ValueError(
              "Mapping to_save should contain 'optimizer' key"
          )
  
      if not isinstance(to_save["optimizer"], torch.optim.Optimizer):
          raise TypeError(
              f"Object to_save['optimizer'] should be torch optimizer, but given {type(to_save['optimizer'])}"
          )
  
      if smooth_f < 0 or smooth_f >= 1:
          raise ValueError("smooth_f is outside the range [0, 1]")
      if diverge_th < 1:
          raise ValueError("diverge_th should be larger than 1")
      if step_mode not in ["exp", "linear"]:
          raise ValueError(
              f"step_mode should be 'exp' or 'linear', but given {step_mode}"
          )
      if num_iter is not None:
          if not isinstance(num_iter, int):
              raise TypeError(
                  f"if provided, num_iter should be an integer, but give {num_iter}"
              )
          if num_iter <= 0:
              raise ValueError(
                  f"if provided, num_iter should be positive, but give {num_iter}"
              )
  
      optimizer = to_save["optimizer"]
      if start_lr is None:
          start_lrs = [pg["lr"] for pg in optimizer.param_groups]
      elif isinstance(start_lr, float):
          start_lrs = [start_lr] * len(optimizer.param_groups)
      elif isinstance(start_lr, list):
          if len(start_lr) != len(optimizer.param_groups):
              raise ValueError(
                  "Number of values of start_lr should be equal to optimizer values."
                  f"start_lr values:{len(start_lr)} optimizer values: {len(optimizer.param_groups)}"
              )
          start_lrs = start_lr
      else:
          raise TypeError(
              f"start_lr should be a float or list of floats, but given {type(start_lr)}"
          )
  
      if isinstance(end_lr, float):
          end_lrs = [end_lr] * len(optimizer.param_groups)
      elif isinstance(end_lr, list):
          if len(end_lr) != len(optimizer.param_groups):
              raise ValueError(
                  "Number of values of end_lr should be equal to optimizer values."
                  f"end_lr values:{len(end_lr)} optimizer values: {len(optimizer.param_groups)}"
              )
          end_lrs = end_lr
      else:
          raise TypeError(
              f"end_lr should be a float or list of floats, but given {type(end_lr)}"
          )
  
      for start, end in zip(start_lrs, end_lrs):
          if start >= end:
              raise ValueError(
                  f"start_lr must be less than end_lr, start_lr={start_lr} vs end_lr={end_lr}"
              )
  
      # store to_save
      with tempfile.TemporaryDirectory() as tmpdirname:
          obj = {k: o.state_dict() for k, o in to_save.items()}
          # add trainer
          obj["trainer"] = trainer.state_dict()
          cache_filepath = (
              Path(tmpdirname) / "ignite_lr_finder_cache.pt"
          )
          torch.save(obj, cache_filepath.as_posix())
  
          # Attach handlers
          if not trainer.has_event_handler(self._run):
              trainer.add_event_handler(
                  Events.STARTED,
                  self._run,
                  optimizer,
                  output_transform,
                  num_iter,
                  start_lrs,
                  end_lrs,
                  step_mode,
                  smooth_f,
                  diverge_th,
              )
          if not trainer.has_event_handler(self._warning):
              trainer.add_event_handler(Events.COMPLETED, self._warning)
          if not trainer.has_event_handler(self._reset):
              trainer.add_event_handler(Events.COMPLETED, self._reset)
  
          yield trainer
          self._detach(trainer)
          # restore to_save and reset trainer's state
          obj = torch.load(cache_filepath.as_posix())
          trainer.load_state_dict(obj["trainer"])
          for k, o in obj.items():
              if k in to_save:
                  to_save[k].load_state_dict(o)
  
imports: import contextlib
  import logging
  import tempfile
  import warnings
  from math import ceil
  from pathlib import Path
  from typing import Any, Callable, Dict, List, Mapping, Optional, Union
  import torch
  from torch.optim import Optimizer
  from torch.optim.lr_scheduler import _LRScheduler
  import ignite.distributed
  from ignite.engine import Engine, Events
  from ignite.handlers import Checkpoint
  from ignite.handlers.param_scheduler import LRScheduler, ParamGroupScheduler, PiecewiseLinear
label_desc: Use image node_id 12 for calling the FastaiLRFinder obj's underlying member method code with example usage: obj.attach(trainer, to_save, output_transform, num_iter, start_lr, end_lr, step_mode, smooth_f, diverge_th) without return types