Bootstrap

序列标注 | (2) 用命名实体识别(NER)解释CRF (BiLSTM+CRF)

原文地址

看了许多的CRF的介绍和讲解,这个感觉是最清楚的,结合实际的应用场景,让你了解CRF的用处和用法。

本篇文章包括:

  • **介绍:**在BiLSTM顶层上使用CRF层用于命名实体识别任务的总体思想
  • 详细的例子: 一个例子,解释CRF层是如何逐步工作的
  • Chainer实现: CRF层的Chainer实现

预备知识

你需要知道的惟一的事情是什么是命名实体识别(实体抽取)。如果你不知道神经网络,CRF或任何其他相关知识,请不要担心。我会尽可能直观地解释一切。

1. 介绍

对于命名实体识别任务,基于神经网络的方法非常普遍。例如,这篇文章:https://arxiv.org/abs/1603.01360提出了一个使用词和字嵌入的BiLSTM-CRF命名实体识别模型。我将以本文中的模型为例来解释CRF层是如何工作的。

如果你不知道BiLSTM和CRF的细节,请记住它们是命名实体识别模型中的两个不同的层

1.1 序言

我们假设,我们有一个数据集,其中有两个实体类型(实际可以有多种实体类型,本文以两个为例),Person和Organization。但是,事实上,在我们的数据集中,我们有5个实体标签(标签集):

  • B-Person (Person实体开始)
  • I-Person(Person实体中间或结束)
  • B-Organization(Organization实体开始)
  • I-Organization(Organization实体的中间或结束)
  • O(非命名实体)

此外,x是一个包含5个单词的句子,w0,w1,w2,w3,w4。更重要的是,在句子x中,[w0,w1]是一个Person实体,[w3]是一个Organization实体,其他都是“O”。

1.2 BiLSTM-CRF模型

我将对这个模型做一个简单的介绍。
如下图所示:

  • 首先,将句子x中的每个单词表示为一个向量,其中包括单词的嵌入和字符的嵌入。字符嵌入是随机初始化的。词嵌入通常是从一个预先训练的词嵌入文件导入的。所有的嵌入将在训练过程中进行微调。
  • 第二,BiLSTM-CRF模型的输入是这些嵌入,输出是句子x中的单词的预测标签。
    在这里插入图片描述
    虽然不需要知道BiLSTM层的细节,但是为了更容易的理解CRF层,我们需要知道BiLSTM层输出的意义是什么。
    在这里插入图片描述
    上图说明BiLSTM层的输出是每个标签的分数。例如,对于w0, BiLSTM节点的输出为1.5 (B-Person)、0.9 (I-Person)、0.1 (B-Organization)、0.08 (I-Organization)和0.05 (O),这些分数(未经过softmax)将作为CRF层的输入。(命名实体识别是一种序列标注任务,实际上就是为序列中的每个元素(单词)打标签(基于标签集合的多分类))。

然后,将BiLSTM层预测的所有分数输入CRF层。在CRF层中,选择预测得分最高的标签序列作为最佳答案。

1.3 如果没有CRF层会怎么样

你可能已经发现,即使没有CRF层,也就是说,我们可以训练一个BiLSTM命名实体识别模型,如下图所示。
在这里插入图片描述
因为每个单词的BiLSTM的输出是标签分数。我们可以选择每个单词得分最高的标签。

例如,对于w0,标签“B-Person”得分最高(1.5),因此我们可以选择“B-Person”作为其最佳预测标签。同样,我们可以为w1选择“I-Person”,为w2选择“O”,为w3选择“B-Organization”,为w4选择“O”。

虽然在这个例子中我们可以得到正确的句子x的标签,但是并不总是这样。再试一下下面图片中的例子。
在这里插入图片描述
显然,这次的输出是无效的,“I-Organization I-Person”和“B-Organization I-Person”。

1.4 CRF层可以从训练数据中学到约束

