class_docstr: HotFlip generator.
  
  This implemention uses a single backward pass to estimate the gradient of
  each token and uses them to heuristically estimate the impact of perturbing
  the token.
  
  This generator works for both classification and regression models. In the
  case of classification models, the returned counterfactuals are guaranteed to
  have a different prediction class as the original example. In the case of
  regression models, the returned counterfactuals are guaranteed to be on the
  opposite side of a user-provided threshold as the original example.
  
  The returned counterfactuals are guaranteed to be minimal in the sense that
  no strict subset of the applied token perturbations would have resulted in a
  prediction flip.
class_docstr_tok: ["HotFlip","generator",".","This","implemention","uses","a","single","backward","pass","to","estimate","the","gradient","of","each","token","and","uses","them","to","heuristically","estimate","the","impact","of","perturbing","the","token",".","This","generator","works","for","both","classification","and","regression","models",".","In","the","case","of","classification","models",",","the","returned","counterfactuals","are","guaranteed","to","have","a","different","prediction","class","as","the","original","example",".","In","the","case","of","regression","models",",","the","returned","counterfactuals","are","guaranteed","to","be","on","the","opposite","side","of","a","user-provided","threshold","as","the","original","example",".","The","returned","counterfactuals","are","guaranteed","to","be","minimal","in","the","sense","that","no","strict","subset","of","the","applied","token","perturbations","would","have","resulted","in","a","prediction","flip","."]
docstr: Identify minimal sets of token flips that alter the prediction.
docstr_tok: ["Identify","minimal","sets","of","token","flips","that","alter","the","prediction","."]
code: def generate(
      self,
      example: JsonDict,
      model: lit_model.Model,
      dataset: lit_dataset.Dataset,
      config: Optional[JsonDict] = None,
  ) -> list[JsonDict]:
      """Identify minimal sets of token flips that alter the prediction."""
      del dataset  # Unused.
  
      config = config or {}
      num_examples = int(
          config.get(NUM_EXAMPLES_KEY, NUM_EXAMPLES_DEFAULT)
      )
      max_flips = int(config.get(MAX_FLIPS_KEY, MAX_FLIPS_DEFAULT))
      tokens_to_ignore = config.get(
          TOKENS_TO_IGNORE_KEY, TOKENS_TO_IGNORE_DEFAULT
      )
      pred_key = config.get(PREDICTION_KEY, "")
      regression_thresh = float(
          config.get(REGRESSION_THRESH_KEY, REGRESSION_THRESH_DEFAULT)
      )
      assert (
          model is not None
      ), "Please provide a model for this generator."
  
      input_spec = model.input_spec()
      output_spec = model.output_spec()
      assert pred_key, "Please provide the prediction key"
      assert pred_key in output_spec, "Invalid prediction key"
  
      is_regression = False
      if isinstance(output_spec[pred_key], types.RegressionScore):
          is_regression = True
      else:
          assert isinstance(
              output_spec[pred_key], types.MulticlassPreds
          ), "Only classification or regression models are supported"
      logging.info(r"W3lc0m3 t0 H0tFl1p \o/")
      logging.info("Original example: %r", example)
  
      # Get model outputs.
      orig_output = list(model.predict([example]))[0]
  
      # Check config for selected fields.
      selected_fields = list(config.get(FIELDS_TO_HOTFLIP_KEY, []))
      if not selected_fields:
          return []
  
      # Get tokens (corresponding to each text input field) and corresponding
      # gradients.
      tokens_and_gradients = self._get_tokens_and_gradients(
          input_spec, output_spec, orig_output, selected_fields
      )
      assert (
          tokens_and_gradients
      ), "No token fields found. Cannot use HotFlip. :-("
  
      # Copy tokens into input example.
      example = dict(example)
      for token_field, v in tokens_and_gradients.items():
          tokens, _ = v
          example[token_field] = tokens
  
      inv_vocab, embedding_matrix = model.get_embedding_table()
      assert (
          len(inv_vocab) == embedding_matrix.shape[0]
      ), "Vocab/embeddings size mismatch."
  
      successful_cfs = []
      # TODO(lit-team): use only 1 sequence as input (configurable in UI).
      # TODO(lit-team): Refactor the following code so that it's not so deeply
      # nested (and easier to track loop state).
      for token_field, v in tokens_and_gradients.items():
          tokens, grads = v
          text_field = input_spec[
              token_field
          ].parent  # pytype: disable=attribute-error
          logging.info(
              "Identifying Hotflips for input field: %s",
              str(text_field),
          )
          direction = -1
          if is_regression:
              # We want the replacements to increase the prediction score if the
              # original score is below the threshold, and decrease otherwise.
              direction = (
                  1
                  if orig_output[pred_key] <= regression_thresh
                  else -1
              )
          replacement_tokens = self._get_replacement_tokens(
              embedding_matrix, inv_vocab, grads, direction
          )
  
          successful_positions = []
          for token_idxs in self._gen_token_idxs_to_flip(
              tokens, grads, max_flips, tokens_to_ignore
          ):
              if len(successful_cfs) >= num_examples:
                  return successful_cfs
              # If a subset of the set of tokens have already been successful in
              # obtaining a flip, we continue. This ensures that we only consider
              # sets of token flips that are minimal.
              if self._subset_exists(
                  set(token_idxs), successful_positions
              ):
                  continue
  
              # Create counterfactual.
              cf = self._create_cf(
                  example,
                  token_field,
                  text_field,
                  tokens,
                  token_idxs,
                  replacement_tokens,
              )
              # Obtain model prediction.
              cf_output = list(model.predict([cf]))[0]
  
              if cf_utils.is_prediction_flip(
                  cf_output,
                  orig_output,
                  output_spec,
                  pred_key,
                  regression_thresh,
              ):
                  # Prediciton flip found!
                  cf_utils.update_prediction(
                      cf, cf_output, output_spec, pred_key
                  )
                  successful_cfs.append(cf)
                  successful_positions.append(set(token_idxs))
      return successful_cfs
  
imports: from collections.abc import Iterator, Mapping
  import itertools
  from typing import Any, cast, Optional
  from absl import logging
  from lit_nlp.api import components
  from lit_nlp.api import dataset
  from lit_nlp.api import model
  from lit_nlp.api import types
  from lit_nlp.components import cf_utils
  from lit_nlp.lib import utils
  import numpy
label_desc: Use image node_id 11 for calling the HotFlip obj's underlying member method code with example usage: obj.generate(example, model, dataset, config) and returns: successful_cfs, list, successful_cfs