code: def iterate_training(
      args,
      trainer,
      train_trees,
      train_sequences,
      transitions,
      dev_trees,
      silver_trees,
      silver_sequences,
      foundation_cache,
      model_save_each_filename,
      evaluator,
  ):
      """
      Given an initialized model, a processed dataset, and a secondary dev dataset, train the model
  
      The training is iterated in the following loop:
        extract a batch of trees of the same length from the training set
        convert those trees into initial parsing states
        repeat until trees are done:
          batch predict the model's interpretation of the current states
          add the errors to the list of things to backprop
          advance the parsing state for each of the trees
      """
      model = trainer.model
  
      # Somewhat unusual, but possibly related to the extreme variability in length of trees
      # Various experiments generally show about 0.5 F1 loss on various
      # datasets when using 'mean' instead of 'sum' for reduction
      # (Remember to adjust the weight decay when rerunning that experiment)
      if args["loss"] == "cross":
          logger.info("Building CrossEntropyLoss(sum)")
          process_outputs = lambda x: x
          model_loss_function = nn.CrossEntropyLoss(reduction="sum")
      elif args["loss"] == "focal":
          try:
              from focal_loss.focal_loss import FocalLoss
          except ImportError:
              raise ImportError(
                  "focal_loss not installed.  Must `pip install focal_loss_torch` to use the --loss=focal feature"
              )
          logger.info(
              "Building FocalLoss, gamma=%f", args["loss_focal_gamma"]
          )
          process_outputs = lambda x: torch.softmax(x, dim=1)
          model_loss_function = FocalLoss(
              reduction="sum", gamma=args["loss_focal_gamma"]
          )
      elif args["loss"] == "large_margin":
          logger.info("Building LargeMarginInSoftmaxLoss(sum)")
          process_outputs = lambda x: x
          model_loss_function = LargeMarginInSoftmaxLoss(
              reduction="sum"
          )
      else:
          raise ValueError("Unexpected loss term: %s" % args["loss"])
  
      device = next(model.parameters()).device
      model_loss_function.to(device)
      transition_tensors = {
          x: torch.tensor(
              y, requires_grad=False, device=device
          ).unsqueeze(0)
          for (y, x) in enumerate(model.transitions)
      }
      model.train()
  
      train_data = compose_train_data(train_trees, train_sequences)
      silver_data = compose_train_data(silver_trees, silver_sequences)
  
      if not args["epoch_size"]:
          args["epoch_size"] = len(train_data)
      if silver_data and not args["silver_epoch_size"]:
          args["silver_epoch_size"] = args["epoch_size"]
  
      if args["multistage"]:
          multistage_splits = {}
          # if we're halfway, only do pattn.  save lattn for next time
          multistage_splits[args["epochs"] // 2] = (
              args["pattn_num_layers"],
              False,
          )
          if LSTMModel.uses_lattn(args):
              multistage_splits[args["epochs"] * 3 // 4] = (
                  args["pattn_num_layers"],
                  True,
              )
  
      oracle = None
      if args["transition_scheme"] is TransitionScheme.IN_ORDER:
          oracle = InOrderOracle(
              model.root_labels, args["oracle_level"]
          )
  
      leftover_training_data = []
      leftover_silver_data = []
      if trainer.best_epoch > 0:
          logger.info(
              "Restarting trainer with a model trained for %d epochs.  Best epoch %d, f1 %f",
              trainer.epochs_trained,
              trainer.best_epoch,
              trainer.best_f1,
          )
  
      # if we're training a new model, save the initial state so it can be inspected
      if model_save_each_filename and trainer.epochs_trained == 0:
          trainer.save(
              model_save_each_filename % trainer.epochs_trained,
              save_optimizer=True,
          )
  
      # trainer.epochs_trained+1 so that if the trainer gets saved after 1 epoch, the epochs_trained is 1
      for trainer.epochs_trained in range(
          trainer.epochs_trained + 1, args["epochs"] + 1
      ):
          model.train()
          logger.info("Starting epoch %d", trainer.epochs_trained)
          update_bert_learning_rate(
              args, trainer.optimizer, trainer.epochs_trained
          )
  
          if args["log_norms"]:
              model.log_norms()
          leftover_training_data, epoch_data = next_epoch_data(
              leftover_training_data, train_data, args["epoch_size"]
          )
          leftover_silver_data, epoch_silver_data = next_epoch_data(
              leftover_silver_data,
              silver_data,
              args["silver_epoch_size"],
          )
          epoch_data = epoch_data + epoch_silver_data
          epoch_data.sort(key=lambda x: len(x[1]))
  
          epoch_stats = train_model_one_epoch(
              trainer.epochs_trained,
              trainer,
              transition_tensors,
              process_outputs,
              model_loss_function,
              epoch_data,
              oracle,
              args,
          )
  
          # print statistics
          # by now we've forgotten about the original tags on the trees,
          # but it doesn't matter for hill climbing
          f1, _ = run_dev_set(
              model, dev_trees, dev_trees, args, evaluator
          )
          if f1 > trainer.best_f1 or (
              trainer.best_epoch == 0 and trainer.best_f1 == 0.0
          ):
              # best_epoch == 0 to force a save of an initial model
              # useful for tests which expect something, even when a
              # very simple model didn't learn anything
              logger.info(
                  "New best dev score: %.5f > %.5f", f1, trainer.best_f1
              )
              trainer.best_f1 = f1
              trainer.best_epoch = trainer.epochs_trained
              trainer.save(args["save_name"], save_optimizer=False)
          if epoch_stats.nans > 0:
              logger.warning(
                  "Had to ignore %d batches with NaN", epoch_stats.nans
              )
          logger.info(
              "Epoch %d finished\n  Transitions correct: %s\n  Transitions incorrect: %s\n  Total loss for epoch: %.5f\n  Dev score      (%5d): %8f\n  Best dev score (%5d): %8f",
              trainer.epochs_trained,
              epoch_stats.transitions_correct,
              epoch_stats.transitions_incorrect,
              epoch_stats.epoch_loss,
              trainer.epochs_trained,
              f1,
              trainer.best_epoch,
              trainer.best_f1,
          )
  
          old_lr = trainer.optimizer.param_groups[0]["lr"]
          trainer.scheduler.step(f1)
          new_lr = trainer.optimizer.param_groups[0]["lr"]
          if old_lr != new_lr:
              logger.info(
                  "Updating learning rate from %f to %f", old_lr, new_lr
              )
  
          if args["wandb"]:
              wandb.log(
                  {
                      "epoch_loss": epoch_stats.epoch_loss,
                      "dev_score": f1,
                  },
                  step=trainer.epochs_trained,
              )
              if args["wandb_norm_regex"]:
                  watch_regex = re.compile(args["wandb_norm_regex"])
                  for n, p in model.named_parameters():
                      if watch_regex.search(n):
                          wandb.log({n: torch.linalg.norm(p)})
  
          # recreate the optimizer and alter the model as needed if we hit a new multistage split
          if (
              args["multistage"]
              and trainer.epochs_trained in multistage_splits
          ):
              # we may be loading a save model from an earlier epoch if the scores stopped increasing
              epochs_trained = trainer.epochs_trained
              batches_trained = trainer.batches_trained
  
              stage_pattn_layers, stage_uses_lattn = multistage_splits[
                  epochs_trained
              ]
  
              # when loading the model, let the saved model determine whether it has pattn or lattn
              temp_args = copy.deepcopy(model.args)
              temp_args.pop("pattn_num_layers", None)
              temp_args.pop("lattn_d_proj", None)
              # overwriting the old trainer & model will hopefully free memory
              trainer = Trainer.load(
                  args["save_name"],
                  temp_args,
                  load_optimizer=False,
                  foundation_cache=foundation_cache,
              )
              model = trainer.model
              logger.info(
                  "Finished stage at epoch %d.  Restarting optimizer",
                  epochs_trained,
              )
              logger.info(
                  "Previous best model was at epoch %d",
                  trainer.epochs_trained,
              )
  
              temp_args = dict(args)
              logger.info(
                  "Switching to a model with %d pattn layers and %slattn",
                  stage_pattn_layers,
                  "" if stage_uses_lattn else "NO ",
              )
              temp_args["pattn_num_layers"] = stage_pattn_layers
              if not stage_uses_lattn:
                  temp_args["lattn_d_proj"] = 0
              pt = foundation_cache.load_pretrain(
                  args["wordvec_pretrain_file"]
              )
              forward_charlm = foundation_cache.load_charlm(
                  args["charlm_forward_file"]
              )
              backward_charlm = foundation_cache.load_charlm(
                  args["charlm_backward_file"]
              )
              bert_model, bert_tokenizer = foundation_cache.load_bert(
                  args["bert_model"]
              )
              new_model = LSTMModel(
                  pt,
                  forward_charlm,
                  backward_charlm,
                  bert_model,
                  bert_tokenizer,
                  model.force_bert_saved,
                  model.transitions,
                  model.constituents,
                  model.tags,
                  model.delta_words,
                  model.rare_words,
                  model.root_labels,
                  model.constituent_opens,
                  model.unary_limit(),
                  temp_args,
              )
              new_model.to(device)
              new_model.copy_with_new_structure(model)
  
              optimizer = build_optimizer(temp_args, new_model, False)
              scheduler = build_scheduler(temp_args, optimizer)
              trainer = Trainer(
                  new_model,
                  optimizer,
                  scheduler,
                  epochs_trained,
                  batches_trained,
                  trainer.best_f1,
                  trainer.best_epoch,
              )
              add_grad_clipping(trainer, args["grad_clipping"])
              model = new_model
  
          # checkpoint needs to be saved AFTER rebuilding the optimizer
          # so that assumptions about the optimizer in the checkpoint
          # can be made based on the end of the epoch
          if args["checkpoint"] and args["checkpoint_save_name"]:
              trainer.save(
                  args["checkpoint_save_name"], save_optimizer=True
              )
          # same with the "each filename", actually, in case those are
          # brought back for more training or even just for testing
          if model_save_each_filename:
              trainer.save(
                  model_save_each_filename % trainer.epochs_trained,
                  save_optimizer=True,
              )
  
      return trainer
  