CRF层可以向最终的预测标签添加一些约束,以确保它们是有效的。这些约束可以由CRF层在训练过程中从训练数据集自动学习。

约束条件可以是:

  • 句子中第一个单词的标签应该以“B-xx”或“O”开头,而不是“I-xx”
  • “B-label1 I-label2 I-label3 I-…”,在这个模式中,label1、label2、label3…应该是相同的命名实体标签。例如,“B-Person I-Person”是有效的,但是“B-Person I-Organization”是无效的。
  • “O I-label”无效。一个命名实体的第一个标签应该以“B-xx”而不是“I-xx”开头,换句话说,有效的模式应该是“O B-label”

有了这些有用的约束,无效预测标签序列的数量将显著减少。

总结:
仅使用BiLSTM无法学习到上述约束,会存在很多无效预测标签,即只使用BiLSTM,序列中各元素的预测标签之间是相互独立的,没有依赖关系,但实际中并非如此,因此后面要接CRF层。下一小节,我们将分析CRF损失函数,以解释CRF层如何或为什么能够从训练数据集中学习上述约束。

2. CRF层

第二部分,给大家推导一下CRF的损失函数如何计算,思路很清楚。

在CRF层的损失函数中,我们有两种类型的分数。这两个分数是CRF层的关键概念

2.1 Emission得分

第一个是emission分数。这些emission分数来自BiLSTM层。例如,如图2.1所示,w0标记为B-Person的分数为1.5。
在这里插入图片描述
为了方便起见,我们将给每个标签一个索引号,如下表所示。
在这里插入图片描述
我们用 x i y j x_{iy_j} xiyj来表示emission分数。i是word的索引, y j y_j yj是label的索引。如图2.1所示, x i = 1 , y j = 2 = x w 1 , B − O r g a n i z a t i o n = 0.1 x_{i=1,y_j=2}=x_{w_1,B-Organization}=0.1 xi=1,yj=2=xw1,BOrganization=0.1,即单词w1作为B-Organization的得分为0.1。

2.2 Transition得分

我们使用 t y i , y j t_{y_i,y_j} tyi,yj来表示transition分数。例如, t B − P e r s o n , I − P e r s o n = 0.9 t_{B-Person,I-Person}=0.9 tBPerson,IPerson=0.9表示标签的transition,B-Person -> I-Person得分为0.9。因此,我们有一个transition得分矩阵,它存储了所有标签之间的所有得分。

为了使transition评分矩阵更健壮,我们将添加另外两个标签,START和END。START是指一个句子的开头,而不是第一个单词。END表示句子的结尾。

下面是一个transition得分矩阵的例子,包括额外添加的START和END标签。
在这里插入图片描述
如上表所示,我们可以发现transition矩阵已经学习了一些有用的约束。

  • 句子中第一个单词的标签应该以“B-”或“O”开头,而不是“I-”开头**(从“START”到“I- person或I- organization”的transition分数非常低)**
  • “B-label1 I-label2 I-label3 I-…”,在这个模式中,label1、label2、label3…应该是相同的命名实体标签。例如,“B-Person I-Person”是有效的,但是“B-Person I-Organization”是无效的。(例如,从“B-Organization”到“I-Person”的分数只有0.0003,比其他分数低很多)
  • “O I-label”无效。一个被命名实体的第一个标签应该以“B-”而不是“I-”开头,换句话说,有效的模式应该是“O B-label”(同样, t O , I − P e r s o n t_{O,I-Person} tO,IPerson的分数非常小)

你可能想问一个关于矩阵的问题。在哪里或如何得到transition矩阵?

实际上,该矩阵是BiLSTM-CRF模型的一个参数。在训练模型之前,可以随机初始化矩阵中的所有transition分数。所有的随机分数将在你的训练过程中自动更新。换句话说,CRF层可以自己学习这些约束。我们不需要手动构建矩阵。随着训练迭代次数的增加,分数会逐渐趋于合理。

2.3 CRF损失函数

