class_docstr: Labels each token in a sequence as belonging to 1 of N token classes.
  
  :param config: A :py:class:`finetune.config.Settings` object or None (for default config).
  :param \**kwargs: key-value pairs of config items to override.
class_docstr_tok: ["Labels","each","token","in","a","sequence","as","belonging","to","1","of","N","token","classes",".",":","param","config",":","A",":","py",":","class",":","`","finetune.config.Settings","`","object","or","None","(","for","default","config",")",".",":","param","\\","*","*","kwargs",":","key-value","pairs","of","config","items","to","override","."]
docstr: Produces a list of most likely class labels as determined by the fine-tuned model.
  
  :param X: A list / array of text, shape [batch]
  :param per_token: If True, return raw probabilities and labels on a per token basis
  :returns: list of class labels.
docstr_tok: ["Produces","a","list","of","most","likely","class","labels","as","determined","by","the","fine-tuned","model",".",":","param","X",":","A","list","\/","array","of","text",",","shape","[","batch","]",":","param","per_token",":","If","True",",","return","raw","probabilities","and","labels","on","a","per","token","basis",":","returns",":","list","of","class","labels","."]
code: def _predict_decode(
      self,
      zipped_data,
      predictions,
      per_token=False,
      return_negative_confidence=False,
      **kwargs,
  ):
      """
      Produces a list of most likely class labels as determined by the fine-tuned model.
  
      :param X: A list / array of text, shape [batch]
      :param per_token: If True, return raw probabilities and labels on a per token basis
      :returns: list of class labels.
      """
      classes = list(self.input_pipeline.label_encoder.classes_)
      doc_idx = -1
      doc_annotations = []
      raw_text = [
          data.get("raw_text", data["X"]) for data in zipped_data
      ]
      for (
          token_start_idx,
          token_end_idx,
          start_of_doc,
          end_of_doc,
          label_seq,
          proba_seq,
          start,
          end,
      ) in predictions:
          if start_of_doc:
              # if this is the first chunk in a document, start accumulating from scratch
              doc_subseqs = []
              doc_labels = []
              doc_probs = []
              doc_positions = []
              doc_starts = []
              doc_idx += 1
              last_end = 0
              doc_level_probas = []
              chunk_spans = []
  
          label_seq = label_seq[start:end]
          end_of_token_seq = token_end_idx[start:end]
          start_of_token_seq = token_start_idx[start:end]
          proba_seq = proba_seq[start:end]
  
          tok_starts_useful_chunk = [
              i for i in token_start_idx[start:] if i != -1
          ]
          if len(tok_starts_useful_chunk) == 0:
              if chunk_spans:
                  chunk_start_char_idx = chunk_spans[-1]["end"]
              else:
                  chunk_start_char_idx = 0
              # This is a 0 length span here.
              chunk_spans.append(
                  {
                      "start": chunk_start_char_idx,
                      "end": chunk_start_char_idx,
                  }
              )
          else:
              chunk_spans.append(
                  {
                      # This indexing is done like this because end may be > len(token_end_idx) and is intended to be used only for slicing.
                      "start": int(tok_starts_useful_chunk[0]),
                      "end": int(
                          max(token_end_idx[:end])
                      ),  # Max to dodge the -1s
                  }
              )
          proba_seq_masked = proba_seq.copy()
  
          for il, label in enumerate(label_seq):
              # covers the multilabel case where pad is not a distinct class.
              if label in classes:
                  label_idx = classes.index(label)
                  proba_seq_masked[il:, label_idx] = 0.0
          if proba_seq_masked.shape[0] == 0:
              doc_level_probas.append(0)
          else:
              doc_level_probas.append(np.max(proba_seq_masked, axis=0))
  
          for label, start_idx, end_idx, proba in zip(
              label_seq, start_of_token_seq, end_of_token_seq, proba_seq
          ):
              if end_idx == -1:
                  # indicates padding / special tokens
                  continue
  
              assert (
                  start_idx >= last_end
              ), "Start idx: {}, last_end: {}".format(
                  start_idx, last_end
              )
              last_end = end_idx
  
              if self.config.group_bio_tagging:
                  group_prefix = ""
                  if label[:3] == "BG-" or label[:3] == "IG-":
                      group_prefix, label = label[:3], label[3:]
              if self.config.bio_tagging:
                  bio_prefix = None
                  if label != self.config.pad_token:
                      bio_prefix, label = label[:2], label[2:]
              if (
                  self.config.group_bio_tagging
                  and label != self.config.pad_token
              ):
                  # Save the group prefix so the grouping target models can
                  # extract grouping information down the line
                  label = group_prefix + label
  
              def _get_label(label):
                  if label[:3] == "BG-" or label[:3] == "IG-":
                      return label[3:]
                  return label
  
              # if there are no current subsequences
              # or the current subsequence has the wrong label
              # or bio tagging is on and we have a B- tag
              if (
                  not doc_subseqs
                  or per_token
                  or (self.config.bio_tagging and bio_prefix == "B-")
                  or (
                      self.config.group_bio_tagging
                      and group_prefix == "BG-"
                  )
                  or (
                      label != doc_labels[-1]
                      and (
                          # Merge spans if the labels are the same,
                          # disregarding group BIO tags
                          # This is safe as we already hard break on BG-, so
                          # we will only be merging IG- tags
                          not self.config.group_bio_tagging
                          or _get_label(label)
                          != _get_label(doc_labels[-1])
                      )
                  )
              ):
                  assert (
                      start_idx <= end_idx
                  ), "Start: {}, End: {}".format(start_idx, end_idx)
                  # start new subsequence
                  doc_subseqs.append(
                      raw_text[doc_idx][start_idx:end_idx]
                  )
                  doc_labels.append(label)
                  doc_probs.append([proba])
                  doc_positions.append((start_idx, end_idx))
                  doc_starts.append(start_idx)
              else:
                  assert (
                      start_idx <= end_idx
                  ), "Start: {}, End: {}".format(start_idx, end_idx)
                  # continue appending to current subsequence
                  assert (
                      doc_starts[-1] <= end_idx
                  ), "Start: {}, End: {}".format(
                      doc_starts[-1], end_idx
                  )
                  doc_subseqs[-1] = raw_text[doc_idx][
                      doc_starts[-1] : end_idx
                  ]
                  doc_probs[-1].append(proba)
  
          if end_of_doc:
              # last chunk in a document
              prob_dicts = []
              for prob_seq in doc_probs:
                  # format probabilities as dictionary
                  probs = np.mean(np.vstack(prob_seq), axis=0)
                  prob_dicts.append(
                      dict(
                          zip(
                              self.input_pipeline.label_encoder.classes_,
                              probs,
                          )
                      )
                  )
                  if self.multi_label:
                      del prob_dicts[-1][self.config.pad_token]
  
              _, doc_annotations_sample = finetune_to_indico_sequence(
                  raw_texts=[raw_text[doc_idx]],
                  subseqs=[doc_subseqs],
                  labels=[doc_labels],
                  probs=[prob_dicts],
                  none_value=self.config.pad_token,
                  subtoken_predictions=self.config.subtoken_predictions,
                  bio_tagging=self.config.bio_tagging
                  or self.config.group_bio_tagging,
              )
              if per_token:
                  doc_annotations.append(
                      {
                          "tokens": _spacy_token_predictions(
                              raw_text=raw_text[doc_idx],
                              tokens=doc_subseqs,
                              probas=prob_dicts,
                              positions=doc_positions,
                          ),
                          "prediction": doc_annotations_sample[0],
                      }
                  )
              elif return_negative_confidence:
                  doc_annotations.append(
                      {
                          "prediction": doc_annotations_sample[0],
                          "negative_confidence": dict(
                              zip(
                                  classes,
                                  np.max(doc_level_probas, axis=0),
                              )
                          ),
                      }
                  )
              elif self.config.predict_chunk_markers:
                  doc_annotations.append(
                      {
                          "prediction": doc_annotations_sample[0],
                          "chunks": chunk_spans,
                      }
                  )
              else:
                  doc_annotations.append(doc_annotations_sample[0])
      return doc_annotations
  
imports: import copy
  import os
  from collections import Counter, defaultdict
  import math
  from typing import Dict, List, Tuple, Union
  import tensorflow
  import numpy
  from finetune.base import BaseModel
  from finetune.encoding.target_encoders import SequenceLabelingEncoder, SequenceMultiLabelingEncoder
  from finetune.nn.target_blocks import sequence_labeler
  from finetune.nn.crf import sequence_decode
  from finetune.encoding.sequence_encoder import finetune_to_indico_sequence
  from finetune.encoding.input_encoder import get_spacy
  from finetune.input_pipeline import BasePipeline
  from finetune.util.metrics import sequences_overlap
  from finetune.encoding.input_encoder import tokenize_context
label_desc: Use image node_id 9 for calling the SequenceLabeler obj's underlying member method code with example usage: obj._predict_decode(zipped_data, predictions, per_token, return_negative_confidence) and returns: doc_annotations, label, label