class_docstr: This class calculates Viterbi alignments in the forward method.
  
  It also records alignments and creates batches of them for use
  in Viterbi training.
  
  Arguments
  ---------
  states_per_phoneme : int
      Number of hidden states to use per phoneme.
  output_folder : str
      It is the folder that the alignments will be stored in when
      saved to disk. Not yet implemented.
  neg_inf : float
      The float used to represent a negative infinite log probability.
      Using `-float("Inf")` tends to give numerical instability.
      A number more negative than -1e5 also sometimes gave errors when
      the `genbmm` library was used (currently not in use). (default: -1e5)
  batch_reduction : string
      One of "none", "sum" or "mean".
      What kind of batch-level reduction to apply to the loss calculated
      in the forward method.
  input_len_norm : bool
      Whether to normalize the loss in the forward method by the length of
      the inputs.
  target_len_norm : bool
      Whether to normalize the loss in the forward method by the length of
      the targets.
  lexicon_path : string
      The location of the lexicon.
  
  Example
  -------
  >>> log_posteriors = torch.tensor([[[ -1., -10., -10.],
  ...                                 [-10.,  -1., -10.],
  ...                                 [-10., -10.,  -1.]],
  ...
  ...                                [[ -1., -10., -10.],
  ...                                 [-10.,  -1., -10.],
  ...                                 [-10., -10., -10.]]])
  >>> lens = torch.tensor([1., 0.66])
  >>> phns = torch.tensor([[0, 1, 2],
  ...                      [0, 1, 0]])
  >>> phn_lens = torch.tensor([1., 0.66])
  >>> aligner = HMMAligner()
  >>> forward_scores = aligner(
  ...        log_posteriors, lens, phns, phn_lens, 'forward'
  ... )
  >>> forward_scores.shape
  torch.Size([2])
  >>> viterbi_scores, alignments = aligner(
  ...        log_posteriors, lens, phns, phn_lens, 'viterbi'
  ... )
  >>> alignments
  [[0, 1, 2], [0, 1]]
  >>> viterbi_scores.shape
  torch.Size([2])
code: def __init__(
      self,
      states_per_phoneme=1,
      output_folder="",
      neg_inf=-1e5,
      batch_reduction="none",
      input_len_norm=False,
      target_len_norm=False,
      lexicon_path=None,
  ):
      super().__init__()
      self.states_per_phoneme = states_per_phoneme
      self.output_folder = output_folder
      self.neg_inf = neg_inf
  
      self.batch_reduction = batch_reduction
      self.input_len_norm = input_len_norm
      self.target_len_norm = target_len_norm
  
      self.align_dict = {}
      self.lexicon_path = lexicon_path
  
      if self.lexicon_path is not None:
          with open(self.lexicon_path, "r") as f:
              lines = f.readlines()
  
          for i, line in enumerate(lines):
              if line[0] != ";":
                  start_index = i
                  break
  
          lexicon = {}  # {"read": {0: "r eh d", 1: "r iy d"}}
          lexicon_phones = set()
          for i in range(start_index, len(lines)):
              line = lines[i]
              word = line.split()[0]
              phones = line.split("/")[1]
  
              phones = "".join([p for p in phones if not p.isdigit()])
  
              for p in phones.split(" "):
                  lexicon_phones.add(p)
  
              if "~" in word:
                  word = word.split("~")[0]
              if word in lexicon:
                  number_of_existing_pronunciations = len(lexicon[word])
                  lexicon[word][
                      number_of_existing_pronunciations
                  ] = phones
              else:
                  lexicon[word] = {0: phones}
          self.lexicon = lexicon
  
          lexicon_phones = list(lexicon_phones)
          lexicon_phones.sort()
  
          self.lex_lab2ind = {
              p: i + 1 for i, p in enumerate(lexicon_phones)
          }
          self.lex_ind2lab = {
              i + 1: p for i, p in enumerate(lexicon_phones)
          }
  
          # add sil, which is not in the lexicon
          self.lex_lab2ind["sil"] = 0
          self.lex_ind2lab[0] = "sil"
  
imports: import torch
  import random
  from speechbrain.utils.checkpoints import register_checkpoint_hooks
  from speechbrain.utils.checkpoints import mark_as_saver
  from speechbrain.utils.checkpoints import mark_as_loader
  from speechbrain.utils.data_utils import undo_padding
label_desc: Use image node_id 1 to create a new HMMAligner object from inherited base classes: torch.nn with example: obj = HMMAligner(states_per_phoneme, output_folder, neg_inf, batch_reduction, input_len_norm, target_len_norm, lexicon_path)