code: def evaluate_and_save(
      args,
      vocab,
      data,
      trainer,
      best_loss,
      model_file,
      checkpoint_file,
      writer=None,
  ):
      """
      Run an evaluation over entire dataset, print progress and save the model if necessary.
      """
      start_time = time.time()
      loss = evaluate_epoch(
          args, vocab, data, trainer.model, trainer.criterion
      )
      ppl = math.exp(loss)
      elapsed = int(time.time() - start_time)
      # TODO: step the scheduler less often when the eval frequency is higher
      previous_lr = get_current_lr(trainer, args)
      trainer.scheduler.step(loss)
      current_lr = get_current_lr(trainer, args)
      if previous_lr != current_lr:
          logger.info("Updating learning rate to %f", current_lr)
      logger.info(
          "| eval checkpoint @ global step {:10d} | time elapsed {:6d}s | loss {:5.2f} | ppl {:8.2f}".format(
              trainer.global_step,
              elapsed,
              loss,
              ppl,
          )
      )
      if best_loss is None or loss < best_loss:
          best_loss = loss
          trainer.save(model_file, full=False)
          logger.info(
              "new best model saved at step {:10d}".format(
                  trainer.global_step
              )
          )
      if writer:
          writer.add_scalar(
              "dev_loss", loss, global_step=trainer.global_step
          )
          writer.add_scalar(
              "dev_ppl", ppl, global_step=trainer.global_step
          )
      if checkpoint_file:
          trainer.save(checkpoint_file, full=True)
          logger.info(
              "new checkpoint saved at step {:10d}".format(
                  trainer.global_step
              )
          )
  
      return loss, ppl, best_loss
  
imports: import argparse
  from copy import copy
  import logging
  import lzma
  import math
  import os
  import random
  import time
  from types import GeneratorType
  import numpy
  import torch
  from stanza.models.common.char_model import build_charlm_vocab, CharacterLanguageModel, CharacterLanguageModelTrainer
  from stanza.models.common.vocab import CharVocab
  from stanza.models.common import utils
  from stanza.models import _training_logging
label_desc: Use image node_id 11 for calling a global function with example usage: evaluate_and_save(args, vocab, data, trainer, best_loss, model_file, checkpoint_file, writer) and returns: loss,  ppl,  best_loss