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 _make_embedder_input(
      self, all_tokens: List[str]
  ) -> Dict[str, torch.Tensor]:
      inputs = {}
      # A bit of a hack; this will only work with some dataset readers, but it'll do for now.
      indexers = self.predictor._dataset_reader._token_indexers  # type: ignore
      for indexer_name, token_indexer in indexers.items():
          if isinstance(token_indexer, SingleIdTokenIndexer):
              all_indices = [
                  self.vocab._token_to_index[self.namespace][token]
                  for token in all_tokens
              ]
              inputs[indexer_name] = {
                  "tokens": torch.LongTensor(all_indices).unsqueeze(0)
              }
          elif isinstance(token_indexer, TokenCharactersIndexer):
              tokens = [Token(x) for x in all_tokens]
              max_token_length = max(len(x) for x in all_tokens)
              # sometime max_token_length is too short for cnn encoder
              max_token_length = max(
                  max_token_length, token_indexer._min_padding_length
              )
              indexed_tokens = token_indexer.tokens_to_indices(
                  tokens, self.vocab
              )
              padding_lengths = token_indexer.get_padding_lengths(
                  indexed_tokens
              )
              padded_tokens = token_indexer.as_padded_tensor_dict(
                  indexed_tokens, padding_lengths
              )
              inputs[indexer_name] = {
                  "token_characters": torch.LongTensor(
                      padded_tokens["token_characters"]
                  ).unsqueeze(0)
              }
          elif isinstance(token_indexer, ELMoTokenCharactersIndexer):
              elmo_tokens = []
              for token in all_tokens:
                  elmo_indexed_token = token_indexer.tokens_to_indices(
                      [Token(text=token)], self.vocab
                  )["elmo_tokens"]
                  elmo_tokens.append(elmo_indexed_token[0])
              inputs[indexer_name] = {
                  "elmo_tokens": torch.LongTensor(
                      elmo_tokens
                  ).unsqueeze(0)
              }
          else:
              raise RuntimeError(
                  "Unsupported token indexer:", token_indexer
              )
  
      return util.move_to_device(inputs, self.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 4 for calling the Hotflip obj's underlying member method code with example usage: obj._make_embedder_input(all_tokens) and returns: util