hunk.code_window: def update_summary(epoch, train_metrics, eval_metrics, filename, write_header=False, log_wandb=False):
       rowd = OrderedDict(epoch=epoch)
       rowd.update([('train_' + k, v) for k, v in train_metrics.items()])
       rowd.update([('eval_' + k, v) for k, v in eval_metrics.items()])
       if log_wandb:
           wandb.log(rowd)
       with open(filename, mode='a') as cf:
           dw = csv.DictWriter(cf, fieldnames=rowd.keys())
           if write_header:  # first iteration (epoch == 1 can't be used)
  
hunk.labels: keep keep keep keep keep replace replace keep keep keep
hunk.file_path: timm/utils/summary.py
hunk.type: replace
file: """ TanH Scheduler
  
  TanH schedule with warmup, cycle/restarts, noise.
  
  Hacked together by / Copyright 2020 Ross Wightman
  """
  import logging
  import math
  import numpy as np
  import torch
  
  from .scheduler import Scheduler
  
  
  _logger = logging.getLogger(__name__)
  
  
  class TanhLRScheduler(Scheduler):
      """
      Hyberbolic-Tangent decay with restarts.
      This is described in the paper https://arxiv.org/abs/1806.01593
      """
  
      def __init__(self,
                   optimizer: torch.optim.Optimizer,
                   t_initial: int,
                   lb: float = -6.,
                   ub: float = 4.,
                   t_mul: float = 1.,
                   lr_min: float = 0.,
                   decay_rate: float = 1.,
                   warmup_t=0,
                   warmup_lr_init=0,
                   warmup_prefix=False,
                   cycle_limit=0,
                   t_in_epochs=True,
                   noise_range_t=None,
                   noise_pct=0.67,
                   noise_std=1.0,
                   noise_seed=42,
                   initialize=True) -> None:
          super().__init__(
              optimizer, param_group_field="lr",
              noise_range_t=noise_range_t, noise_pct=noise_pct, noise_std=noise_std, noise_seed=noise_seed,
              initialize=initialize)
  
          assert t_initial > 0
          assert lr_min >= 0
          assert lb < ub
          assert cycle_limit >= 0
          assert warmup_t >= 0
          assert warmup_lr_init >= 0
          self.lb = lb
          self.ub = ub
          self.t_initial = t_initial
          self.t_mul = t_mul
          self.lr_min = lr_min
          self.decay_rate = decay_rate
          self.cycle_limit = cycle_limit
          self.warmup_t = warmup_t
          self.warmup_lr_init = warmup_lr_init
          self.warmup_prefix = warmup_prefix
          self.t_in_epochs = t_in_epochs
          if self.warmup_t:
              t_v = self.base_values if self.warmup_prefix else self._get_lr(self.warmup_t)
              self.warmup_steps = [(v - warmup_lr_init) / self.warmup_t for v in t_v]
              super().update_groups(self.warmup_lr_init)
          else:
              self.warmup_steps = [1 for _ in self.base_values]
  
      def _get_lr(self, t):
          if t < self.warmup_t:
              lrs = [self.warmup_lr_init + t * s for s in self.warmup_steps]
          else:
              if self.warmup_prefix:
                  t = t - self.warmup_t
  
              if self.t_mul != 1:
                  i = math.floor(math.log(1 - t / self.t_initial * (1 - self.t_mul), self.t_mul))
                  t_i = self.t_mul ** i * self.t_initial
                  t_curr = t - (1 - self.t_mul ** i) / (1 - self.t_mul) * self.t_initial
              else:
                  i = t // self.t_initial
                  t_i = self.t_initial
                  t_curr = t - (self.t_initial * i)
  
              if self.cycle_limit == 0 or (self.cycle_limit > 0 and i < self.cycle_limit):
                  gamma = self.decay_rate ** i
                  lr_min = self.lr_min * gamma
                  lr_max_values = [v * gamma for v in self.base_values]
  
                  tr = t_curr / t_i
                  lrs = [
                      lr_min + 0.5 * (lr_max - lr_min) * (1 - math.tanh(self.lb * (1. - tr) + self.ub * tr))
                      for lr_max in lr_max_values
                  ]
              else:
                  lrs = [self.lr_min * (self.decay_rate ** self.cycle_limit) for _ in self.base_values]
          return lrs
  
      def get_epoch_values(self, epoch: int):
          if self.t_in_epochs:
              return self._get_lr(epoch)
          else:
              return None
  
      def get_update_values(self, num_updates: int):
          if not self.t_in_epochs:
              return self._get_lr(num_updates)
          else:
              return None
  
      def get_cycle_length(self, cycles=0):
          if not cycles:
              cycles = self.cycle_limit
          cycles = max(1, cycles)
          if self.t_mul == 1.0:
              return self.t_initial * cycles
          else:
              return int(math.floor(-self.t_initial * (self.t_mul ** cycles - 1) / (1 - self.t_mul)))
  