CRF损失函数由真实路径得分和所有可能路径的总得分组成。在所有可能的路径中,真实路径的得分应该是最高的。

例如,如果我们的数据集中有如下表所示的这些标签:
在这里插入图片描述
我们还是有一个5个单词的句子。可能的路径是:

    1. START B-Person B-Person B-Person B-Person B-Person END
    1. START B-Person I-Person B-Person B-Person B-Person END
  • 10) START B-Person I-Person O B-Organization O END
  • N) O O O O O O O

假设每条可能的路径都有一个分数 P i P_i Pi,并且总共有N条可能的路径,所有路径的总分数是: P t o t a l = P 1 + P 2 + . . . + P N = e S 1 + e S 2 + . . . + e S N P_{total}=P_1+P_2+...+P_N=e^{S_1}+e^{S_2}+...+e^{S_N} Ptotal=P1+P2+...+PN=eS1+eS2+...+eSN.(在第2.4节中,我们将解释如何计算 S i S_i Si,你也可以把它当作这条路径的分数。)

如果我们说第10条路径是真正的路径,换句话说,第10条路径是我们的训练数据集提供的黄金标准标签。在所有可能的路径中,得分 P 10 P_{10} P10应该是百分比最大的。

在训练过程中,我们的BiLSTM-CRF模型的参数值将会一次又一次的更新,以保持增加真实路径的分数百分比。
在这里插入图片描述
现在的问题是:1)如何定义一个路径的分数?2)如何计算所有可能路径的总分?3)当我们计算总分时,我们需要列出所有可能的路径吗?(这个问题的答案是否定的。)

在下面的小节中,我们将看到如何解决这些问题。

2.4 实际路径得分

在2.3节中,我们假设每条可能的路径都有一个得分 P i P_i Pi,并且有N条可能的路径,所有路径的总得分为 P t o t a l = P 1 + P 2 + . . . + P N = e S 1 + e S 2 + . . . + e S N P_{total}=P_1+P_2+...+P_N=e^{S_1}+e^{S_2}+...+e^{S_N} Ptotal=P1+P2+...+PN=eS1+eS2+...+eSN.

显然,在所有可能的路径中,一定有一条是真实路径。对于这个例子来说,第1.2节中句子的实际路径是**“START B-Person I-Person O B-Organization O END”**。其他的是不正确的,如“START B-Person B-Organization O I-Person I-Person B-Person”。 e S i e^{S_i} eSi是第i条路径的得分。

在训练过程中,CRF损失函数只需要两个分数:真实路径的分数和所有可能路径的总分数。所有可能路径的分数中,真实路径分数所占的比例会逐渐增加。

计算实际路径分数 e S i e^{S_i} eSi非常简单。

这里我们主要关注的是 S i S_i Si的计算。

选取真实路径,“START B-Person I-Person O B-Organization O END”,我们以前用过,例如:

  • 我们有一个5个单词的句子,w1,w2,w3,w4,w5
  • 我们增加了两个额外的单词来表示一个句子的开始和结束,w0,w6
  • S i S_i Si由两部分组成: S i = E m i s s i o n S c o r e + T r a n s i t i o n S c o r e S_i = EmissionScore + TransitionScore Si=EmissionScore+TransitionScore

Emission得分:
在这里插入图片描述

  • x i n d e x , l a b e l x_{index,label} xindex,label是第index个单词标记为label的分数
  • 这些得分 x 1 , B − P e r s o n x 2 , I − P e r s o n x 3 , O x 4 , B − O r g a n i z a t i o n x 5 , O x_{1,B-Person}x_{2,I-Person}x_{3,O}x_{4,B-Organization}x_{5,O} x1,BPersonx2,IPersonx3,Ox4,BOrganizationx5,O来自之前的BiLSTM输出。
  • 对于 x 0 , S T A R T , x 6 , E N D x_{0,START},x_{6,END} x0,START,x6,END,我们可以把它们设为0。

