docstr: Gets called at the end of a epoch.
docstr_tok: ["Gets","called","at","the","end","of","a","epoch","."]
code: def on_stage_end(self, stage, stage_loss, epoch):
      """Gets called at the end of a epoch."""
      if stage == sb.Stage.TRAIN:
          self.train_loss = stage_loss
      elif self.hparams.enable_metrics:
          per = self.per_metrics.summarize("error_rate")
      ckpt_predicate, ckpt_meta, min_keys = None, {}, None
      if stage == sb.Stage.VALID:
          if (
              isinstance(
                  self.hparams.lr_annealing,
                  sb.nnet.schedulers.NewBobScheduler,
              )
              and self.hparams.enable_metrics
          ):
              old_lr, new_lr = self.hparams.lr_annealing(per)
          elif isinstance(
              self.hparams.lr_annealing,
              sb.nnet.schedulers.ReduceLROnPlateau,
          ):
              old_lr, new_lr = self.hparams.lr_annealing(
                  optim_list=[self.optimizer],
                  current_epoch=epoch,
                  current_loss=self.train_loss,
              )
          else:
              old_lr, new_lr = self.hparams.lr_annealing(epoch)
          sb.nnet.schedulers.update_learning_rate(
              self.optimizer, new_lr
          )
  
          stats = {
              "stats_meta": {"epoch": epoch, "lr": old_lr},
              "train_stats": {"loss": self.train_loss},
              "valid_stats": {"loss": stage_loss},
          }
          if self.hparams.enable_metrics:
              stats["valid_stats"].update(
                  {
                      "seq_loss": self.seq_metrics.summarize("average"),
                      "PER": per,
                  }
              )
  
              if self.mode == TrainMode.HOMOGRAPH:
                  per_homograph = self.per_metrics_homograph.summarize(
                      "error_rate"
                  )
                  stats["valid_stats"].update(
                      {
                          "seq_loss_homograph": self.seq_metrics_homograph.summarize(
                              "average"
                          ),
                          "PER_homograph": per_homograph,
                      }
                  )
                  ckpt_meta = {
                      "PER_homograph": per_homograph,
                      "PER": per,
                  }
                  min_keys = ["PER_homograph"]
                  ckpt_predicate = self._has_homograph_per
              else:
                  ckpt_meta = {"PER": per}
                  min_keys = ["PER"]
              hp.report_result(stats["valid_stats"])
  
          stats = self._add_stats_prefix(stats)
          self.hparams.train_logger.log_stats(**stats)
          if self.hparams.use_tensorboard:
              self.hparams.tensorboard_train_logger.log_stats(**stats)
              self.save_samples()
          if (
              self.hparams.ckpt_enable
              and epoch % self.hparams.ckpt_frequency == 0
          ):
              ckpt_meta["step"] = self.train_step["name"]
              self.checkpointer.save_and_keep_only(
                  meta=ckpt_meta,
                  min_keys=min_keys,
                  ckpt_predicate=ckpt_predicate,
              )
          if self.hparams.enable_interim_reports:
              if self.hparams.enable_metrics:
                  self._write_reports(epoch, final=False)
  
          self.epoch_counter.update_metric(per)
  
      if stage == sb.Stage.TEST:
          test_stats = {"loss": stage_loss}
          if self.hparams.enable_metrics:
              test_stats["PER"] = per
          self.hparams.train_logger.log_stats(
              stats_meta={"Epoch loaded": self.epoch_counter.current},
              test_stats=test_stats,
          )
          if self.hparams.enable_metrics:
              self._write_reports(epoch)
  
imports: from speechbrain.dataio.dataset import FilteredSortedDynamicItemDataset, DynamicItemDataset
  from speechbrain.dataio.sampler import BalancingDataSampler
  from speechbrain.utils.data_utils import undo_padding
  import datasets
  import logging
  import os
  import random
  import speechbrain
  import sys
  from enum import Enum
  from collections import namedtuple
  from hyperpyyaml import load_hyperpyyaml
  from functools import partial
  from speechbrain.utils.distributed import run_on_main
  from speechbrain.utils.pretrained import save_for_pretrained
  from speechbrain.lobes.models.g2p.dataio import enable_eos_bos, grapheme_pipeline, phoneme_pipeline, tokenizer_encode_pipeline, add_bos_eos, get_sequence_key, phonemes_to_label
  from speechbrain.dataio.wer import print_alignments
  from speechbrain.wordemb.util import expand_to_chars
  from io import StringIO
  from speechbrain.utils import hpopt
  import numpy
label_desc: Use image node_id 12 for calling the G2PBrain obj's underlying member method code with example usage: obj.on_stage_end(stage, stage_loss, epoch) without return types