class_docstr: Transformer-based (duplex) tagger model for TN/ITN.
docstr: Main function for Inference
  
  Args:
      sents: A list of inputs tokenized by a basic tokenizer.
      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:
      all_tag_preds: A list of list where each list contains the raw tag predictions for the corresponding input words in sents.
      nb_spans: A list of ints where each int indicates the number of semiotic spans in input words.
      span_starts: A list of lists where each list contains the starting locations of semiotic spans in input words.
      span_ends: A list of lists where each list contains the ending locations of semiotic spans in input words.
docstr_tok: ["Main","function","for","Inference","Args",":","sents",":","A","list","of","inputs","tokenized","by","a","basic","tokenizer",".","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",":","all_tag_preds",":","A","list","of","list","where","each","list","contains","the","raw","tag","predictions","for","the","corresponding","input","words","in","sents",".","nb_spans",":","A","list","of","ints","where","each","int","indicates","the","number","of","semiotic","spans","in","input","words",".","span_starts",":","A","list","of","lists","where","each","list","contains","the","starting","locations","of","semiotic","spans","in","input","words",".","span_ends",":","A","list","of","lists","where","each","list","contains","the","ending","locations","of","semiotic","spans","in","input","words","."]
code: def _infer(self, sents: List[List[str]], inst_directions: List[str]):
      """Main function for Inference
  
      Args:
          sents: A list of inputs tokenized by a basic tokenizer.
          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:
          all_tag_preds: A list of list where each list contains the raw tag predictions for the corresponding input words in sents.
          nb_spans: A list of ints where each int indicates the number of semiotic spans in input words.
          span_starts: A list of lists where each list contains the starting locations of semiotic spans in input words.
          span_ends: A list of lists where each list contains the ending locations of semiotic spans in input words.
      """
      self.eval()
      # Append prefix
      texts = []
      for ix, sent in enumerate(sents):
          if inst_directions[ix] == constants.INST_BACKWARD:
              prefix = constants.ITN_PREFIX
          elif inst_directions[ix] == constants.INST_FORWARD:
              prefix = constants.TN_PREFIX
          texts.append([prefix] + sent)
  
      # Apply the model
      encodings = self.tokenizer(
          texts,
          is_split_into_words=True,
          padding=True,
          truncation=True,
          return_tensors="pt",
      )
  
      inputs = encodings
      encodings_reduced = None
  
      # check that the length of the 'input_ids' equals as least the length of the original input
      # if an input symbol is missing in the tokenizer's vocabulary (such as emoji or a Chinese character), it could be skipped
      len_texts = [len(x) for x in texts]
      len_ids = [
          len(
              self.tokenizer.convert_ids_to_tokens(
                  x, skip_special_tokens=True
              )
          )
          for x in encodings["input_ids"]
      ]
      idx_valid = [
          i
          for i, (t, enc) in enumerate(zip(len_texts, len_ids))
          if enc >= t
      ]
  
      if len(idx_valid) != len(texts):
          logging.warning(
              "Some of the examples have symbols that were skipped during the tokenization. Such examples will be skipped."
          )
          for i in range(len(texts)):
              if i not in idx_valid:
                  logging.warning(f"Invalid input: {texts[i]}")
          # skip these sentences and fall back to the input
          # exclude invalid examples from the encodings
          encodings_reduced = {
              k: tensor[idx_valid, :] for k, tensor in encodings.items()
          }
          for k, tensor in encodings_reduced.items():
              if tensor.ndim == 1:
                  encodings_reduced[k] = tensor.unsqueeze(dim=0)
          inputs = BatchEncoding(data=encodings_reduced)
  
      # skip the batch if no valid inputs are present
      if (
          encodings_reduced
          and encodings_reduced["input_ids"].numel() == 0
      ):
          # -1 to exclude tag for the prompt token
          all_tag_preds = [
              [constants.SAME_TAG] * (len(x) - 1) for x in texts
          ]
          nb_spans = [0] * len(texts)
          span_starts = [] * len(texts)
          span_ends = [] * len(texts)
          return all_tag_preds, nb_spans, span_starts, span_ends
  
      logits = self.model(**inputs.to(self.device)).logits
      pred_indexes = torch.argmax(logits, dim=-1).tolist()
  
      # Extract all_tag_preds for words
      all_tag_preds = []
      batch_size, max_len = encodings["input_ids"].size()
      pred_idx = 0
      for ix in range(batch_size):
          if ix in idx_valid:
              # remove first special token and task prefix token
              raw_tag_preds = [
                  constants.ALL_TAG_LABELS[p]
                  for p in pred_indexes[pred_idx][2:]
              ]
              tag_preds, previous_word_idx = [], None
              word_ids = encodings.word_ids(batch_index=ix)[2:]
              for jx, word_idx in enumerate(word_ids):
                  if word_idx is None:
                      continue
                  if word_idx != previous_word_idx:
                      tag_preds.append(
                          raw_tag_preds[jx]
                      )  # without special token at index 0
                  previous_word_idx = word_idx
              pred_idx += 1
          else:
              # for excluded examples, use SAME tags for all words
              tag_preds = [constants.SAME_TAG] * (len(texts[ix]) - 1)
          all_tag_preds.append(tag_preds)
  
      # Post-correction of simple tagger mistakes, i.e. I- tag is proceeding the B- tag in a span
      all_tag_preds = [
          self._postprocess_tag_preds(words, inst_dir, ps)
          for words, inst_dir, ps in zip(
              sents, inst_directions, all_tag_preds
          )
      ]
  
      # Decoding
      nb_spans, span_starts, span_ends = self.decode_tag_preds(
          all_tag_preds
      )
      return all_tag_preds, nb_spans, span_starts, span_ends
  
imports: from time import perf_counter
  from typing import Dict, List, Optional
  import torch
  from omegaconf import DictConfig
  from pytorch_lightning import Trainer
  from torch import nn
  from transformers import AutoModelForTokenClassification, AutoTokenizer, DataCollatorForTokenClassification
  from transformers.tokenization_utils_base import BatchEncoding
  from nemo.collections.nlp.data.text_normalization import TextNormalizationTaggerDataset, constants
  from nemo.collections.nlp.metrics.classification_report import ClassificationReport
  from nemo.collections.nlp.models.duplex_text_normalization.utils import has_numbers
  from nemo.collections.nlp.models.nlp_model import NLPModel
  from nemo.core.classes.common import PretrainedModelInfo, typecheck
  from nemo.core.neural_types import ChannelType, LogitsType, MaskType, NeuralType
  from nemo.utils import logging
label_desc: Use image node_id 12 for calling the DuplexTaggerModel obj's underlying member method code with example usage: obj._infer(sents, inst_directions) and returns: all_tag_preds,  nb_spans,  span_starts,  span_ends, all_tag_preds,  nb_spans,  span_starts,  span_ends