class_docstr: Cosine learning rate decay
  
  Args:
      max_epochs (int): max epochs for the training process.
          if you commbine cosine decay with warmup, it is recommended that
          the max_iters is much larger than the warmup iter
      use_warmup (bool): whether to use warmup. Default: True.
      min_lr_ratio (float): minimum learning rate ratio. Default: 0.
      last_plateau_epochs (int): use minimum learning rate in
          the last few epochs. Default: 0.
class_docstr_tok: ["Cosine","learning","rate","decay","Args",":","max_epochs","(","int",")",":","max","epochs","for","the","training","process",".","if","you","commbine","cosine","decay","with","warmup",",","it","is","recommended","that","the","max_iters","is","much","larger","than","the","warmup","iter","use_warmup","(","bool",")",":","whether","to","use","warmup",".","Default",":","True",".","min_lr_ratio","(","float",")",":","minimum","learning","rate","ratio",".","Default",":","0.","last_plateau_epochs","(","int",")",":","use","minimum","learning","rate","in","the","last","few","epochs",".","Default",":","0","."]
code: def __call__(
      self, base_lr=None, boundary=None, value=None, step_per_epoch=None
  ):
      assert (
          base_lr is not None
      ), "either base LR or values should be provided"
  
      max_iters = self.max_epochs * int(step_per_epoch)
      last_plateau_iters = self.last_plateau_epochs * int(
          step_per_epoch
      )
      min_lr = base_lr * self.min_lr_ratio
      if boundary is not None and value is not None and self.use_warmup:
          # use warmup
          warmup_iters = len(boundary)
          for i in range(int(boundary[-1]), max_iters):
              boundary.append(i)
              if i < max_iters - last_plateau_iters:
                  decayed_lr = min_lr + (base_lr - min_lr) * 0.5 * (
                      math.cos(
                          (i - warmup_iters)
                          * math.pi
                          / (
                              max_iters
                              - warmup_iters
                              - last_plateau_iters
                          )
                      )
                      + 1
                  )
                  value.append(decayed_lr)
              else:
                  value.append(min_lr)
          return optimizer.lr.PiecewiseDecay(boundary, value)
      elif last_plateau_iters > 0:
          # not use warmup, but set `last_plateau_epochs` > 0
          boundary = []
          value = []
          for i in range(max_iters):
              if i < max_iters - last_plateau_iters:
                  decayed_lr = min_lr + (base_lr - min_lr) * 0.5 * (
                      math.cos(
                          i * math.pi / (max_iters - last_plateau_iters)
                      )
                      + 1
                  )
                  value.append(decayed_lr)
              else:
                  value.append(min_lr)
              if i > 0:
                  boundary.append(i)
          return optimizer.lr.PiecewiseDecay(boundary, value)
  
      return optimizer.lr.CosineAnnealingDecay(
          base_lr, T_max=max_iters, eta_min=min_lr
      )
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import sys
  import math
  import paddle
  import paddle.nn
  import paddle.optimizer
  import paddle.regularizer
  from ppdet.core.workspace import register, serializable
  import copy
  from .adamw import AdamWDL, build_adamwdl
  from ppdet.utils.logger import setup_logger
label_desc: Use image node_id 2 for calling the CosineDecay obj's underlying member method code with example usage: obj.__call__(base_lr, boundary, value, step_per_epoch) and returns: optimizer, optimizer, optimizer