class_docstr: 条件随机场。提供 :meth:`forward` 以及 :meth:`viterbi_decode` 两个方法，分别用于 **训练** 与 **inference** 。
  
  :param num_tags: 标签的数量
  :param include_start_end_trans: 是否考虑各个 tag 作为开始以及结尾的分数。
  :param allowed_transitions: 内部的 ``Tuple[from_tag_id(int), to_tag_id(int)]`` 视为允许发生的跃迁，其他没
      有包含的跃迁认为是禁止跃迁，可以通过 :func:`allowed_transitions` 函数得到；如果为 ``None`` ，则所有跃迁均为合法。
class_docstr_tok: ["\u6761\u4ef6\u968f\u673a\u573a\u3002\u63d0\u4f9b",":","meth",":","`","forward","`","\u4ee5\u53ca",":","meth",":","`","viterbi_decode","`","\u4e24\u4e2a\u65b9\u6cd5\uff0c\u5206\u522b\u7528\u4e8e","*","*","\u8bad\u7ec3","*","*","\u4e0e","*","*","inference","*","*","\u3002",":","param","num_tags",":","\u6807\u7b7e\u7684\u6570\u91cf",":","param","include_start_end_trans",":","\u662f\u5426\u8003\u8651\u5404\u4e2a","tag","\u4f5c\u4e3a\u5f00\u59cb\u4ee5\u53ca\u7ed3\u5c3e\u7684\u5206\u6570\u3002",":","param","allowed_transitions",":","\u5185\u90e8\u7684","``","Tuple","[","from_tag_id","(","int",")",",","to_tag_id","(","int",")","]","``","\u89c6\u4e3a\u5141\u8bb8\u53d1\u751f\u7684\u8dc3\u8fc1\uff0c\u5176\u4ed6\u6ca1","\u6709\u5305\u542b\u7684\u8dc3\u8fc1\u8ba4\u4e3a\u662f\u7981\u6b62\u8dc3\u8fc1\uff0c\u53ef\u4ee5\u901a\u8fc7",":","func",":","`","allowed_transitions","`","\u51fd\u6570\u5f97\u5230\uff1b\u5982\u679c\u4e3a","``","None","``","\uff0c\u5219\u6240\u6709\u8dc3\u8fc1\u5747\u4e3a\u5408\u6cd5\u3002"]
docstr: 给定一个 **特征矩阵** 以及 **转移分数矩阵** ，计算出最佳的路径以及对应的分数
  
  :param logits: 特征矩阵，形状为 ``[batch_size, max_len, num_tags]``
  :param mask: 标签矩阵，形状为 ``[batch_size, max_len]`` ，为 **0** 的位置认为是 padding。如果为 ``None`` ，则认为没有 padding。
  :param unpad: 是否将结果删去 padding：
  
          - 为 ``False`` 时，返回的是 ``[batch_size, max_len]`` 的张量
          - 为 ``True`` 时，返回的是 :class:`List` [:class:`List` [ :class:`int` ]], 内部的 :class:`List` [:class:`int` ] 为每个 
            sequence 的 label ，已经除去 pad 部分，即每个 :class:`List` [ :class:`int` ] 的长度是这个 sample 的有效长度。
  :return:  (paths, scores)。
  
          - ``paths`` -- 解码后的路径, 其值参照 ``unpad`` 参数.
          - ``scores`` -- :class:`torch.FloatTensor` ，形状为 ``[batch_size,]`` ，对应每个最优路径的分数。
