class_docstr: ASR model wrapper to perform alignment building.
  Functionality is limited to the components needed to build an alignment.
docstr: Transforms predictions with probabilities to a list of FrameCtmUnit objects, 
  containing frame-level alignment information (label, start, duration, probability), for a given sample id.
  
  Alignment information can be either token-based (char, wordpiece, ...) or word-based.
docstr_tok: ["Transforms","predictions","with","probabilities","to","a","list","of","FrameCtmUnit","objects",",","containing","frame-level","alignment","information","(","label",",","start",",","duration",",","probability",")",",","for","a","given","sample","id",".","Alignment","information","can","be","either","token-based","(","char",",","wordpiece",",","...",")","or","word-based","."]
code: def _results_to_ctmUnits(
      self, s_id: int, pred: torch.Tensor, prob: torch.Tensor
  ) -> Tuple[int, List["FrameCtmUnit"]]:
      """Transforms predictions with probabilities to a list of FrameCtmUnit objects,
      containing frame-level alignment information (label, start, duration, probability), for a given sample id.
  
      Alignment information can be either token-based (char, wordpiece, ...) or word-based.
      """
      if len(pred) == 0:
          return (s_id, [])
  
      non_blank_idx = (
          (pred != self.blank_id).nonzero(as_tuple=True)[0].cpu()
      )
      pred_ids = pred[non_blank_idx].tolist()
      prob_list = prob.tolist()
      if self.model_type == "rnnt":
          wer_module = self._model.decoding
          # for rnnt forced alignment we always have num_blanks == num_frames,
          # thus len(pred) == num_frames + num_non_blanks
          token_begin = non_blank_idx - torch.arange(len(non_blank_idx))
          token_end = torch.cat(
              (
                  token_begin[1:],
                  torch.tensor([len(pred) - len(non_blank_idx)]),
              )
          )
      else:
          wer_module = self._model._wer
          token_begin = non_blank_idx
          token_end = torch.cat(
              (token_begin[1:], torch.tensor([len(pred)]))
          )
      tokens = wer_module.decode_ids_to_tokens(pred_ids)
      token_len = (token_end - token_begin).tolist()
      token_begin = token_begin.tolist()
      token_prob = [
          sum(prob_list[i:j]) / (j - i)
          for i, j in zip(
              non_blank_idx.tolist(),
              non_blank_idx[1:].tolist() + [len(pred)],
          )
      ]
      if self.word_output:
          words = wer_module.decode_tokens_to_str(pred_ids).split(" ")
          words, word_begin, word_len, word_prob = (
              self._process_tokens_to_words(
                  tokens, token_begin, token_len, token_prob, words
              )
              if hasattr(self._model, "tokenizer")
              else self._process_char_with_space_to_words(
                  tokens, token_begin, token_len, token_prob, words
              )
          )
          return s_id, [
              FrameCtmUnit(t, b, l, p)
              for t, b, l, p in zip(
                  words, word_begin, word_len, word_prob
              )
          ]
      return s_id, [
          FrameCtmUnit(t, b, l, p)
          for t, b, l, p in zip(
              tokens, token_begin, token_len, token_prob
          )
      ]
  
imports: import copy
  import os
  from typing import Dict, List, Optional, Tuple, Union
  import numpy
  import torch
  from omegaconf import DictConfig, OmegaConf, open_dict
  from tqdm.auto import tqdm
  from nemo.collections.asr.data.audio_to_ctm_dataset import FrameCtmUnit
  from nemo.collections.asr.data.audio_to_text_dali import DALIOutputs
  from nemo.collections.asr.models.asr_model import ASRModel
  from nemo.utils import logging
label_desc: Use image node_id 11 for calling the AlignerWrapperModel obj's underlying member method code with example usage: obj._results_to_ctmUnits(s_id, pred, prob) and returns: s_id,  unknown, s_id,  list, s_id,  unknown