class_docstr: Transformer-based (duplex) decoder model for TN/ITN.
docstr: Main function for Inference
  Args:
      sents: A list of inputs tokenized by a basic tokenizer.
      nb_spans: A list of ints where each int indicates the number of semiotic spans in each input.
      span_starts: A list of lists where each list contains the starting locations of semiotic spans in an input.
      span_ends: A list of lists where each list contains the ending locations of semiotic spans in an input.
      inst_directions: A list of str where each str indicates the direction of the corresponding instance (i.e., INST_BACKWARD for ITN or INST_FORWARD for TN).
  
  Returns: A list of lists where each list contains the decoded spans for the corresponding input.
code: def _infer(
      self,
      sents: List[List[str]],
      nb_spans: List[int],
      span_starts: List[List[int]],
      span_ends: List[List[int]],
      inst_directions: List[str],
  ):
      """Main function for Inference
      Args:
          sents: A list of inputs tokenized by a basic tokenizer.
          nb_spans: A list of ints where each int indicates the number of semiotic spans in each input.
          span_starts: A list of lists where each list contains the starting locations of semiotic spans in an input.
          span_ends: A list of lists where each list contains the ending locations of semiotic spans in an input.
          inst_directions: A list of str where each str indicates the direction of the corresponding instance (i.e., INST_BACKWARD for ITN or INST_FORWARD for TN).
  
      Returns: A list of lists where each list contains the decoded spans for the corresponding input.
      """
      self.eval()
  
      if sum(nb_spans) == 0:
          return [[]] * len(sents)
      model, tokenizer = self.model, self.tokenizer
      ctx_size = constants.DECODE_CTX_SIZE
      extra_id_0 = constants.EXTRA_ID_0
      extra_id_1 = constants.EXTRA_ID_1
  
      """
          Build all_inputs - extracted spans to be transformed by the decoder model
          Inputs for TN direction have "0" prefix, while the backward, ITN direction, has prefix "1"
          "input_centers" - List[str] - ground-truth labels for the span
          """
      input_centers, input_dirs, all_inputs = [], [], []
      for ix, sent in enumerate(sents):
          cur_inputs = []
          for jx in range(nb_spans[ix]):
              cur_start = span_starts[ix][jx]
              cur_end = span_ends[ix][jx]
              ctx_left = sent[max(0, cur_start - ctx_size) : cur_start]
              ctx_right = sent[cur_end + 1 : cur_end + 1 + ctx_size]
              span_words = sent[cur_start : cur_end + 1]
              span_words_str = " ".join(span_words)
              input_centers.append(span_words_str)
              input_dirs.append(inst_directions[ix])
              # Build cur_inputs
              if inst_directions[ix] == constants.INST_BACKWARD:
                  cur_inputs = [constants.ITN_PREFIX]
              if inst_directions[ix] == constants.INST_FORWARD:
                  cur_inputs = [constants.TN_PREFIX]
              cur_inputs += ctx_left
              cur_inputs += (
                  [extra_id_0]
                  + span_words_str.split(" ")
                  + [extra_id_1]
              )
              cur_inputs += ctx_right
              all_inputs.append(" ".join(cur_inputs))
  
      # Apply the decoding model
      batch = tokenizer(all_inputs, padding=True, return_tensors="pt")
      input_ids = batch["input_ids"].to(self.device)
  
      (
          generated_texts,
          generated_ids,
          sequence_toks_scores,
      ) = self._generate_predictions(
          input_ids=input_ids, model_max_len=self.max_sequence_len
      )
  
      # Use covering grammars (if enabled)
      if self.use_cg:
          # Compute sequence probabilities
          sequence_probs = torch.ones(len(all_inputs)).to(self.device)
          for ix, cur_toks_scores in enumerate(sequence_toks_scores):
              cur_generated_ids = generated_ids[:, ix + 1].tolist()
              cur_toks_probs = torch.nn.functional.softmax(
                  cur_toks_scores, dim=-1
              )
              # Compute selected_toks_probs
              selected_toks_probs = []
              for jx, _id in enumerate(cur_generated_ids):
                  if _id != self.tokenizer.pad_token_id:
                      selected_toks_probs.append(
                          cur_toks_probs[jx, _id]
                      )
                  else:
                      selected_toks_probs.append(1)
              selected_toks_probs = torch.tensor(
                  selected_toks_probs
              ).to(self.device)
              sequence_probs *= selected_toks_probs
  
          # For TN cases where the neural model is not confident, use CGs
          neural_confidence_threshold = self.neural_confidence_threshold
          for ix, (_dir, _input, _prob) in enumerate(
              zip(input_dirs, input_centers, sequence_probs)
          ):
              if (
                  _dir == constants.INST_FORWARD
                  and _prob < neural_confidence_threshold
              ):
                  try:
                      cg_outputs = self.cg_normalizer.normalize(
                          text=_input,
                          verbose=False,
                          n_tagged=self.n_tagged,
                      )
                      generated_texts[ix] = list(cg_outputs)[0]
                  except:  # if there is any exception, fall back to the input
                      generated_texts[ix] = _input
  
      # Prepare final_texts
      final_texts, span_ctx = [], 0
      for nb_span in nb_spans:
          cur_texts = []
          for i in range(nb_span):
              cur_texts.append(generated_texts[span_ctx])
              span_ctx += 1
          final_texts.append(cur_texts)
  
      return final_texts
  
imports: import json
  import os
  from collections import defaultdict
  from math import ceil
  from typing import Dict, List, Optional, Union
  import torch
  from omegaconf import DictConfig
  from pytorch_lightning import Trainer
  from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, DataCollatorForSeq2Seq
  import nemo.collections.nlp.data.text_normalization.constants
  from nemo.collections.common.tokenizers.moses_tokenizers import MosesProcessor
  from nemo.collections.nlp.data.text_normalization import TextNormalizationTestDataset
  from nemo.collections.nlp.data.text_normalization.decoder_dataset import TarredTextNormalizationDecoderDataset, TextNormalizationDecoderDataset
  from nemo.collections.nlp.models.duplex_text_normalization.utils import get_formatted_string
  from nemo.collections.nlp.models.nlp_model import NLPModel
  from nemo.core.classes.common import PretrainedModelInfo, typecheck
  from nemo.core.neural_types import ChannelType, LabelsType, LossType, MaskType, NeuralType
  from nemo.utils import logging
label_desc: Use image node_id 12 for calling the DuplexDecoderModel obj's underlying member method code with example usage: obj._infer(sents, nb_spans, span_starts, span_ends, inst_directions) and returns: final_texts, unknown