class_docstr: Container module with an encoder, a recurrent module, and a decoder.
class_docstr_tok: ["Container","module","with","an","encoder",",","a","recurrent","module",",","and","a","decoder","."]
code: def calculate_perplexity(self, text: str) -> float:
      if not self.is_forward_lm:
          text = text[::-1]
  
      # input ids
      input = torch.tensor(
          [self.dictionary.get_idx_for_item(char) for char in text[:-1]]
      ).unsqueeze(1)
      input = input.to(flair.device)
  
      # push list of character IDs through model
      hidden = self.init_hidden(1)
      prediction, _, hidden = self.forward(input, hidden)
  
      # the target is always the next character
      targets = torch.tensor(
          [self.dictionary.get_idx_for_item(char) for char in text[1:]]
      )
      targets = targets.to(flair.device)
  
      # use cross entropy loss to compare output of forward pass with targets
      cross_entroy_loss = torch.nn.CrossEntropyLoss()
      loss = cross_entroy_loss(
          prediction.view(-1, len(self.dictionary)), targets
      ).item()
  
      # exponentiate cross-entropy loss to calculate perplexity
      perplexity = math.exp(loss)
  
      return perplexity
  
imports: import math
  from pathlib import Path
  from typing import List, Optional, Tuple, Union
  import torch
  from torch import logsumexp, nn
  from torch.optim import Optimizer
  import flair
  from flair.data import Dictionary
  from flair.nn.recurrent import create_recurrent_layer
label_desc: Use image node_id 15 for calling the LanguageModel obj's underlying member method code with example usage: obj.calculate_perplexity(text) and returns: perplexity