Transition得分:
在这里插入图片描述

  • t_{label_1->label_2}是从 label1到label2的transition分数
  • 这些分数来自CRF层。换句话说,这些transition分数实际上是CRF层的参数。

综上所述,现在我们可以计算出 S i S_i Si以及路径得分 e S i e^{S_i} eSi

下一步是如何计算所有可能路径的总分?

2.5 所有可能的路径的得分

如何逐步计算一个句子的所有可能的路径的总分。

在上一节中,我们学习了如何计算一个路径(即 e S i e^{S_i} eSi)的标签路径得分。到目前为止,我们还有一个需要解决的问题,就是如何得到所有路径的总分( P t o t a l = P 1 + P 2 + . . . + P N = e S 1 + e S 2 + . . . + e S N P_{total}=P_1+P_2+...+P_N=e^{S_1}+e^{S_2}+...+e^{S_N} Ptotal=P1+P2+...+PN=eS1+eS2+...+eSN)。

衡量总分最简单的方法是:列举所有可能的路径并将它们的分数相加。是的,你可以用这种方法计算总分。然而,这是非常低效的。训练的时间将是难以忍受的。

在探索以下内容之前,我建议你先准备一张白纸和一支笔,并按照示例中列出的步骤进行操作。我相信这将有助于你更好地理解算法的细节。此外,你应该知道如何用你喜欢的编程语言实现它。

步骤1: 回想一下CRF损失函数

在section 2.3中,我们将CRF损失函数定义为:
在这里插入图片描述
现在我们把loss函数变成log loss函数:
在这里插入图片描述
因为当我们训练一个模型时,通常我们的目标是最小化我们的损失函数,我们加上一个负号:
log ⁡ L o s s F u n c t i o n = − log ⁡ P R e a l P a t h P 1 + P 2 + . . . + P N = − log ⁡ e S R e a l P a t h e S 1 + e S 2 + . . . + e S N = − ( log ⁡ ( e S R e a l P a t h ) − log ⁡ ( e S 1 + e S 2 + . . . + e S N ) ) = − ( S R e a l P a t h − log ⁡ ( e S 1 + e S 2 + . . . + e S N ) ) \log LossFunction = -\log \frac{P_{RealPath}}{P_1+P_2+...+P_N} = -\log \frac{e^{S_{RealPath}}}{e^{S_1}+e^{S_2}+...+e^{S_N}}\\ =-(\log(e^{S_{RealPath}})-\log(e^{S_1}+e^{S_2}+...+e^{S_N}))\\=-(S_{RealPath}-\log(e^{S_1}+e^{S_2}+...+e^{S_N})) logLossFunction=logP1+P2+...+PNPRealPath=logeS1+eS2+...+eSNeSRealPath=(log(eSRealPath)log(eS1+eS2+...+eSN))=(SRealPathlog(eS1+eS2+...+eSN))
在上一节中,我们已经知道如何计算实际路径得分,现在我们需要找到一个有效的解决方案来计算 log ⁡ ( e S 1 + . . . e S N ) \log (e^{S_1}+...e^{S_N}) log(eS1+...eSN)

步骤2: 回忆一下Emission和Transition得分

为了简化,我们假设我们从这个句子中训练我们的模型,它的长度只有3:
在这里插入图片描述
此外,在我们的数据集中,我们有两个标签:
在这里插入图片描述
我们还有Bi-LSTM层输出的Emission分数:
在这里插入图片描述
x i j x_{ij} xij表示 w i w_i wi被标记为 l j l_j lj的得分。

此外,Transition分数来自CRF层:
t i , j t_{i,j} ti,j是从标签i到标签j的transition得分。

步骤3: 开始战斗(准备好纸笔)

**记住:**我们的目标是: log ⁡ ( e S 1 + . . . e S N ) \log (e^{S_1}+...e^{S_N}) log(eS1+...eSN)

