docstr: Use for long strings of text that might not fit in the model's context.
  
  Technique described here: https://huggingface.co/docs/transformers/perplexity
  It scores "token_stride" tokens at a time using up to "max_length" tokens as context,
  straddling "i", and moving forward "token_stride" number of tokens at each step.
  Example with max_length = 4, on the second step, where tokens 2 through 4 are being scored:
  input_ids:             [1, 2, 3, 4, 5, 6]
  beg_loc, end_loc, i:    b     i     e
docstr_tok: ["Use","for","long","strings","of","text","that","might","not","fit","in","the","model","'s","context",".","Technique","described","here",":","https",":","\/\/huggingface.co\/docs\/transformers\/perplexity","It","scores","``","token_stride","''","tokens","at","a","time","using","up","to","``","max_length","''","tokens","as","context",",","straddling","``","i","''",",","and","moving","forward","``","token_stride","''","number","of","tokens","at","each","step",".","Example","with","max_length","=","4",",","on","the","second","step",",","where","tokens","2","through","4","are","being","scored",":","input_ids",":","[","1",",","2",",","3",",","4",",","5",",","6","]","beg_loc",",","end_loc",",","i",":","b","i","e"]
code: def cross_entropy_strided(
      self, input_ids: torch.Tensor, attention_mask: torch.Tensor
  ) -> List[float]:
      """
      Use for long strings of text that might not fit in the model's context.
  
      Technique described here: https://huggingface.co/docs/transformers/perplexity
      It scores "token_stride" tokens at a time using up to "max_length" tokens as context,
      straddling "i", and moving forward "token_stride" number of tokens at each step.
      Example with max_length = 4, on the second step, where tokens 2 through 4 are being scored:
      input_ids:             [1, 2, 3, 4, 5, 6]
      beg_loc, end_loc, i:    b     i     e
      """
      bsz = input_ids.size(0)
      # maximum context length the model is capable of processing
      max_length = self.ppl_model.config.n_positions
      assert max_length % 2 == 0
      token_stride = max_length // 2
  
      nlls = []
      end_loc = 0
      total_tokens_scored = 0
      # keep stepping forward until last token is scored
      for i in range(0, input_ids.size(1), token_stride):
          # score using max context possible
          beg_loc = max(i + token_stride - max_length, 0)
          end_loc = min(i + token_stride, input_ids.size(1))
          input = input_ids[:, beg_loc:end_loc].to(self.device)
          mask = attention_mask[:, beg_loc:end_loc].to(self.device)
          # for tokens we are only treating as context, set the target to ignore_index so they won't be scored
          target_len = end_loc - i
          label = input.clone()
          label[:, :-target_len] = self.cross_entropy_loss.ignore_index
  
          with torch.no_grad():
              outputs = self.ppl_model(
                  input, attention_mask=mask, labels=label
              )
  
              # Copied from transformers GPT2LMHeadModel.forward implementation
              # so we can get unreduced losses:
              # Shift so that tokens < n predict n
              shift_logits = outputs.logits[..., :-1, :].contiguous()
              shift_labels = label[..., 1:].contiguous()
              # Flatten the tokens
              loss = self.cross_entropy_loss(
                  shift_logits.view(-1, shift_logits.size(-1)),
                  shift_labels.view(-1),
              )
  
              # unflatten
              loss = loss.view(bsz, -1)
              # first token is never scored, and masked tokens in the target sequence aren't scored
              new_tokens = mask[:, 1:][:, -target_len:].sum(-1)
              # accumulate loss, which will later be divided by the total token count
              neg_log_likelihood = loss.sum(-1)
  
          nlls.append(neg_log_likelihood)
          total_tokens_scored += new_tokens
  
      assert end_loc == input_ids.size(
          1
      ), "we didn't get to the end of the sequence"
      assert (
          total_tokens_scored.sum() == attention_mask.sum() - bsz
      ), "our loss hasn't been weighted properly"
  
      return (
          torch.stack(nlls, dim=1).sum(-1) / total_tokens_scored
      ).tolist()
  
imports: from collections import defaultdict
  import itertools
  import math
  import numpy
  from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
  import torch
  from torch import nn
  from tqdm import tqdm
  from projects.roscoe.utils import cosine_similarity_scaled, embedding_alignment, al_mean
label_desc: Use image node_id 21 for calling the Evaluator obj's underlying member method code with example usage: obj.cross_entropy_strided(input_ids, attention_mask) and returns: unknown