code: def eval_tune_loss(args, trainer, task, subset, extra_state):
      """Evaluate the model on the validation set and return the average loss."""
      # Initialize dataloader
      itr = task.get_batch_iterator(
          dataset=task.dataset(subset),
          max_tokens=args.max_tokens,
          max_sentences=args.batch_size_valid,
          max_positions=utils.resolve_max_positions(
              task.max_positions(), trainer.get_model().max_positions()
          ),
          ignore_invalid_inputs=args.skip_invalid_size_inputs_valid_test,
          required_batch_size_multiple=8,
          seed=args.seed,
          num_shards=args.distributed_world_size,
          shard_id=args.distributed_rank,
          num_workers=args.num_workers,
      ).next_epoch_itr(shuffle=False)
      progress = progress_bar.build_progress_bar(
          args=args,
          iterator=itr,
          epoch=extra_state["epoch"],
          prefix=f"valid on '{subset}' subset",
          no_progress_bar="simple",
      )
  
      # reset validation loss meters
      for k in ["valid_loss", "valid_nll_loss"]:
          meter = trainer.get_meter(k)
          if meter is not None:
              meter.reset()
  
      extra_meters = defaultdict(lambda: AverageMeter())
      for sample in progress:
          log_output = trainer.valid_step(sample)
  
          # log mid-validation stats
          stats = get_valid_stats(trainer)
          for k, v in log_output.items():
              if k in [
                  "loss",
                  "nll_loss",
                  "ntokens",
                  "nsentences",
                  "sample_size",
              ]:
                  continue
              if "loss" in k:
                  extra_meters[k].update(v, log_output["sample_size"])
              else:
                  extra_meters[k].update(v)
              stats[k] = extra_meters[k].avg
          progress.log(stats)
  
      # log validation stats
      stats = get_valid_stats(trainer)
      for k, meter in extra_meters.items():
          stats[k] = meter.avg
      progress.print(stats)
  
      extra_state["tune_eval"]["loss"] = stats["valid_loss"]
      extra_state["tune_eval"]["perplexity"] = stats["valid_ppl"]
  
      if (
          extra_state["tune_eval"]["lowest_loss"] is None
          or extra_state["tune_eval"]["loss"]
          < extra_state["tune_eval"]["lowest_loss"]
      ):
          extra_state["tune_eval"]["lowest_loss"] = extra_state[
              "tune_eval"
          ]["loss"]
          extra_state["tune_eval"]["num_since_best"] = 0
      else:
          extra_state["tune_eval"]["num_since_best"] += 1
  
      stop_due_to_tune_loss = False
      if (
          args.stop_no_best_validate_loss >= 0
          and extra_state["tune_eval"]["num_since_best"]
          > args.stop_no_best_validate_loss
      ):
          stop_due_to_tune_loss = True
          print(
              f"Stopping training due to eval tune loss stagnation - last best "
              f"eval tune loss of {extra_state['tune_eval']['lowest_loss']} "
              f"(current loss: {extra_state['tune_eval']['loss']}) "
              f"was {extra_state['tune_eval']['num_since_best']} validations ago."
          )
      return extra_state, stop_due_to_tune_loss
  
file_path: translate/pytorch_translate/evals.py
imports: import math
  import time
  from collections import defaultdict, OrderedDict
  from typing import Any, Dict, List, Optional, Tuple
  from fairseq import distributed_utils, progress_bar, utils
  from fairseq.meters import AverageMeter
  from pytorch_translate import checkpoint, generate, utils
  from pytorch_translate.dual_learning.dual_learning_task import DualLearningTask
  from pytorch_translate.tasks.pytorch_translate_multi_task import PyTorchTranslateMultiTask
label_desc: Use image node_id 6 for calling a global function with example usage: eval_tune_loss(args, trainer, task, subset, extra_state) and returns: extra_state,  stop_due_to_tune_loss