class_docstr: Runs the HotFlip style attack at the word-level https://arxiv.org/abs/1712.06751.  We use the
  first-order taylor approximation described in https://arxiv.org/abs/1903.06620, in the function
  `_first_order_taylor()`.
  
  We try to re-use the embedding matrix from the model when deciding what other words to flip a
  token to.  For a large class of models, this is straightforward.  When there is a
  character-level encoder, however (e.g., with ELMo, any char-CNN, etc.), or a combination of
  encoders (e.g., ELMo + glove), we need to construct a fake embedding matrix that we can use in
  `_first_order_taylor()`.  We do this by getting a list of words from the model's vocabulary
  and embedding them using the encoder.  This can be expensive, both in terms of time and memory
  usage, so we take a `max_tokens` parameter to limit the size of this fake embedding matrix.
  This also requires a model to `have` a token vocabulary in the first place, which can be
  problematic for models that only have character vocabularies.
  
  Registered as an `Attacker` with name "hotflip".
  
  # Parameters
  
  predictor : `Predictor`
      The model (inside a Predictor) that we're attacking.  We use this to get gradients and
      predictions.
  vocab_namespace : `str`, optional (default=`'tokens'`)
      We use this to know three things: (1) which tokens we should ignore when producing flips
      (we don't consider non-alphanumeric tokens); (2) what the string value is of the token that
      we produced, so we can show something human-readable to the user; and (3) if we need to
      construct a fake embedding matrix, we use the tokens in the vocabulary as flip candidates.
  max_tokens : `int`, optional (default=`5000`)
      This is only used when we need to construct a fake embedding matrix.  That matrix can take
      a lot of memory when the vocab size is large.  This parameter puts a cap on the number of
      tokens to use, so the fake embedding matrix doesn't take as much memory.
code: def __init__(
      self,
      predictor: Predictor,
      vocab_namespace: str = "tokens",
      max_tokens: int = 5000,
  ) -> None:
      super().__init__(predictor)
      self.vocab = self.predictor._model.vocab
      self.namespace = vocab_namespace
      # Force new tokens to be alphanumeric
      self.max_tokens = max_tokens
      self.invalid_replacement_indices: List[int] = []
      for i in self.vocab._index_to_token[self.namespace]:
          if not self.vocab._index_to_token[self.namespace][
              i
          ].isalnum():
              self.invalid_replacement_indices.append(i)
      self.embedding_matrix: torch.Tensor = None
      self.embedding_layer: torch.nn.Module = None
      # get device number
      self.cuda_device = predictor.cuda_device
  
imports: from copy import deepcopy
  from typing import Dict, List, Tuple
  import numpy
  import torch
  from allennlp.common.util import JsonDict, sanitize
  from allennlp.data import Instance, Token
  from allennlp.data.fields import TextField
  from allennlp.data.token_indexers import ELMoTokenCharactersIndexer, TokenCharactersIndexer, SingleIdTokenIndexer
  from allennlp.interpret.attackers import utils
  from allennlp.interpret.attackers.attacker import Attacker
  from allennlp.modules.token_embedders import Embedding
  from allennlp.nn import util
  from allennlp.predictors.predictor import Predictor
label_desc: Use image node_id 1 to create a new Hotflip object from inherited base classes: Attacker with example: obj = Hotflip(predictor, vocab_namespace, max_tokens)