code: def compute_ppl_scores(
      self,
      hypo: Chain,
      score_types: List[str],
  ) -> Dict[str, float]:
      scores = {}
  
      if PPL_STEP in score_types or PPL_STEP_MAX in score_types:
          # Step-level Perplexities, for all scores that use them.
          step_perplexities = self.perplexity(
              hypo.chain, self.ppl_batch
          )
  
      def _token_weighted_mean(ppl_tkns_list):
          numer = sum(
              loss * n_tokens for loss, n_tokens in ppl_tkns_list
          )
          denom = sum(n_tokens for _, n_tokens in ppl_tkns_list)
          return numer / denom
  
      if PPL_STEP in score_types:
          scores[PPL_STEP] = 1 / _token_weighted_mean(step_perplexities)
      if PPL_CHAIN in score_types:
          chain_ppl_results = self.perplexity(
              [" ".join(hypo.chain)], self.ppl_batch
          )
          chain_ppl = chain_ppl_results[0][0]
          scores[PPL_CHAIN] = 1 / chain_ppl
      if PPL_STEP_MAX in score_types:
          scores[PPL_STEP_MAX] = 1 / max(
              ppl for ppl, _ in step_perplexities
          )
  
      return scores
  
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 28 for calling the Evaluator obj's underlying member method code with example usage: obj.compute_ppl_scores(hypo, score_types) and returns: scores, unknown