这个过程就是分数的累加。其思想与动态规划相似(如果你不知道什么是动态编程,也可以继续阅读本文)。我将逐步解释这个例子。但我强烈建议你学习动态规划算法。简而言之,计算w0的所有可能路径的总分。然后,我们用总分来计算w0→w1。最后,我们使用最新的总分来计算w0→w1→w2。我们需要的是最后的总分。

在接下来的步骤中,你将看到两个变量:obs和previous。previous存储前面步骤的最终结果。obs表示当前单词的信息。
在这里插入图片描述
如果我们的句子只有一个单词 w 0 w_0 w0,我们就没有前面步骤的结果,因此previous是None。另外,我们只能观察到第一个词 o b s = [ x 01 , x 02 ] obs=[x_{01},x_{02}] obs=[x01,x02] x 01 x_{01} x01 x 02 x_{02} x02是上述的Emission分数。

你可能会想, w 0 w_0 w0的所有可能路径的总分是多少?答案很简单:
在这里插入图片描述

在这里插入图片描述

  1. 把previous展开成:
    在这里插入图片描述
  2. 把obs展开成:
    在这里插入图片描述
    你可能想知道,为什么我们需要把previous和obs扩展成矩阵。因为矩阵可以提高计算的效率。在下面的过程中,你将很快看到这一点。
  3. 对 previous, obs以及transition得分求和:
    在这里插入图片描述
    然后:
    在这里插入图片描述
    为下一个迭代修改previous的值:
    在这里插入图片描述
    实际上,第二次迭代已经完成。如果有人想知道如何计算所有可能路径的总分(label1→label1, label1→label2, label2→label1, label2→label2),从w0到w1,可以做如下计算。

我们使用新的previous中的元素:
T o t a l S c o r e ( w 0 − > w 1 ) = log ⁡ ( e p r e v i o u s [ 0 ] + e p r e v i o u s [ 1 ] ) = log ⁡ ( e log ⁡ ( e x 01 + x 11 + t 11 + e x 02 + x 11 + t 21 ) + e log ⁡ ( e x 01 + x 12 + t 12 + e x 02 + x 12 + t 22 ) ) = log ⁡ ( e x 01 + x 11 + t 11 + e x 02 + x 11 + t 21 + e x 01 + x 12 + t 12 + e x 02 + x 12 + t 22 ) TotalScore(w_0 -> w_1) = \log(e^{previous[0]}+e^{previous[1]}) \\=\log(e^{\log(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}})}+e^{\log(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}})})\\=\log(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}+e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}}) TotalScore(w0>w1)=log(eprevious[0]+eprevious[1])=log(elog(ex01+x11+t11+ex02+x11+t21)+elog(ex01+x12+t12+ex02+x12+t22))=log(ex01+x11+t11+ex02+x11+t21+ex01+x12+t12+ex02+x12+t22)
你发现了吗?这正是我们的目标: log ⁡ ( e S 1 + . . . e S N ) \log (e^{S_1}+...e^{S_N}) log(eS1+...eSN)

在这个等式中,我们可以看到:
在这里插入图片描述

在这里插入图片描述
如果你读到这里了,你已经快要读完了,实际上,在这个迭代里,我们做的事情是和上个迭代一样的。
在这里插入图片描述

  1. 把previous扩展成:
    在这里插入图片描述
  2. 把obs扩展成:
    在这里插入图片描述
  3. 把previous, obs和transition分数加起来:
    在这里插入图片描述
    在这里插入图片描述
    为下一个迭代计算 previous的值:
    在这里插入图片描述
    就像下一个迭代描述的一样,我们使用新的previous中的元素来计算total score:
    在这里插入图片描述
    我们达到了目标, log ⁡ ( e S 1 + . . . e S N ) \log (e^{S_1}+...e^{S_N}) log(eS1+...eSN),我们的toy句子有三个单词,label set有两个label,所以一共应该有 2 3 = 8 2^3=8 23=8种可能的label path。

2.6 为新句子推理标签

