class_docstr: Mask-CTC-based non-autoregressive inference
class_docstr_tok: ["Mask-CTC-based","non-autoregressive","inference"]
docstr: Perform Mask-CTC inference
docstr_tok: ["Perform","Mask-CTC","inference"]
code: def forward(self, enc_out: torch.Tensor) -> List[Hypothesis]:
      """Perform Mask-CTC inference"""
      # greedy ctc outputs
      enc_out = enc_out.unsqueeze(0)
      ctc_probs, ctc_ids = torch.exp(self.ctc.log_softmax(enc_out)).max(
          dim=-1
      )
      y_hat = torch.stack([x[0] for x in groupby(ctc_ids[0])])
      y_idx = torch.nonzero(y_hat != 0).squeeze(-1)
  
      logging.info(
          "ctc:{}".format(self.ids2text(y_hat[y_idx].tolist()))
      )
  
      # calculate token-level ctc probabilities by taking
      # the maximum probability of consecutive frames with
      # the same ctc symbols
      probs_hat = []
      cnt = 0
      for i, y in enumerate(y_hat.tolist()):
          probs_hat.append(-1)
          while cnt < ctc_ids.shape[1] and y == ctc_ids[0][cnt]:
              if probs_hat[i] < ctc_probs[0][cnt]:
                  probs_hat[i] = ctc_probs[0][cnt].item()
              cnt += 1
      probs_hat = torch.from_numpy(numpy.array(probs_hat)).to(
          enc_out.device
      )
  
      # mask ctc outputs based on ctc probabilities
      p_thres = self.threshold_probability
      mask_idx = torch.nonzero(probs_hat[y_idx] < p_thres).squeeze(-1)
      confident_idx = torch.nonzero(
          probs_hat[y_idx] >= p_thres
      ).squeeze(-1)
      mask_num = len(mask_idx)
  
      y_in = (
          torch.zeros(1, len(y_idx), dtype=torch.long).to(
              enc_out.device
          )
          + self.mask_token
      )
      y_in[0][confident_idx] = y_hat[y_idx][confident_idx]
  
      logging.info("msk:{}".format(self.ids2text(y_in[0].tolist())))
  
      # iterative decoding
      if not mask_num == 0:
          K = self.n_iterations
          num_iter = K if mask_num >= K and K > 0 else mask_num
  
          for t in range(num_iter - 1):
              pred, _ = self.mlm(
                  enc_out, [enc_out.size(1)], y_in, [y_in.size(1)]
              )
              pred_score, pred_id = pred[0][mask_idx].max(dim=-1)
              cand = torch.topk(pred_score, mask_num // num_iter, -1)[1]
              y_in[0][mask_idx[cand]] = pred_id[cand]
              mask_idx = torch.nonzero(
                  y_in[0] == self.mask_token
              ).squeeze(-1)
  
              logging.info(
                  "msk:{}".format(self.ids2text(y_in[0].tolist()))
              )
  
          # predict leftover masks (|masks| < mask_num // num_iter)
          pred, _ = self.mlm(
              enc_out, [enc_out.size(1)], y_in, [y_in.size(1)]
          )
          y_in[0][mask_idx] = pred[0][mask_idx].argmax(dim=-1)
  
          logging.info("msk:{}".format(self.ids2text(y_in[0].tolist())))
  
      # pad with mask tokens to ensure compatibility with sos/eos tokens
      yseq = torch.tensor(
          [self.mask_token] + y_in.tolist()[0] + [self.mask_token],
          device=y_in.device,
      )
  
      return Hypothesis(yseq=yseq)
  
imports: import logging
  from contextlib import contextmanager
  from itertools import groupby
  from typing import Dict, List, Optional, Tuple, Union
  import numpy
  import torch
  from packaging.version import parse
  from typeguard import check_argument_types
  from espnet2.asr.ctc import CTC
  from espnet2.asr.decoder.mlm_decoder import MLMDecoder
  from espnet2.asr.encoder.abs_encoder import AbsEncoder
  from espnet2.asr.espnet_model import ESPnetASRModel
  from espnet2.asr.frontend.abs_frontend import AbsFrontend
  from espnet2.asr.postencoder.abs_postencoder import AbsPostEncoder
  from espnet2.asr.preencoder.abs_preencoder import AbsPreEncoder
  from espnet2.asr.specaug.abs_specaug import AbsSpecAug
  from espnet2.layers.abs_normalize import AbsNormalize
  from espnet2.text.token_id_converter import TokenIDConverter
  from espnet2.torch_utils.device_funcs import force_gatherable
  from espnet.nets.beam_search import Hypothesis
  from espnet.nets.e2e_asr_common import ErrorCalculator
  from espnet.nets.pytorch_backend.maskctc.add_mask_token import mask_uniform
  from espnet.nets.pytorch_backend.nets_utils import th_accuracy
  from espnet.nets.pytorch_backend.transformer.label_smoothing_loss import LabelSmoothingLoss
label_desc: Use image node_id 3 for calling the MaskCTCInference obj's underlying member method code with example usage: obj.forward(enc_out) and returns: Hypothesis