class_docstr: Runs the input reduction method from [Pathologies of Neural Models Make Interpretations
  Difficult](https://arxiv.org/abs/1804.07781), which removes as many words as possible from
  the input without changing the model's prediction.
  
  The functions on this class handle a special case for NER by looking for a field called "tags"
  This check is brittle, i.e., the code could break if the name of this field has changed, or if
  a non-NER model has a field called "tags".
  
  Registered as an `Attacker` with name "input-reduction".
class_docstr_tok: ["Runs","the","input","reduction","method","from","[","Pathologies","of","Neural","Models","Make","Interpretations","Difficult","]","(","https",":","\/\/arxiv.org\/abs\/1804.07781",")",",","which","removes","as","many","words","as","possible","from","the","input","without","changing","the","model","'s","prediction",".","The","functions","on","this","class","handle","a","special","case","for","NER","by","looking","for","a","field","called","``","tags","''","This","check","is","brittle",",","i.e.",",","the","code","could","break","if","the","name","of","this","field","has","changed",",","or","if","a","non-NER","model","has","a","field","called","``","tags","''",".","Registered","as","an","`","Attacker","`","with","name","``","input-reduction","''","."]
code: def _attack_instance(
      self,
      inputs: JsonDict,
      instance: Instance,
      input_field_to_attack: str,
      grad_input_field: str,
      ignore_tokens: List[str],
  ):
      # Save fields that must be checked for equality
      fields_to_compare = utils.get_fields_to_compare(
          inputs, instance, input_field_to_attack
      )
  
      # Set num_ignore_tokens, which tells input reduction when to stop
      # We keep at least one token for input reduction on classification/entailment/etc.
      if "tags" not in instance:
          num_ignore_tokens = 1
          tag_mask = None
  
      # Set num_ignore_tokens for NER and build token mask
      else:
          (
              num_ignore_tokens,
              tag_mask,
              original_tags,
          ) = _get_ner_tags_and_mask(
              instance, input_field_to_attack, ignore_tokens
          )
  
      text_field: TextField = instance[input_field_to_attack]  # type: ignore
      current_tokens = deepcopy(text_field.tokens)
      candidates = [(instance, -1, tag_mask)]
      # keep removing tokens until prediction is about to change
      while len(current_tokens) > num_ignore_tokens and candidates:
          # sort current candidates by smallest length (we want to remove as many tokens as possible)
          def get_length(input_instance: Instance):
              input_text_field: TextField = input_instance[input_field_to_attack]  # type: ignore
              return len(input_text_field.tokens)
  
          candidates = heapq.nsmallest(
              self.beam_size, candidates, key=lambda x: get_length(x[0])
          )
  
          beam_candidates = deepcopy(candidates)
          candidates = []
          for beam_instance, smallest_idx, tag_mask in beam_candidates:
              # get gradients and predictions
              beam_tag_mask = deepcopy(tag_mask)
              grads, outputs = self.predictor.get_gradients(
                  [beam_instance]
              )
  
              for output in outputs:
                  if isinstance(outputs[output], torch.Tensor):
                      outputs[output] = (
                          outputs[output]
                          .detach()
                          .cpu()
                          .numpy()
                          .squeeze()
                          .squeeze()
                      )
                  elif isinstance(outputs[output], list):
                      outputs[output] = outputs[output][0]
  
              # Check if any fields have changed, if so, next beam
              if "tags" not in instance:
                  # relabel beam_instance since last iteration removed an input token
                  beam_instance = (
                      self.predictor.predictions_to_labeled_instances(
                          beam_instance, outputs
                      )[0]
                  )
                  if utils.instance_has_changed(
                      beam_instance, fields_to_compare
                  ):
                      continue
  
              # special case for sentence tagging (we have tested NER)
              else:
                  # remove the mask where you remove the input token from.
                  if (
                      smallest_idx != -1
                  ):  # Don't delete on the very first iteration
                      del beam_tag_mask[smallest_idx]  # type: ignore
                  cur_tags = [
                      outputs["tags"][x] for x in range(len(outputs["tags"])) if beam_tag_mask[x]  # type: ignore
                  ]
                  if cur_tags != original_tags:
                      continue
  
              # remove a token from the input
              text_field: TextField = beam_instance[input_field_to_attack]  # type: ignore
              current_tokens = deepcopy(text_field.tokens)
              reduced_instances_and_smallest = _remove_one_token(
                  beam_instance,
                  input_field_to_attack,
                  grads[grad_input_field][0],
                  ignore_tokens,
                  self.beam_size,
                  beam_tag_mask,  # type: ignore
              )
              candidates.extend(reduced_instances_and_smallest)
      return current_tokens
  
file_path: allennlp/allennlp/interpret/attackers/input_reduction.py
imports: from copy import deepcopy
  from typing import List, Tuple
  import heapq
  import numpy
  import torch
  from allennlp.common.util import JsonDict, sanitize
  from allennlp.data import Instance
  from allennlp.data.fields import TextField, SequenceLabelField
  from allennlp.interpret.attackers import utils
  from allennlp.interpret.attackers.attacker import Attacker
  from allennlp.predictors import Predictor
label_desc: Use image node_id 3 for calling the InputReduction obj's underlying member method code with example usage: obj._attack_instance(inputs, instance, input_field_to_attack, grad_input_field, ignore_tokens) and returns: current_tokens, len