class_docstr: Ecco's central class. A wrapper around language models. We use it to run the language models
  and collect important data like input saliency and neuron activations.
  
  A LM object is typically not created directly by users,
  it is returned by `ecco.from_pretrained()`.
  
  Usage:
  
  ```python
  import ecco
  
  lm = ecco.from_pretrained('distilgpt2')
  output = lm.generate("Hello computer")
  ```
docstr: Run a forward pass through the model. For when we don't care about output tokens.
  Currently only support activations collection. No attribution/saliency.
  
  Usage:
  
  ```python
  inputs = lm.tokenizer("Hello computer", return_tensors="pt")
  output = lm(inputs)
  ```
  
  Args:
      input_tokens: tuple returned by tokenizer( TEXT, return_tensors="pt").
          contains key 'input_ids', its value tensor with input token ids.
          Shape is (batch_size, sequence_length).
          Also a key for masked tokens
code: def __call__(self, input_tokens: torch.Tensor):
      """
      Run a forward pass through the model. For when we don't care about output tokens.
      Currently only support activations collection. No attribution/saliency.
  
      Usage:
  
      ```python
      inputs = lm.tokenizer("Hello computer", return_tensors="pt")
      output = lm(inputs)
      ```
  
      Args:
          input_tokens: tuple returned by tokenizer( TEXT, return_tensors="pt").
              contains key 'input_ids', its value tensor with input token ids.
              Shape is (batch_size, sequence_length).
              Also a key for masked tokens
      """
  
      if "input_ids" not in input_tokens:
          raise ValueError(
              "Parameter 'input_tokens' needs to have the attribute 'input_ids'."
              "Verify it was produced by the appropriate tokenizer with the "
              'parameter return_tensors="pt".'
          )
  
      # Move inputs to GPU if the model is on GPU
      if (
          self.model.device.type == "cuda"
          and input_tokens["input_ids"].device.type == "cpu"
      ):
          input_tokens = self.to(input_tokens)
  
      # Remove downstream. For now setting to batch length
      n_input_tokens = len(input_tokens["input_ids"][0])
  
      # attach hooks
      self._attach_hooks(self.model)
  
      # model
      if self.model_type == "mlm":
          output = self.model(**input_tokens, return_dict=True)
          lm_head = None
      elif self.model_type == "causal":
          output = self.model(
              **input_tokens, return_dict=True, use_cache=False
          )
          lm_head = self.model.lm_head
      elif self.model_type == "enc-dec":
          decoder_input_ids = (
              self.model._prepare_decoder_input_ids_for_generation(
                  input_tokens["input_ids"], None, None
              )
          )
          output = self.model(
              **input_tokens,
              decoder_input_ids=decoder_input_ids,
              return_dict=True,
              use_cache=False,
          )
          lm_head = self.model.lm_head
      else:
          raise NotImplemented(
              f"model type {self.model_type} not found"
          )
  
      # Turn activations from dict to a proper array
      activations_dict = self._all_activations_dict
      for layer_type, activations in activations_dict.items():
          self.activations[layer_type] = activations_dict_to_array(
              activations
          )
  
      encoder_hidden_states = getattr(
          output, "encoder_hidden_states", None
      )
      decoder_hidden_states = getattr(
          output,
          "hidden_states",
          getattr(output, "decoder_hidden_states", None),
      )
  
      if self.model_type in ["causal", "mlm"]:
          # First hidden state of the causal model is the embedding layer, skip it
          # FIXME: do this in a cleaner way
          embedding_states = decoder_hidden_states[0]
          decoder_hidden_states = decoder_hidden_states[1:]
  
      elif self.model_type == "enc-dec":
          embedding_states = encoder_hidden_states[0]
          encoder_hidden_states = encoder_hidden_states[1:]
  
      else:
          raise NotImplemented(
              f"model type {self.model_type} not found"
          )
  
      tokens = []
      for i in input_tokens["input_ids"]:
          token = self.tokenizer.convert_ids_to_tokens(i)
          tokens.append(token)
  
      attn = getattr(output, "attentions", None)
      return OutputSeq(
          **{
              "tokenizer": self.tokenizer,
              "token_ids": input_tokens["input_ids"],
              "n_input_tokens": n_input_tokens,
              "tokens": tokens,
              "encoder_hidden_states": encoder_hidden_states,
              "decoder_hidden_states": decoder_hidden_states,
              "embedding_states": embedding_states,
              "attention": attn,
              "activations": self.activations,
              "collect_activations_layer_nums": self.collect_activations_layer_nums,
              "lm_head": lm_head,
              "model_type": self.model_type,
              "device": self.device,
              "config": self.model_config,
          }
      )
  
imports: from collections import defaultdict
  import inspect
  import json
  import os
  import random
  import torch
  import transformers
  from transformers import BatchEncoding
  import ecco
  import numpy
  from IPython import display
  from torch.nn import functional
  from ecco.attribution import compute_primary_attributions_scores
  from ecco.output import OutputSeq
  from typing import Optional, Any, List, Tuple, Dict, Union
  from operator import attrgetter
  import re
  from ecco.util import is_partial_token, strip_tokenizer_prefix
  from packaging import version
label_desc: Use image node_id 6 for calling the LM obj's underlying member method code with example usage: obj.__call__(input_tokens) and returns: OutputSeq