code: def build_trainer(
      args,
      train_trees,
      dev_trees,
      silver_trees,
      foundation_cache,
      model_load_file,
  ):
      """
      Builds a Trainer (with model) and the train_sequences and transitions for the given trees.
      """
      train_constituents = (
          parse_tree.Tree.get_unique_constituent_labels(train_trees)
      )
      logger.info(
          "Unique constituents in training set: %s", train_constituents
      )
      check_constituents(train_constituents, dev_trees, "dev")
      check_constituents(train_constituents, silver_trees, "silver")
      constituent_counts = parse_tree.Tree.get_constituent_counts(
          train_trees
      )
      logger.info("Constituent node counts: %s", constituent_counts)
  
      tags = parse_tree.Tree.get_unique_tags(train_trees)
      if None in tags:
          raise RuntimeError(
              "Fatal problem: the tagger put None on some of the nodes!"
          )
      logger.info("Unique tags in training set: %s", tags)
      # no need to fail for missing tags between train/dev set
      # the model has an unknown tag embedding
      for tag in parse_tree.Tree.get_unique_tags(dev_trees):
          if tag not in tags:
              logger.info(
                  "Found tag in dev set which does not exist in train set: %s  Continuing...",
                  tag,
              )
  
      unary_limit = (
          max(
              max(t.count_unary_depth() for t in train_trees),
              max(t.count_unary_depth() for t in dev_trees),
          )
          + 1
      )
      if silver_trees:
          unary_limit = max(
              unary_limit,
              max(t.count_unary_depth() for t in silver_trees),
          )
      logger.info("Unary limit: %d", unary_limit)
      (
          train_sequences,
          train_transitions,
      ) = transition_sequence.convert_trees_to_sequences(
          train_trees,
          "training",
          args["transition_scheme"],
          args["reversed"],
      )
      (
          dev_sequences,
          dev_transitions,
      ) = transition_sequence.convert_trees_to_sequences(
          dev_trees, "dev", args["transition_scheme"], args["reversed"]
      )
      (
          silver_sequences,
          silver_transitions,
      ) = transition_sequence.convert_trees_to_sequences(
          silver_trees,
          "silver",
          args["transition_scheme"],
          args["reversed"],
      )
  
      logger.info(
          "Total unique transitions in train set: %d",
          len(train_transitions),
      )
      logger.info(
          "Unique transitions in training set: %s", train_transitions
      )
      expanded_train_transitions = set(
          train_transitions
          + [
              x
              for trans in train_transitions
              for x in trans.components()
          ]
      )
      parse_transitions.check_transitions(
          expanded_train_transitions, dev_transitions, "dev"
      )
      # theoretically could just train based on the items in the silver dataset
      parse_transitions.check_transitions(
          expanded_train_transitions, silver_transitions, "silver"
      )
  
      verify_transitions(
          train_trees,
          train_sequences,
          args["transition_scheme"],
          unary_limit,
          args["reversed"],
          "train",
      )
      verify_transitions(
          dev_trees,
          dev_sequences,
          args["transition_scheme"],
          unary_limit,
          args["reversed"],
          "dev",
      )
  
      root_labels = parse_tree.Tree.get_root_labels(train_trees)
      check_root_labels(root_labels, dev_trees, "dev")
      check_root_labels(root_labels, silver_trees, "silver")
  
      # we don't check against the words in the dev set as it is
      # expected there will be some UNK words
      words = parse_tree.Tree.get_unique_words(train_trees)
      rare_words = parse_tree.Tree.get_rare_words(
          train_trees, args["rare_word_threshold"]
      )
      # rare/unknown silver words will just get UNK if they are not already known
      if silver_trees and args["use_silver_words"]:
          logger.info(
              "Getting silver words to add to the delta embedding"
          )
          silver_words = parse_tree.Tree.get_common_words(
              tqdm(silver_trees, postfix="Silver words"), len(words)
          )
          words = sorted(set(words + silver_words))
  
      # also, it's not actually an error if there is a pattern of
      # compound unary or compound open nodes which doesn't exist in the
      # train set.  it just means we probably won't ever get that right
      open_nodes = get_open_nodes(train_trees, args)
      logger.info(
          "Using the following open nodes:\n  %s",
          "\n  ".join(map(str, open_nodes)),
      )
  
      # at this point we have:
      # pretrain
      # train_trees, dev_trees
      # lists of transitions, internal nodes, and root states the parser needs to be aware of
  
      # in the 'finetune' case, this will preload the models into foundation_cache
      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"]
      )
  
      trainer = None
      if (
          args["checkpoint"]
          and args["checkpoint_save_name"]
          and os.path.exists(args["checkpoint_save_name"])
      ):
          logger.info(
              "Found checkpoint to continue training: %s",
              args["checkpoint_save_name"],
          )
          trainer = Trainer.load(
              args["checkpoint_save_name"],
              args,
              load_optimizer=True,
              foundation_cache=foundation_cache,
          )
          # grad clipping is not saved with the rest of the model
          add_grad_clipping(trainer, args["grad_clipping"])
  
          # TODO: turn finetune, relearn_structure, multistage into an enum?
          # finetune just means continue learning, so checkpoint is sufficient
          # relearn_structure is essentially a one stage multistage
          # multistage with a checkpoint will have the proper optimizer for that epoch
          # and no special learning mode means we are training a new model and should continue
          return (
              trainer,
              train_sequences,
              silver_sequences,
              train_transitions,
          )
  
      if args["finetune"]:
          logger.info("Loading model to finetune: %s", model_load_file)
          trainer = Trainer.load(
              model_load_file,
              args,
              load_optimizer=True,
              foundation_cache=foundation_cache,
          )
          # a new finetuning will start with a new epochs_trained count
          trainer.epochs_trained = 0
      elif args["relearn_structure"]:
          logger.info(
              "Loading model to continue training with new structure from %s",
              model_load_file,
          )
          temp_args = dict(args)
          # remove the pattn & lattn layers unless the saved model had them
          temp_args.pop("pattn_num_layers", None)
          temp_args.pop("lattn_d_proj", None)
          trainer = Trainer.load(
              model_load_file,
              temp_args,
              load_optimizer=False,
              foundation_cache=foundation_cache,
          )
  
          # using the model's current values works for if the new
          # dataset is the same or smaller
          # TODO: handle a larger dataset as well
          model = LSTMModel(
              pt,
              forward_charlm,
              backward_charlm,
              trainer.model.bert_model,
              trainer.model.bert_tokenizer,
              trainer.model.force_bert_saved,
              trainer.model.transitions,
              trainer.model.constituents,
              trainer.model.tags,
              trainer.model.delta_words,
              trainer.model.rare_words,
              trainer.model.root_labels,
              trainer.model.constituent_opens,
              trainer.model.unary_limit(),
              args,
          )
          model = model.to(args["device"])
          model.copy_with_new_structure(trainer.model)
          optimizer = build_optimizer(args, model, False)
          scheduler = build_scheduler(args, optimizer)
          trainer = Trainer(model, optimizer, scheduler)
      elif args["multistage"]:
          # run adadelta over the model for half the time with no pattn or lattn
          # training then switches to a different optimizer for the rest
          # this works surprisingly well
          logger.info(
              "Warming up model for %d iterations using AdaDelta to train the embeddings",
              args["epochs"] // 2,
          )
          temp_args = dict(args)
          # remove the attention layers for the temporary model
          temp_args["pattn_num_layers"] = 0
          temp_args["lattn_d_proj"] = 0
  
          if args["bert_finetune"] or args["stage1_bert_finetune"]:
              bert_model, bert_tokenizer = load_bert(args["bert_model"])
          else:
              bert_model, bert_tokenizer = load_bert(
                  args["bert_model"], foundation_cache
              )
          temp_model = LSTMModel(
              pt,
              forward_charlm,
              backward_charlm,
              bert_model,
              bert_tokenizer,
              False,
              train_transitions,
              train_constituents,
              tags,
              words,
              rare_words,
              root_labels,
              open_nodes,
              unary_limit,
              temp_args,
          )
          temp_model = temp_model.to(args["device"])
          temp_optim = build_optimizer(temp_args, temp_model, True)
          scheduler = build_scheduler(temp_args, temp_optim, True)
          trainer = Trainer(temp_model, temp_optim, scheduler)
      else:  # TODO: combine with the multistage version?  could make this a single stage
          if args["bert_finetune"]:
              bert_model, bert_tokenizer = load_bert(args["bert_model"])
          else:
              bert_model, bert_tokenizer = load_bert(
                  args["bert_model"], foundation_cache
              )
          model = LSTMModel(
              pt,
              forward_charlm,
              backward_charlm,
              bert_model,
              bert_tokenizer,
              False,
              train_transitions,
              train_constituents,
              tags,
              words,
              rare_words,
              root_labels,
              open_nodes,
              unary_limit,
              args,
          )
          model = model.to(args["device"])
  
          optimizer = build_optimizer(args, model, False)
          scheduler = build_scheduler(args, optimizer)
  
          trainer = Trainer(model, optimizer, scheduler)
  
      logger.info(
          "Number of words in the training set found in the embedding: %d out of %d",
          trainer.model.num_words_known(words),
          len(words),
      )
      add_grad_clipping(trainer, args["grad_clipping"])
  
      return (
          trainer,
          train_sequences,
          silver_sequences,
          train_transitions,
      )
  
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 12 for calling a global function with example usage: build_trainer(args, train_trees, dev_trees, silver_trees, foundation_cache, model_load_file) and returns: trainer,  train_sequences,  silver_sequences,  train_transitions, trainer,  train_sequences,  silver_sequences,  train_transitions