class_docstr: Graph decoder with token_lm-based decoding graph.
  Available topologies:
      -   `default`, with or without self-loops
      -   `compact`, with or without self-loops
      -   `shared_blank`, with or without self-loops
      -   `minimal`, without self-loops
  
  Can do decoding and forced alignment.
  
  cfg takes precedence over all optional parameters
  We keep explicit parameter setting to be able to create an instance without the need of a config.
code: def update_graph(self, graph: "k2.Fsa"):
      self.token_lm = graph
      token_lm = self.token_lm.clone()
      if hasattr(token_lm, "aux_labels"):
          delattr(token_lm, "aux_labels")
      labels = token_lm.labels
      if labels.max() != self.num_classes - 1:
          raise ValueError(
              f"token_lm is not compatible with the num_classes: {labels.unique()}, {self.num_classes}"
          )
      self.graph_compiler = CtcNumGraphCompiler(
          self.num_classes,
          self.blank,
          self.topo_type,
          self.topo_with_self_loops,
          self.device,
          token_lm,
      )
      self.base_graph = k2.create_fsa_vec(
          [self.graph_compiler.base_graph]
      ).to(self.device)
  
imports: from abc import abstractmethod
  from typing import List, Optional, Tuple, Union
  import torch
  from omegaconf import DictConfig
  from nemo.collections.asr.parts.k2.classes import GraphIntersectDenseConfig
  from nemo.collections.asr.parts.k2.loss_mixins import CtcK2Mixin, RnntK2Mixin
  from nemo.collections.asr.parts.k2.utils import invert_permutation, load_graph
  from nemo.utils import logging
label_desc: Use image node_id 2 for calling the TokenLMDecoder obj's underlying member method code with example usage: obj.update_graph(graph) without return types