imports: from collections import Counter
  from collections import namedtuple
  import copy
  from enum import Enum
  import logging
  from operator import itemgetter
  import os
  import random
  import re
  import sys
  import torch
  from torch import nn
  from stanza.models.common import pretrain
  from stanza.models.common import utils
  from stanza.models.common.foundation_cache import load_bert, load_charlm, load_pretrain, FoundationCache
  from stanza.models.common.large_margin_loss import LargeMarginInSoftmaxLoss
  from stanza.models.constituency import parse_transitions
  from stanza.models.constituency import parse_tree
  from stanza.models.constituency import transition_sequence
  from stanza.models.constituency import tree_reader
  from stanza.models.constituency.base_model import SimpleModel, UNARY_LIMIT
  from stanza.models.constituency.in_order_oracle import InOrderOracle
  from stanza.models.constituency.lstm_model import LSTMModel, StackHistory
  from stanza.models.constituency.parse_transitions import TransitionScheme
  from stanza.models.constituency.parse_tree import Tree
  from stanza.models.constituency.utils import retag_tags, retag_trees, build_optimizer, build_scheduler
  from stanza.models.constituency.utils import DEFAULT_LEARNING_EPS, DEFAULT_LEARNING_RATES, DEFAULT_LEARNING_RHO, DEFAULT_WEIGHT_DECAY
  from stanza.server.parser_eval import EvaluateParser, ParseResult
  from stanza.utils.get_tqdm import get_tqdm
  from stanza.utils.training.common import find_wordvec_pretrain, choose_charlm, find_charlm_file
  from stanza.resources.default_packages import default_charlms, default_pretrains
label_desc: Use image node_id 19 for calling a global function with example usage: iterate_training(args, trainer, train_trees, train_sequences, transitions, dev_trees, silver_trees, silver_sequences, foundation_cache, model_save_each_filename, evaluator) and returns: trainer