code: def train(args):
      model_file = model_file_name(args)
  
      save_dir, save_name = os.path.split(model_file)
      utils.ensure_dir(save_dir)
      if args["save_dir"] is None:
          args["save_dir"] = save_dir
      args["save_name"] = save_name
  
      utils.log_training_args(args, logger)
  
      pretrain = None
      vocab = None
      trainer = None
  
      if args["finetune"] and args["finetune_load_name"]:
          logger.warning(
              'Finetune is ON. Using model from "{}"'.format(
                  args["finetune_load_name"]
              )
          )
          _, trainer, vocab = load_model(
              args, args["finetune_load_name"]
          )
      elif args["finetune"] and os.path.exists(model_file):
          logger.warning(
              'Finetune is ON. Using model from "{}"'.format(model_file)
          )
          _, trainer, vocab = load_model(args, model_file)
      else:
          if args["finetune"]:
              raise FileNotFoundError(
                  "Finetune is set to true but model file is not found: {}".format(
                      model_file
                  )
              )
  
          pretrain = load_pretrain(args)
  
          if pretrain is not None:
              word_emb_dim = pretrain.emb.shape[1]
              if (
                  args["word_emb_dim"]
                  and args["word_emb_dim"] != word_emb_dim
              ):
                  logger.warning(
                      "Embedding file has a dimension of {}.  Model will be built with that size instead of {}".format(
                          word_emb_dim, args["word_emb_dim"]
                      )
                  )
              args["word_emb_dim"] = word_emb_dim
  
          if args["charlm"]:
              if args["charlm_shorthand"] is None:
                  raise ValueError(
                      "CharLM Shorthand is required for loading pretrained CharLM model..."
                  )
              logger.info(
                  "Using pretrained contextualized char embedding"
              )
              if not args["charlm_forward_file"]:
                  args[
                      "charlm_forward_file"
                  ] = "{}/{}_forward_charlm.pt".format(
                      args["charlm_save_dir"], args["charlm_shorthand"]
                  )
              if not args["charlm_backward_file"]:
                  args[
                      "charlm_backward_file"
                  ] = "{}/{}_backward_charlm.pt".format(
                      args["charlm_save_dir"], args["charlm_shorthand"]
                  )
  
      # load data
      logger.info(
          "Loading training data with batch size %d from %s",
          args["batch_size"],
          args["train_file"],
      )
      with open(args["train_file"]) as fin:
          train_doc = Document(json.load(fin))
      logger.info(
          "Loaded %d sentences of training data",
          len(train_doc.sentences),
      )
      if len(train_doc.sentences) == 0:
          raise ValueError(
              "File %s exists but has no usable training data"
              % args["train_file"]
          )
      train_batch = DataLoader(
          train_doc,
          args["batch_size"],
          args,
          pretrain,
          vocab=vocab,
          evaluation=False,
          scheme=args.get("train_scheme"),
      )
      vocab = train_batch.vocab
      logger.info("Loading dev data from %s", args["eval_file"])
      with open(args["eval_file"]) as fin:
          dev_doc = Document(json.load(fin))
      logger.info(
          "Loaded %d sentences of dev data", len(dev_doc.sentences)
      )
      if len(dev_doc.sentences) == 0:
          raise ValueError(
              "File %s exists but has no usable dev data"
              % args["train_file"]
          )
      dev_batch = DataLoader(
          dev_doc,
          args["batch_size"],
          args,
          pretrain,
          vocab=vocab,
          evaluation=True,
      )
  
      train_tags = get_known_tags(train_batch.tags)
      logger.info(
          "Training data has %d columns of tags", len(train_tags)
      )
      for tag_idx, tags in enumerate(train_tags):
          logger.info(
              "Tags present in training set at column %d:\n  Tags without BIES markers: %s\n  Tags with B-, I-, E-, or S-: %s",
              tag_idx,
              " ".join(
                  sorted(
                      set(
                          i
                          for i in tags
                          if i[:2] not in ("B-", "I-", "E-", "S-")
                      )
                  )
              ),
              " ".join(
                  sorted(
                      set(
                          i[2:]
                          for i in tags
                          if i[:2] in ("B-", "I-", "E-", "S-")
                      )
                  )
              ),
          )
  
      # skip training if the language does not have training or dev data
      if len(train_batch) == 0 or len(dev_batch) == 0:
          logger.info("Skip training because no data available...")
          return
  
      logger.info("Training tagger...")
      if (
          trainer is None
      ):  # init if model was not loaded previously from file
          trainer = Trainer(
              args=args,
              vocab=vocab,
              pretrain=pretrain,
              device=args["device"],
              train_classifier_only=args["train_classifier_only"],
          )
  
      if args["finetune"]:
          warn_missing_tags(
              trainer.vocab["tag"], train_batch.tags, "training set"
          )
      # the evaluation will coerce the tags to the proper scheme,
      # so we won't need to alert for not having S- or E- tags
      bioes_to_bio = (
          args["train_scheme"] == "bio" and args["scheme"] == "bioes"
      )
      warn_missing_tags(
          trainer.vocab["tag"],
          dev_batch.tags,
          "dev set",
          bioes_to_bio=bioes_to_bio,
      )
  
      # TODO: might still want to add multiple layers of tag evaluation to the scorer
      dev_gold_tags = [
          [x[trainer.args["predict_tagset"]] for x in tags]
          for tags in dev_batch.tags
      ]
  
      logger.info(trainer.model)
  
      global_step = 0
      max_steps = args["max_steps"]
      dev_score_history = []
      best_dev_preds = []
      current_lr = trainer.optimizer.param_groups[0]["lr"]
      global_start_time = time.time()
      format_str = (
          "{}: step {}/{}, loss = {:.6f} ({:.3f} sec/batch), lr: {:.6f}"
      )
  
      # LR scheduling
      if args["lr_decay"] > 0:
          # learning rate changes on plateau -- no improvement on model for patience number of epochs
          # change is made as a factor of the learning rate decay
          scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
              trainer.optimizer,
              mode="max",
              factor=args["lr_decay"],
              patience=args["patience"],
              verbose=True,
              min_lr=args["min_lr"],
          )
      else:
          scheduler = None
  
      if args["wandb"]:
          import wandb
  
          wandb_name = (
              args["wandb_name"]
              if args["wandb_name"]
              else "%s_ner" % args["shorthand"]
          )
          wandb.init(name=wandb_name, config=args)
          wandb.run.define_metric("train_loss", summary="min")
          wandb.run.define_metric("dev_score", summary="max")
  
      # start training
      train_loss = 0
      while True:
          should_stop = False
          for i, batch in enumerate(train_batch):
              start_time = time.time()
              global_step += 1
              loss = trainer.update(batch, eval=False)  # update step
              train_loss += loss
              if global_step % args["log_step"] == 0:
                  duration = time.time() - start_time
                  logger.info(
                      format_str.format(
                          datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                          global_step,
                          max_steps,
                          loss,
                          duration,
                          current_lr,
                      )
                  )
                  if args["log_norms"]:
                      trainer.model.log_norms()
  
              if global_step % args["eval_interval"] == 0:
                  # eval on dev
                  logger.info("Evaluating on dev set...")
                  dev_preds = []
                  for batch in dev_batch:
                      preds = trainer.predict(batch)
                      dev_preds += preds
                  _, _, dev_score, _ = scorer.score_by_entity(
                      dev_preds,
                      dev_gold_tags,
                      ignore_tags=args["ignore_tag_scores"],
                  )
  
                  train_loss = (
                      train_loss / args["eval_interval"]
                  )  # avg loss per batch
                  logger.info(
                      "step {}: train_loss = {:.6f}, dev_score = {:.4f}".format(
                          global_step, train_loss, dev_score
                      )
                  )
                  if args["wandb"]:
                      wandb.log(
                          {
                              "train_loss": train_loss,
                              "dev_score": dev_score,
                          }
                      )
                  train_loss = 0
  
                  # save best model
                  if len(dev_score_history) == 0 or dev_score > max(
                      dev_score_history
                  ):
                      trainer.save(model_file)
                      logger.info("New best model saved.")
                      best_dev_preds = dev_preds
  
                  dev_score_history += [dev_score]
                  logger.info("")
  
                  # lr schedule
                  if scheduler is not None:
                      scheduler.step(dev_score)
  
              # check stopping
              current_lr = trainer.optimizer.param_groups[0]["lr"]
              if (
                  global_step >= args["max_steps"]
                  or current_lr <= args["min_lr"]
              ):
                  should_stop = True
                  break
  
          if should_stop:
              break
  
          train_batch.reshuffle()
  
      logger.info("Training ended with {} steps.".format(global_step))
  
      if args["wandb"]:
          wandb.finish()
  
      if len(dev_score_history) > 0:
          best_f, best_eval = (
              max(dev_score_history) * 100,
              np.argmax(dev_score_history) + 1,
          )
          logger.info(
              "Best dev F1 = {:.2f}, at iteration = {}".format(
                  best_f, best_eval * args["eval_interval"]
              )
          )
      else:
          logger.info("Dev set never evaluated.  Saving final model.")
          trainer.save(model_file)
  
      return trainer
  
imports: import sys
  import os
  import time
  from datetime import datetime
  import argparse
  import logging
  import numpy
  import random
  import re
  import json
  import torch
  from torch import nn, optim
  from stanza.models.ner.data import DataLoader
  from stanza.models.ner.trainer import Trainer
  from stanza.models.ner import scorer
  from stanza.models.common import utils
  from stanza.models.common.pretrain import Pretrain
  from stanza.utils.conll import CoNLL
  from stanza.models.common.doc import *
  from stanza.models import _training_logging
  from stanza.utils.confusion import confusion_to_weighted_f1, format_confusion
label_desc: Use image node_id 8 for calling a global function with example usage: train(args) and returns: trainer