在前面的章节中,我们学习了BiLSTM-CRF模型的结构和CRF损失函数的细节。你可以通过各种开源框架(Keras、Chainer、TensorFlow、Pytorch等)实现自己的BiLSTM-CRF模型。最重要的事情之一是模型的反向传播是在这些框架上自动计算的,因此你不需要自己实现反向传播来训练你的模型(即计算梯度和更新参数)。此外,一些框架已经实现了CRF层,因此将CRF层与你自己的模型结合起来非常容易,只需添加一行代码即可。

在本节中,我们将探索如何在模型准备好时(训练完成)在测试期间推断句子的标签。

步骤1:BiLSTM-CRF模型的Emission和transition得分

假设,我们有一个包含三个单词的句子: x = [ w 0 , w 1 , w 2 ] x=[w_0,w_1,w_2] x=[w0,w1,w2]

此外,我们已经从BiLSTM模型得到了Emission分数,从下面的CRF层得到了transition分数:
在这里插入图片描述
x i j x_{ij} xij表示单词 w i w_i wi被标记为 l j l_j lj的得分。
在这里插入图片描述
t i j t_{ij} tij是从标签i转换成标签j的得分。

步骤2:开始推理

如果你熟悉Viterbi算法,那么这一部分对你来说很容易。但如果你不熟悉,请不要担心。与前一节类似,我将逐步解释该算法。我们将从句子的左到右进行推理算法,如下图所示:

  • w 0 w_0 w0
  • w 0 w_0 w0 -> w 1 w_1 w1
  • w 0 w_0 w0 -> w 1 w_1 w1 -> w 2 w_2 w2

你会看到两个变量:obs和previous。previous存储前面步骤的最终结果。obs表示当前单词的信息。

a l p h a 0 alpha_0 alpha0是历史最好得分, a l p h a 1 alpha_1 alpha1是历史对应的索引。这两个变量的细节将在它们出现时进行解释。请看下面的图片:你可以把这两个变量当作狗在探索森林时沿路留下的“记号”,这些“记号”可以帮助狗找到回家的路。
在这里插入图片描述

在这里插入图片描述
现在,我们观察到第一个单词,现在,对于是很明显的。
比如,如果 o b s = [ x 01 = 0.2 , x 02 = 0.8 ] obs=[x_{01}=0.2,x_{02}=0.8] obs=[x01=0.2,x02=0.8],很显然, w 0 w_0 w0的最佳的标签是 l 2 l_2 l2
因为只有一个单词,而且没有标签直接的转换,transition的得分没有用到。

在这里插入图片描述

  1. 把previous扩展成:
    在这里插入图片描述
  2. 把obs扩展成:
    在这里插入图片描述
  3. 把previous, obs和transition 分数都加起来:
    在这里插入图片描述
    你可能想知道,当我们计算所有路径的总分时,与上一节没有什么不同。请耐心和细心,你很快就会看到区别。

为下一次迭代更改previous的值:
在这里插入图片描述
比如,如果我们的得分是:
在这里插入图片描述
我们的下个迭代的previous是:
在这里插入图片描述
previous有什么含义吗? previous列表存储了每个当前的单词的标签的最大的得分。

[Example Start]

举个例子:

我们知道在我们的语料中,我们假设总共只有2个标签, l a b e l 1 ( l 1 ) label1(l_1) label1(l1) l a b e l 2 ( l 2 ) label2(l_2) label2(l2)。这两个标签的索引是0和1。

previous[0]是以第0个标签 l 1 l_1 l1为结尾的路径的最大得分,类似的previous[1]是以第1个标签 l 2 l_2 l2为结尾的路径的最大得分。**在每个迭代中,变量previous存储了以每个标签为结尾的路径的最大得分。**换句话说,在每个迭代中,我们只保留了每个标签的最佳路径的信息( p r e v i o u s = m a x ( s c o r e s [ 00 ] , s c o r e s [ 10 ] ) , m a x ( s c o r e s [ 01 ] , s c o r e s [ 11 ] ) previous=max(scores[00],scores[10]),max(scores[01],scores[11]) previous=max(scores[00],scores[10]),max(scores[01],scores[11]))。具有小得分的路径信息会被丢掉。

