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])
docstr: Creates tensor of transition (log) probabilities.
  Only allows transitions to the same phoneme (self-loop) or the next
  phoneme in the phn sequence
  
  Arguments
  ---------
  phn_lens_abs : torch.Tensor (batch)
      The absolute length of each phoneme sequence in the batch.
  
  Returns
  -------
  trans_prob : torch.Tensor (batch, from, to)
docstr_tok: ["Creates","tensor","of","transition","(","log",")","probabilities",".","Only","allows","transitions","to","the","same","phoneme","(","self-loop",")","or","the","next","phoneme","in","the","phn","sequence","Arguments","--","--","--","--","-","phn_lens_abs",":","torch.Tensor","(","batch",")","The","absolute","length","of","each","phoneme","sequence","in","the","batch",".","Returns","--","--","--","-","trans_prob",":","torch.Tensor","(","batch",",","from",",","to",")"]
code: def _make_trans_prob(self, phn_lens_abs):
      """Creates tensor of transition (log) probabilities.
      Only allows transitions to the same phoneme (self-loop) or the next
      phoneme in the phn sequence
  
      Arguments
      ---------
      phn_lens_abs : torch.Tensor (batch)
          The absolute length of each phoneme sequence in the batch.
  
      Returns
      -------
      trans_prob : torch.Tensor (batch, from, to)
      """
      # Extract useful values for later
      batch_size = len(phn_lens_abs)
      U_max = int(phn_lens_abs.max())
      device = phn_lens_abs.device
  
      ## trans_prob matrix consists of 2 diagonals:
      ## (1) offset diagonal (next state) &
      ## (2) main diagonal (self-loop)
      # make offset diagonal
      trans_prob_off_diag = torch.eye(U_max - 1)
      zero_side = torch.zeros([U_max - 1, 1])
      zero_bottom = torch.zeros([1, U_max])
      trans_prob_off_diag = torch.cat(
          (zero_side, trans_prob_off_diag), 1
      )
      trans_prob_off_diag = torch.cat(
          (trans_prob_off_diag, zero_bottom), 0
      )
  
      # make main diagonal
      trans_prob_main_diag = torch.eye(U_max)
  
      # join the diagonals and repeat for whole batch
      trans_prob = trans_prob_off_diag + trans_prob_main_diag
      trans_prob = (
          trans_prob.reshape(1, U_max, U_max)
          .repeat(batch_size, 1, 1)
          .to(device)
      )
  
      # clear probabilities for too-long sequences
      mask_a = (
          torch.arange(U_max, device=device)[None, :]
          < phn_lens_abs[:, None]
      )
      mask_a = mask_a.unsqueeze(2)
      mask_a = mask_a.expand(-1, -1, U_max)
      mask_b = mask_a.permute(0, 2, 1)
      trans_prob = trans_prob * (mask_a & mask_b).float()
  
      ## put -infs in place of zeros:
      trans_prob = torch.where(
          trans_prob == 1,
          trans_prob,
          torch.tensor(-float("Inf"), device=device),
      )
  
      ## normalize
      trans_prob = torch.nn.functional.log_softmax(trans_prob, dim=2)
  
      ## set nans to v neg numbers
      trans_prob[trans_prob != trans_prob] = self.neg_inf
      ## set -infs to v neg numbers
      trans_prob[trans_prob == -float("Inf")] = self.neg_inf
  
      return trans_prob
  
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 5 for calling the HMMAligner obj's underlying member method code with example usage: obj._make_trans_prob(phn_lens_abs) and returns: trans_prob