docstr: Gets called at the end of an epoch.
  
  Arguments
  ---------
  stage : sb.Stage
      One of sb.Stage.TRAIN, sb.Stage.VALID, sb.Stage.TEST
  stage_loss : float
      The average loss for all of the data processed in this stage.
  epoch : int
      The currently-starting epoch. This is passed
      `None` during the test stage.
docstr_tok: ["Gets","called","at","the","end","of","an","epoch",".","Arguments","--","--","--","--","-","stage",":","sb.Stage","One","of","sb.Stage.TRAIN",",","sb.Stage.VALID",",","sb.Stage.TEST","stage_loss",":","float","The","average","loss","for","all","of","the","data","processed","in","this","stage",".","epoch",":","int","The","currently-starting","epoch",".","This","is","passed","`","None","`","during","the","test","stage","."]
code: def on_stage_end(self, stage, stage_loss, epoch):
      """Gets called at the end of an epoch.
  
      Arguments
      ---------
      stage : sb.Stage
          One of sb.Stage.TRAIN, sb.Stage.VALID, sb.Stage.TEST
      stage_loss : float
          The average loss for all of the data processed in this stage.
      epoch : int
          The currently-starting epoch. This is passed
          `None` during the test stage.
      """
      if stage == sb.Stage.TRAIN:
          self.train_stats = stage_loss
  
      # At the end of validation, we can write
      elif (
          stage == sb.Stage.VALID
          and epoch % self.hparams.evaluation_interval == 0
      ):
          # delete vocoder and asr to free memory for next training epoch
          del self.test_vocoder
          del self.test_asr
  
          stage_stats = {"loss": stage_loss}
          stage_stats["ACC"] = self.acc_metric.summarize()
          stage_stats["BLEU"] = self.bleu_metric.summarize("BLEU")
  
          output_progress_sample = (
              self.hparams.progress_samples
              and epoch % self.hparams.progress_samples_interval == 0
          )
  
          if output_progress_sample:
              self._save_progress_sample(epoch)
  
          current_epoch = self.hparams.epoch_counter.current
          lr_model = self.hparams.noam_annealing.current_lr
          lr_wav2vec = 0.0
  
          if not self.hparams.wav2vec2_frozen:
              (
                  lr_wav2vec,
                  new_lr_wav2vec,
              ) = self.hparams.wav2vec_annealing(stage_stats["ACC"])
              sb.nnet.schedulers.update_learning_rate(
                  self.wav2vec_optimizer, new_lr_wav2vec
              )
  
          self.hparams.train_logger.log_stats(
              stats_meta={
                  "epoch": current_epoch,
                  "lr_model": lr_model,
                  "lr_wav2vec": lr_wav2vec,
              },
              train_stats={"loss": self.train_stats},
              valid_stats=stage_stats,
          )
  
          # Save the current checkpoint and delete previous checkpoints.
          self.checkpointer.save_and_keep_only(
              meta={
                  "ACC": stage_stats["ACC"],
                  "BLEU": stage_stats["BLEU"],
                  "epoch": epoch,
              },
              max_keys=["BLEU"],
              num_to_keep=10,
          )
  
      elif stage == sb.Stage.TEST:
          stage_stats = {"loss": stage_loss}
          stage_stats["BLEU"] = self.bleu_metric.summarize("BLEU")
  
          self.hparams.train_logger.log_stats(
              stats_meta={
                  "Epoch loaded": self.hparams.epoch_counter.current
              },
              test_stats=stage_stats,
          )
  
          logger.info(
              f"BLEU score: {round(self.bleu_metric.summarize('BLEU'), 2)}"
          )
          bleu_file = pl.Path(self.hparams.output_folder) / "bleu.txt"
          with open(bleu_file, "a+", encoding="utf-8") as w:
              self.bleu_metric.write_stats(w)
  
imports: import sys
  import torch
  import logging
  import pathlib
  from hyperpyyaml import load_hyperpyyaml
  import speechbrain
  from speechbrain.inference.vocoders import UnitHIFIGAN
  from speechbrain.inference.ASR import EncoderDecoderASR
  import tqdm
  import torchaudio
  import numpy
  from torch.nn.parallel import DistributedDataParallel
label_desc: Use image node_id 8 for calling the S2UT obj's underlying member method code with example usage: obj.on_stage_end(stage, stage_loss, epoch) without return types