docstr: Vanilla LIME
  
  model_wrapped: should contain get_conditional_loglikelihood_batch(texts, completion_offset)
  prompt: prompt to do the attribution with
  completion: completion to do the attribution with
  max_parts_to_perturb: maximum parts to perturb for a single instance
  n_samples: number of total perturbations
  parts: all of the parts, provide it if these are predetermined
  parts_to_replace: if not None, specifies the parts to perturb. if not provided, perturbs all parts.
  
  This will output the final attribution scores along with all the parts
docstr_tok: ["Vanilla","LIME","model_wrapped",":","should","contain","get_conditional_loglikelihood_batch","(","texts",",","completion_offset",")","prompt",":","prompt","to","do","the","attribution","with","completion",":","completion","to","do","the","attribution","with","max_parts_to_perturb",":","maximum","parts","to","perturb","for","a","single","instance","n_samples",":","number","of","total","perturbations","parts",":","all","of","the","parts",",","provide","it","if","these","are","predetermined","parts_to_replace",":","if","not","None",",","specifies","the","parts","to","perturb",".","if","not","provided",",","perturbs","all","parts",".","This","will","output","the","final","attribution","scores","along","with","all","the","parts"]
code: def attribution(
      self,
      model_wrapped,
      prompt,
      completion,
      max_parts_to_perturb=2,
      n_samples=100,
      max_features=3,
      parts=None,
      parts_to_replace=None,
      prompt_fn=None,
      *args,
      **kwargs,
  ):
      """
      Vanilla LIME
  
      model_wrapped: should contain get_conditional_loglikelihood_batch(texts, completion_offset)
      prompt: prompt to do the attribution with
      completion: completion to do the attribution with
      max_parts_to_perturb: maximum parts to perturb for a single instance
      n_samples: number of total perturbations
      parts: all of the parts, provide it if these are predetermined
      parts_to_replace: if not None, specifies the parts to perturb. if not provided, perturbs all parts.
  
      This will output the final attribution scores along with all the parts
      """
      prompt_fn = (lambda x: x) if prompt_fn is None else prompt_fn
  
      if parts is None:
          # Create partitions only if they are not fed from outside. This
          # requires a specified partition_fn
          assert self.partition_fn is not None
          parts = self.partition(prompt)
          parts_to_replace = np.arange(len(parts))
  
      perturbed_texts, indices = self.perturbation_model(
          parts,
          parts_to_replace=parts_to_replace,
          max_parts_to_perturb=max_parts_to_perturb,
          n_samples=n_samples,
      )
      # Add the original prompt
      perturbed_texts.append(prompt)
      indices.append([])
      perturbed_prompts = [prompt_fn(txt) for txt in perturbed_texts]
      try:  # TODO : Fix this hack for tiktoken tokenizers
          completion_len = len(
              model_wrapped.tokenizer(completion)["input_ids"]
          )
      except BaseException:
          completion_len = len(
              model_wrapped.tokenizer.encode(completion)
          )
      prompts = [t + completion for t in perturbed_prompts]
      completion_offset = torch.tensor(
          [completion_len for i in range(len(prompts))]
      )
      (
          perplexities,
          loglikelihoods,
      ) = model_wrapped.get_conditional_loglikelihood_batch(
          texts=prompts,
          completion_offset=completion_offset,
          progress_bar=self.progress_bar,
      )
  
      weights = np.array([len(idx) for idx in indices])
      # Featurization is simple 1-0.
      featurization = np.ones((loglikelihoods.shape[0], len(parts)))
      for i, idx in enumerate(indices):
          featurization[i, idx] = 0
  
      attribution_scores = run_klasso(
          featurization,
          loglikelihoods,
          weights,
          max_features=max_features,
      )
      # Each item of attribution_scores contain (feat_idx, score) pairs.
  
      return attribution_scores, parts
  
imports: import torch
  import numpy
  from abc import ABC, abstractmethod
  from sklearn.linear_model import Ridge, lars_path
  from .text_utils import *
  from .perturbation_tools import RemovalPerturbation
label_desc: Use image node_id 2 for calling the LocalExplanationLikelihood obj's underlying member method code with example usage: obj.attribution(model_wrapped, prompt, completion, max_parts_to_perturb, n_samples, max_features, parts, parts_to_replace, prompt_fn) and returns: attribution_scores,  parts