docstr: pretrain is a pretrained word embedding.  should have .emb and .vocab
  
  extra_vocab is a collection of words in the training data to
  be used for the delta word embedding, if used.  can be set to
  None if delta word embedding is not used.
  
  labels is the list of labels we expect in the training data.
  Used to derive the number of classes.  Saving it in the model
  will let us check that test data has the same labels
  
  args is either the complete arguments when training, or the
  subset of arguments stored in the model save file
docstr_tok: ["pretrain","is","a","pretrained","word","embedding",".","should","have",".emb","and",".vocab","extra_vocab","is","a","collection","of","words","in","the","training","data","to","be","used","for","the","delta","word","embedding",",","if","used",".","can","be","set","to","None","if","delta","word","embedding","is","not","used",".","labels","is","the","list","of","labels","we","expect","in","the","training","data",".","Used","to","derive","the","number","of","classes",".","Saving","it","in","the","model","will","let","us","check","that","test","data","has","the","same","labels","args","is","either","the","complete","arguments","when","training",",","or","the","subset","of","arguments","stored","in","the","model","save","file"]
code: def __init__(
      self,
      pretrain,
      extra_vocab,
      labels,
      charmodel_forward,
      charmodel_backward,
      elmo_model,
      bert_model,
      bert_tokenizer,
      args,
  ):
      """
      pretrain is a pretrained word embedding.  should have .emb and .vocab
  
      extra_vocab is a collection of words in the training data to
      be used for the delta word embedding, if used.  can be set to
      None if delta word embedding is not used.
  
      labels is the list of labels we expect in the training data.
      Used to derive the number of classes.  Saving it in the model
      will let us check that test data has the same labels
  
      args is either the complete arguments when training, or the
      subset of arguments stored in the model save file
      """
      super(CNNClassifier, self).__init__()
      self.labels = labels
      # we build a separate config out of the args so that we can easily save it in torch
      self.config = SimpleNamespace(
          filter_channels=args.filter_channels,
          filter_sizes=args.filter_sizes,
          fc_shapes=args.fc_shapes,
          dropout=args.dropout,
          num_classes=len(labels),
          wordvec_type=args.wordvec_type,
          extra_wordvec_method=args.extra_wordvec_method,
          extra_wordvec_dim=args.extra_wordvec_dim,
          extra_wordvec_max_norm=args.extra_wordvec_max_norm,
          char_lowercase=args.char_lowercase,
          charlm_projection=args.charlm_projection,
          use_elmo=args.use_elmo,
          elmo_projection=args.elmo_projection,
          bert_model=args.bert_model,
          bilstm=args.bilstm,
          bilstm_hidden_dim=args.bilstm_hidden_dim,
          maxpool_width=args.maxpool_width,
          model_type=ModelType.CNN,
      )
  
      self.char_lowercase = args.char_lowercase
  
      self.unsaved_modules = []
  
      emb_matrix = pretrain.emb
      self.add_unsaved_module(
          "embedding",
          nn.Embedding.from_pretrained(
              torch.from_numpy(emb_matrix), freeze=True
          ),
      )
      self.add_unsaved_module("elmo_model", elmo_model)
      self.vocab_size = emb_matrix.shape[0]
      self.embedding_dim = emb_matrix.shape[1]
  
      self.add_unsaved_module("forward_charlm", charmodel_forward)
      if charmodel_forward is not None:
          tlogger.debug(
              "Got forward char model of dimension {}".format(
                  charmodel_forward.hidden_dim()
              )
          )
          if not charmodel_forward.is_forward_lm:
              raise ValueError(
                  "Got a backward charlm as a forward charlm!"
              )
      self.add_unsaved_module("backward_charlm", charmodel_backward)
      if charmodel_backward is not None:
          tlogger.debug(
              "Got backward char model of dimension {}".format(
                  charmodel_backward.hidden_dim()
              )
          )
          if charmodel_backward.is_forward_lm:
              raise ValueError(
                  "Got a forward charlm as a backward charlm!"
              )
  
      self.add_unsaved_module("bert_model", bert_model)
      self.add_unsaved_module("bert_tokenizer", bert_tokenizer)
  
      # The Pretrain has PAD and UNK already (indices 0 and 1), but we
      # possibly want to train UNK while freezing the rest of the embedding
      # note that the /10.0 operation has to be inside nn.Parameter unless
      # you want to spend a long time debugging this
      self.unk = nn.Parameter(
          torch.randn(self.embedding_dim)
          / np.sqrt(self.embedding_dim)
          / 10.0
      )
  
      # replacing NBSP picks up a whole bunch of words for VI
      self.vocab_map = {
          word.replace("\xa0", " "): i
          for i, word in enumerate(pretrain.vocab)
      }
  
      if self.config.extra_wordvec_method is not ExtraVectors.NONE:
          if not extra_vocab:
              raise ValueError(
                  "Should have had extra_vocab set for extra_wordvec_method {}".format(
                      self.config.extra_wordvec_method
                  )
              )
          if not args.extra_wordvec_dim:
              self.config.extra_wordvec_dim = self.embedding_dim
          if self.config.extra_wordvec_method is ExtraVectors.SUM:
              if self.config.extra_wordvec_dim != self.embedding_dim:
                  raise ValueError(
                      "extra_wordvec_dim must equal embedding_dim for {}".format(
                          self.config.extra_wordvec_method
                      )
                  )
  
          self.extra_vocab = list(extra_vocab)
          self.extra_vocab_map = {
              word: i for i, word in enumerate(self.extra_vocab)
          }
          # TODO: possibly add regularization specifically on the extra embedding?
          # note: it looks like a bug that this doesn't add UNK or PAD, but actually
          # those are expected to already be the first two entries
          self.extra_embedding = nn.Embedding(
              num_embeddings=len(extra_vocab),
              embedding_dim=self.config.extra_wordvec_dim,
              max_norm=self.config.extra_wordvec_max_norm,
              padding_idx=0,
          )
          tlogger.debug(
              "Extra embedding size: {}".format(
                  self.extra_embedding.weight.shape
              )
          )
      else:
          self.extra_vocab = None
          self.extra_vocab_map = None
          self.config.extra_wordvec_dim = 0
          self.extra_embedding = None
  
      # Pytorch is "aware" of the existence of the nn.Modules inside
      # an nn.ModuleList in terms of parameters() etc
      if self.config.extra_wordvec_method is ExtraVectors.NONE:
          total_embedding_dim = self.embedding_dim
      elif self.config.extra_wordvec_method is ExtraVectors.SUM:
          total_embedding_dim = self.embedding_dim
      elif self.config.extra_wordvec_method is ExtraVectors.CONCAT:
          total_embedding_dim = (
              self.embedding_dim + self.config.extra_wordvec_dim
          )
      else:
          raise ValueError(
              "unable to handle {}".format(
                  self.config.extra_wordvec_method
              )
          )
  
      if charmodel_forward is not None:
          if args.charlm_projection:
              self.charmodel_forward_projection = nn.Linear(
                  charmodel_forward.hidden_dim(), args.charlm_projection
              )
              total_embedding_dim += args.charlm_projection
          else:
              self.charmodel_forward_projection = None
              total_embedding_dim += charmodel_forward.hidden_dim()
  
      if charmodel_backward is not None:
          if args.charlm_projection:
              self.charmodel_backward_projection = nn.Linear(
                  charmodel_backward.hidden_dim(),
                  args.charlm_projection,
              )
              total_embedding_dim += args.charlm_projection
          else:
              self.charmodel_backward_projection = None
              total_embedding_dim += charmodel_backward.hidden_dim()
  
      if self.config.use_elmo:
          if elmo_model is None:
              raise ValueError(
                  "Model requires elmo, but elmo_model not passed in"
              )
          elmo_dim = elmo_model.sents2elmo([["Test"]])[0].shape[1]
  
          # this mapping will combine 3 layers of elmo to 1 layer of features
          self.elmo_combine_layers = nn.Linear(
              in_features=3, out_features=1, bias=False
          )
          if self.config.elmo_projection:
              self.elmo_projection = nn.Linear(
                  in_features=elmo_dim,
                  out_features=self.config.elmo_projection,
              )
              total_embedding_dim = (
                  total_embedding_dim + self.config.elmo_projection
              )
          else:
              total_embedding_dim = total_embedding_dim + elmo_dim
  
      if bert_model is not None:
          if bert_tokenizer is None:
              raise ValueError(
                  "Cannot have a bert model without a tokenizer"
              )
          self.bert_dim = self.bert_model.config.hidden_size
          total_embedding_dim += self.bert_dim
  
      if self.config.bilstm:
          conv_input_dim = self.config.bilstm_hidden_dim * 2
          self.bilstm = nn.LSTM(
              batch_first=True,
              input_size=total_embedding_dim,
              hidden_size=self.config.bilstm_hidden_dim,
              num_layers=2,
              bidirectional=True,
              dropout=0.2,
          )
      else:
          conv_input_dim = total_embedding_dim
          self.bilstm = None
  
      self.fc_input_size = 0
      self.conv_layers = nn.ModuleList()
      self.max_window = 0
      for filter_idx, filter_size in enumerate(
          self.config.filter_sizes
      ):
          if isinstance(filter_size, int):
              self.max_window = max(self.max_window, filter_size)
              if isinstance(self.config.filter_channels, int):
                  filter_channels = self.config.filter_channels
              else:
                  filter_channels = self.config.filter_channels[
                      filter_idx
                  ]
              fc_delta = filter_channels // self.config.maxpool_width
              tlogger.debug(
                  "Adding full width filter %d.  Output channels: %d -> %d",
                  filter_size,
                  filter_channels,
                  fc_delta,
              )
              self.fc_input_size += fc_delta
              self.conv_layers.append(
                  nn.Conv2d(
                      in_channels=1,
                      out_channels=filter_channels,
                      kernel_size=(filter_size, conv_input_dim),
                  )
              )
          elif isinstance(filter_size, tuple) and len(filter_size) == 2:
              filter_height, filter_width = filter_size
              self.max_window = max(self.max_window, filter_width)
              if isinstance(self.config.filter_channels, int):
                  filter_channels = max(
                      1,
                      self.config.filter_channels
                      // (conv_input_dim // filter_width),
                  )
              else:
                  filter_channels = self.config.filter_channels[
                      filter_idx
                  ]
              fc_delta = (
                  filter_channels
                  * (conv_input_dim // filter_width)
                  // self.config.maxpool_width
              )
              tlogger.debug(
                  "Adding filter %s.  Output channels: %d -> %d",
                  filter_size,
                  filter_channels,
                  fc_delta,
              )
              self.fc_input_size += fc_delta
              self.conv_layers.append(
                  nn.Conv2d(
                      in_channels=1,
                      out_channels=filter_channels,
                      stride=(1, filter_width),
                      kernel_size=(filter_height, filter_width),
                  )
              )
          else:
              raise ValueError("Expected int or 2d tuple for conv size")
  
      tlogger.debug("Input dim to FC layers: %d", self.fc_input_size)
      self.fc_layers = build_output_layers(
          self.fc_input_size,
          self.config.fc_shapes,
          self.config.num_classes,
      )
  
      self.dropout = nn.Dropout(self.config.dropout)
  
imports: import logging
  import math
  import os
  import random
  import re
  from types import SimpleNamespace
  import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  import stanza.models.classifiers.data
  from stanza.models.classifiers.base_classifier import BaseClassifier
  from stanza.models.classifiers.data import SentimentDatum
  from stanza.models.classifiers.utils import ExtraVectors, ModelType, build_output_layers
  from stanza.models.common.bert_embedding import extract_bert_embeddings
  from stanza.models.common.data import get_long_tensor, sort_all
  from stanza.models.common.foundation_cache import load_bert
  from stanza.models.common.vocab import PAD_ID, UNK_ID
label_desc: Use image node_id 1 to create a new CNNClassifier object from inherited base classes: BaseClassifier with example: obj = CNNClassifier(pretrain, extra_vocab, labels, charmodel_forward, charmodel_backward, elmo_model, bert_model, bert_tokenizer, args)