docstr_tok: ["\u7ed9\u5b9a\u4e00\u4e2a","*","*","\u7279\u5f81\u77e9\u9635","*","*","\u4ee5\u53ca","*","*","\u8f6c\u79fb\u5206\u6570\u77e9\u9635","*","*","\uff0c\u8ba1\u7b97\u51fa\u6700\u4f73\u7684\u8def\u5f84\u4ee5\u53ca\u5bf9\u5e94\u7684\u5206\u6570",":","param","logits",":","\u7279\u5f81\u77e9\u9635\uff0c\u5f62\u72b6\u4e3a","``","[","batch_size",",","max_len",",","num_tags","]","``",":","param","mask",":","\u6807\u7b7e\u77e9\u9635\uff0c\u5f62\u72b6\u4e3a","``","[","batch_size",",","max_len","]","``","\uff0c\u4e3a","*","*","0","*","*","\u7684\u4f4d\u7f6e\u8ba4\u4e3a\u662f","padding\u3002\u5982\u679c\u4e3a","``","None","``","\uff0c\u5219\u8ba4\u4e3a\u6ca1\u6709","padding\u3002",":","param","unpad",":","\u662f\u5426\u5c06\u7ed3\u679c\u5220\u53bb","padding\uff1a","-","\u4e3a","``","False","``","\u65f6\uff0c\u8fd4\u56de\u7684\u662f","``","[","batch_size",",","max_len","]","``","\u7684\u5f20\u91cf","-","\u4e3a","``","True","``","\u65f6\uff0c\u8fd4\u56de\u7684\u662f",":","class",":","`","List","`","[",":","class",":","`","List","`","[",":","class",":","`","int","`","]","]",",","\u5185\u90e8\u7684",":","class",":","`","List","`","[",":","class",":","`","int","`","]","\u4e3a\u6bcf\u4e2a","sequence","\u7684","label","\uff0c\u5df2\u7ecf\u9664\u53bb","pad","\u90e8\u5206\uff0c\u5373\u6bcf\u4e2a",":","class",":","`","List","`","[",":","class",":","`","int","`","]","\u7684\u957f\u5ea6\u662f\u8fd9\u4e2a","sample","\u7684\u6709\u6548\u957f\u5ea6\u3002",":","return",":","(","paths",",","scores",")","\u3002","-","``","paths","``","--","\u89e3\u7801\u540e\u7684\u8def\u5f84",",","\u5176\u503c\u53c2\u7167","``","unpad","``","\u53c2\u6570",".","-","``","scores","``","--",":","class",":","`","torch.FloatTensor","`","\uff0c\u5f62\u72b6\u4e3a","``","[","batch_size",",","]","``","\uff0c\u5bf9\u5e94\u6bcf\u4e2a\u6700\u4f18\u8def\u5f84\u7684\u5206\u6570\u3002"]
code: def viterbi_decode(
      self,
      logits: "torch.FloatTensor",
      mask: "torch.ByteTensor",
      unpad=False,
  ):
      r"""给定一个 **特征矩阵** 以及 **转移分数矩阵** ，计算出最佳的路径以及对应的分数
  
      :param logits: 特征矩阵，形状为 ``[batch_size, max_len, num_tags]``
      :param mask: 标签矩阵，形状为 ``[batch_size, max_len]`` ，为 **0** 的位置认为是 padding。如果为 ``None`` ，则认为没有 padding。
      :param unpad: 是否将结果删去 padding：
  
              - 为 ``False`` 时，返回的是 ``[batch_size, max_len]`` 的张量
              - 为 ``True`` 时，返回的是 :class:`List` [:class:`List` [ :class:`int` ]], 内部的 :class:`List` [:class:`int` ] 为每个
                sequence 的 label ，已经除去 pad 部分，即每个 :class:`List` [ :class:`int` ] 的长度是这个 sample 的有效长度。
      :return:  (paths, scores)。
  
              - ``paths`` -- 解码后的路径, 其值参照 ``unpad`` 参数.
              - ``scores`` -- :class:`torch.FloatTensor` ，形状为 ``[batch_size,]`` ，对应每个最优路径的分数。
  
      """
      batch_size, max_len, n_tags = logits.size()
      seq_len = mask.long().sum(1)
      logits = logits.transpose(0, 1).data  # L, B, H
      mask = mask.transpose(0, 1).data.eq(True)  # L, B
      flip_mask = mask.eq(False)
  
      # dp
      vpath = logits.new_zeros(
          (max_len, batch_size, n_tags), dtype=torch.long
      )
      vscore = logits[0]  # bsz x n_tags
      transitions = self._constrain.data.clone()
      transitions[:n_tags, :n_tags] += self.trans_m.data
      if self.include_start_end_trans:
          transitions[n_tags, :n_tags] += self.start_scores.data
          transitions[:n_tags, n_tags + 1] += self.end_scores.data
  
      vscore += transitions[n_tags, :n_tags]
  
      trans_score = (
          transitions[:n_tags, :n_tags].view(1, n_tags, n_tags).data
      )
      end_trans_score = (
          transitions[:n_tags, n_tags + 1]
          .view(1, 1, n_tags)
          .repeat(batch_size, 1, 1)
      )  # bsz, 1, n_tags
  
      # 针对长度为1的句子
      vscore += (
          transitions[:n_tags, n_tags + 1]
          .view(1, n_tags)
          .repeat(batch_size, 1)
          .masked_fill(seq_len.ne(1).view(-1, 1), 0)
      )
      for i in range(1, max_len):
          prev_score = vscore.view(batch_size, n_tags, 1)
          cur_score = (
              logits[i].view(batch_size, 1, n_tags) + trans_score
          )
          score = prev_score + cur_score.masked_fill(
              flip_mask[i].view(batch_size, 1, 1), 0
          )  # bsz x n_tag x n_tag
          # 需要考虑当前位置是该序列的最后一个
          score += end_trans_score.masked_fill(
              seq_len.ne(i + 1).view(-1, 1, 1), 0
          )
  
          best_score, best_dst = score.max(1)
          vpath[i] = best_dst
          # 由于最终是通过last_tags回溯，需要保持每个位置的vscore情况
          vscore = best_score.masked_fill(
              flip_mask[i].view(batch_size, 1), 0
          ) + vscore.masked_fill(mask[i].view(batch_size, 1), 0)
  
      # backtrace
      batch_idx = torch.arange(
          batch_size, dtype=torch.long, device=logits.device
      )
      seq_idx = torch.arange(
          max_len, dtype=torch.long, device=logits.device
      )
      lens = seq_len - 1
      # idxes [L, B], batched idx from seq_len-1 to 0
      idxes = (lens.view(1, -1) - seq_idx.view(-1, 1)) % max_len
  
      ans = logits.new_empty((max_len, batch_size), dtype=torch.long)
      ans_score, last_tags = vscore.max(1)
      ans[idxes[0], batch_idx] = last_tags
      for i in range(max_len - 1):
          last_tags = vpath[idxes[i], batch_idx, last_tags]
          ans[idxes[i + 1], batch_idx] = last_tags
      ans = ans.transpose(0, 1)
      if unpad:
          paths = []
          for idx, max_len in enumerate(lens):
              paths.append(ans[idx, : max_len + 1].tolist())
      else:
          paths = ans
      return paths, ans_score
  
file_path: fastNLP/fastNLP/modules/torch/decoder/crf.py
imports: from typing import Union, List, Tuple
  import torch
  from torch import nn
  from ....core.metrics.span_f1_pre_rec_metric import _get_encoding_type_from_tag_vocab, _check_tag_vocab_and_encoding_type
  from ....core.vocabulary import Vocabulary
label_desc: Use image node_id 5 for calling the ConditionalRandomField obj's underlying member method code with example usage: obj.viterbi_decode(logits, mask, unpad) and returns: paths,  ans_score