PyTorch中CRF层

注:本篇文章假设你已经看过CRF(条件随机场)与Viterbi(维特比)算法原理详解
(侵权则删),但是对Pytorch的Tutorials中BiLSTM-CRF中关于CRF的代码还有些许的疑惑。

代码分析

假设有句子 “ 我爱饭 ”

  • 句子经过分词,得到 “我”、“爱”、“饭” 这个词(意思是句子的长度为3)
  • 标签集合={‘START’ 、'N 、 ‘V’、‘END’},START、END表示开始结束标签,N表示名词,V表示动词。

在上述前提下执行一遍代码。

一、train代码

PyTorch中CRF层_第1张图片
loss的计算方法为neg_log_likelihood(),我们跳转到该方法。

二、neg_log_likelihood()

PyTorch中CRF层_第2张图片

  1. 第一行代码:在输入句子 “我爱饭” 的情况下,经过_get_lstm_features()方法可以得到一个(3*4)的tensor,分别表示“我”、“爱”、“饭” 对于{START,N,V,END}标签的可能性。
    如feats[‘爱’][N]=0.2,表示词语 ‘爱’ 的标签是N的分数为0.2,然后将feats传给_forward_alg,接下来我们看farward_alg是如何计算所有路径的分数的。
    PyTorch中CRF层_第3张图片

三、 _forward_alg()

PyTorch中CRF层_第4张图片
PyTorch中CRF层_第5张图片

首先看一下CRF求解所有路径分数之和的动态规划的算法

  • score [ x ] [ y ] :句子从起始位置到位置 x ,且位置x是标签 y 的分数。
    如score [“爱”][N]就是说句子 “我爱” 且“爱”是标签N的所有路径的分数和,这就包括了四条路径的分数,如下
    (START,N)(N,N)(V,N)(END,N)
  • emit [ x ] [ i ]:位置x是标签 i 的分数,emit [“”] [N],表示“”是标签N的分数
  • trans [ i ] [ y ]:从标签 i 到标签y 的分数,即当前标签为y而上一标签是i 的分数。
    如trans [N][START] = -10000,表示当前标签为START,而上一标签为N的分数为-10000,也就是说START上一个标签几乎不可能是N。
    回到代码,逐步说明:
  1. 第一层循环,for feat in feats:
    得到的feat是某个位置的所有标签的可能性。
    第一次进入该循环时,feat就是 “我” 对应的标签可能性,即feat=[0.1,0.5,0.3,0.1],表示 ‘我’ 是START、N、V、END的分数分别为0.1、0.5、0.3、0.1,分数越大,则对应标签的可能性越大。
  2. 第二层循环,for next_tag in feats
    第一次进入该循环时,该层的目的是得到 ‘我’ 是标签next_tag的所有分数,刚进入第二层循环时,next_tag是0,也就是START标签,表明我们在这次循环中求到的是“我” 是 START的分数。
  3. 回到代码,首先求的是“我” 是标签 START的分数。
  • forward_var 初始化为[ 0,-10000,-10000,-10000,-10000 ],因为我们的每个句子的开头有一个独立的START标签,所以句首 “我” 的上一个位置是START、N、V、END的分数分别为 0,-10000,-10000,-10000,相当于式子中的score [x-1] [ i ],i∈tagset。
  • emit_score得到的是"我"是标签START的分数,也就是式子中的emit[ “我” ] [ START ]
  • trans_score 得到的是其他标签转化为START的分数,也就是式子中的trans[ START ][ i ],i∈tagset
    PyTorch中CRF层_第6张图片

最后得到的next_tag_var 就是[a, b, c, d ],简单的理解可以是a+b+c+d就是当前路径的分数,但是代码中使用了log_sum_exp对[a, b, c, d]进行了处理。

你可能感兴趣的:(自然语言处理,pytorch)