[Example End]

回到我们的主任务:

同时,我们还有两个变量用来存储历史信息(得分和索引), a l p h a 0 alpha_0 alpha0 a l p h a 1 alpha_1 alpha1

在这个迭代中,我们把最佳得分加上 a l p h a 0 alpha_0 alpha0,为了方便,每个标签的最大得分会加上下划线。
在这里插入图片描述
另外,对应的列的索引存在 a l p h a 1 alpha_1 alpha1里。
在这里插入图片描述
说明一下, l 1 l_1 l1的索引是0, l 2 l_2 l2的索引是1, 所以 ( 1 , 1 ) = ( l 2 , l 2 ) (1,1)=(l_2,l_2) (1,1)=(l2,l2)表示对于当前的单词 w i w_i wi和标签 l ( i ) l^{(i)} l(i),当路径是 l ( i − 1 ) = l 2 l^{(i-1)}=l_2 l(i1)=l2 -> l i = l 1 l^i=l_1 li=l1的时候,我们可以得到最大的得分是0.5,当路径是 l ( i − 1 ) = l 2 l^{(i-1)}=l_2 l(i1)=l2 -> l i = l 2 l^i=l_2 li=l2的时候,我们可以得到最大的得分是0.4。 l ( i − 1 ) l^{(i-1)} l(i1)是过去的单词 w i − 1 w_{i-1} wi1的标签。

在这里插入图片描述

  1. 把previous扩展成:
    在这里插入图片描述

  2. 把obs扩展成:

在这里插入图片描述

  1. 把previous, obs和transition 分数都加起来:
    在这里插入图片描述
    为下一次迭代更改previous的值:
    在这里插入图片描述
    这次迭代我们得到的分数是:
    在这里插入图片描述
    实际上,previous[0]和previous[1]中最大的那个就是预测的最佳路径。

同时,每个标签和索引的最大得分加到 a l p h a 0 alpha_0 alpha0上和 a l p h a 1 alpha_1 alpha1上。
在这里插入图片描述
步骤3:找到具有最高得分的最佳路径

这是最后一步!你就快完成了!在此步骤中,将使用 a l p h a 0 alpha_0 alpha0上和 a l p h a 1 alpha_1 alpha1来查找得分最高的路径。我们将从最后一个到第一个的元素检查这两个列表中。

w 1 w_1 w1 -> w 2 w_2 w2:

首先,检查 a l p h a 0 alpha_0 alpha0上和 a l p h a 1 alpha_1 alpha1的最后一个元素:(0.8,0.9)和(1,0)。0.9表示当( w 2 w_2 w2的)label为 l 2 l_2 l2时,我们可以得到最高的路径分数0.9。我们还知道 l 2 l_2 l2的索引是1,因此检查(1,0)[1]=0的值。索引“0”表示前一个标签为 l 1 l_1 l1( l 1 l_1 l1的索引为0),因此我们可以得到是 w 1 w_1 w1 -> w 2 w_2 w2的最佳路径是 l 1 l_1 l1 -> l 2 l_2 l2

w 0 w_0 w0 -> w 1 w_1 w1:

其次,我们继续向后移动并得到 a l p h a 1 alpha_1 alpha1:(1,1)的元素。从上一段我们知道w1的label是 l 1 l_1 l1(index是0),因此我们可以检查(1,1)[0]=1。因此,我们可以得到这部分的最佳路径 w 0 w_0 w0 -> w 1 w_1 w1: l 2 l_2 l2 -> l 1 l_1 l1

恭喜!我们这个例子中的最佳路径是 l 2 l_2 l2 -> l 1 l_1 l1 -> l 2 l_2 l2.

3. Chainer实现

详情链接
在本节中,我将解释代码的结构。此外,还将给出实现CRF损失层的一个重要技巧。最后,会公布Chainer(2.0版)实现的源代码。

;