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

在本节中,我们将探讨如何预测句子的标签序列。

1. 预测句子的标签序列

第1步:BiLSTM-CRF模型的emission score和transition score
假设句子xx包含3个字符:x=[w0,w1,w2]x=[w_0, w_1, w_2]。此外,假设我们已经获得了BiLSTM模型的emission score和CRF层的transition score:

l1l_1 l2l_2
w0w_0 w01w_{01} w02w_{02}
w1w_1 w11w_{11} w12w_{12}
w2w_2 w21w_{21} w22w_{22}

xijx_{ij}表示wiw_i被标记为ljl_j的得分。

l1l_1 l2l_2
l1l_1 t11t_{11} t12t_{12}
l2l_2 t21t_{21} t22t_{22}

tijt_{ij}表示标签ii转移到标签jj的分数

第2步:预测
如果您熟悉Viterbi算法,这部分对您来说很容易。如果你不太了解的话,请不要担心,我将逐步解释算法。对于一个句子,我们将按从左到右的方式进行预测,即:

w0w_0
w0w_0–>w1w_1
w0w_0–>w1w_1–>w2w_2

你将看到两个变量:obsobspreviouspreviouspreviousprevious存储前面步骤的最终结果。obsobs表示来自当前单元的信息。


首先,我们来看看w0w_0,即:

obs=[x01,x02]obs=[x_{01}, x_{02}]

previous=Noneprevious=None

对于第一个字符w0w_0w0w_0的最优标签很简单。例如,如果obs=[x01=0.2,x02=0.8]obs=[x_{01}=0.2, x_{02}=0.8],显然,w0w_0的最优标签是l2l_2,由于只有一个字符从而无标签到标签之间的transition,因此不用计算transition scores。


接着,对于w0w_0 --> w1w_1

obs=[x11,x12]obs=[x_{11, x_{12}}]

previous=[x01,x02]previous=[x_{01}, x_{02}]

1).扩展previousprevious为:

previous=(previous[1]previous[1]previous[0]previous[0])=(x02x02x01x01)previous=\left(^{previous[0] \quad previous[0]}_{previous[1] \quad previous[1]}\right)=\left(^{x_{01} \quad x_{01}}_{x_{02} \quad x_{02}}\right)

2).扩展obsobs为:

obs=(obs[0]obs[1]obs[0]obs[1])=(x11x12x11x12)obs=\left(^{obs[0] \quad obs[1]}_{obs[0] \quad obs[1]}\right)=\left(^{x_{11} \quad x_{12}}_{x_{11} \quad x_{12}}\right)

3).将previouspreviousobsobs和transition score进行求和:

scores=(x02x02x01x01)+(x11x12x11x12)+(t21t22t11t12)scores=\left(^{x_{01} \quad x_{01}}_{x_{02} \quad x_{02}}\right) + \left(^{x_{11} \quad x_{12}}_{x_{11} \quad x_{12}}\right) + \left(^{t_{11} \quad t_{12}}_{t_{21} \quad t_{22}}\right)

即:

scores=(x02+x11+t21x02+x12+t22x01+x11+t11x01+x12+t12)scores=\left(^{x_{01}+x_{11}+t_{11} \quad x_{01}+x_{12}+t_{12}}_{x_{02}+x_{11}+t{21} \quad x_{02}+x_{12}+t_{22}}\right)

当我们计算所有可能标签序列组合的总得分时,您可能想知道与前一部分没有有区别。接下来我们将看到其中的差异性。

更新previousprevious值:

previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[\max (scores[00], scores[10]),\max (scores[01],scores[11])]

假设,我们得到的score为:

scores=(x02+x11+t21x02+x12+t22x01+x11+t11x01+x12+t12)=(0.50.40.20.3)scores=\left(^{x_{01}+x_{11}+t_{11} \quad x_{01}+x_{12}+t_{12}}_{x_{02}+x_{11}+t{21} \quad x_{02}+x_{12}+t_{22}}\right)=\left( ^{0.2 \quad 0.3}_{0.5 \quad 0.4}\right)

previousprevious将更新为:

previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]=[0.5,0.4]previous=[\max (scores[00], scores[10]),\max (scores[01],scores[11])] = [0.5, 0.4]

previousprevious是什么意思?previousprevious列表存储当前字符对每个标签的最大得分。

1.1 案例

假设,在语料库中,我们总共有2个标签,label1(l1)label1(l_1)label2(l2)label2(l_2),这两个标签的索引分别为0和1。

previous[0]previous[0]是以第0个标签l1l_1结束的序列的最大得分,类似的previous[1]previous[1]是以l2l_2结束的序列的最大得分。在每次迭代过程中,我们仅仅保留每个标签对应的最优序列的信息(previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[\max(scores[00], scores[10]),\max( scores[01], scores[11])])。分数较少的序列信息将被丢弃。

回到我们的主要任务:

同时,我们还有两个变量来存储历史信息(分数和索引),即alpha0alpha_0alpha1alpha_1
每次迭代,我们都将最好的得分追加到alpha0alpha_0。为方便起见,每个标签的最高分都有下划线。

scores=(x02+x11+t21x02+x12+t22x01+x11+t11x01+x12+t12)=(0.50.40.20.3)scores=\left(^{x_{01}+x_{11}+t_{11} \quad x_{01}+x_{12}+t_{12}}_{\underline{x_{02}+x_{11}+t{21}} \quad \underline{x_{02}+x_{12}+t_{22}}}\right)=\left( ^{0.2 \quad 0.3}_{\underline{0.5} \quad \underline{0.4}}\right)

alpha0=[(scores[10],scores[11])]=[(0.5,0.4)]alpha_0=[(scores[10],scores[11])]=[(0.5,0.4)]

另外,相应的列的索引被保存在alpha1alpha_1

alpha1=[(ColumnIndex(scores[10]),ColumnIndex(scores[11]))]=[(1,1)]alpha_1=[(ColumnIndex(scores[10]),ColumnIndex(scores[11]))]=[(1,1)]

其中,l1l_1的索引是0,l2l_2的索引是1,所以(1,1)=(l2,l2)(1, 1)=(l_2, l_2),这意味着对于当前的单元wiw_i和标签l(i)l^(i)
(1,1)=(l2,l2)(1, 1)=(l_2, l_2)=(当序列是l(i1)=l2>l(i)=l1\underline{l^{(i-1)}=l_2} -> \underline{l^{(i)}=l_1}时我们可以得到最大得分为0.5, 当序列是l(i1)=l2>l(i)=l2\underline{l^{(i-1)}=l_2} -> \underline{l^{(i)}=l_2}时我们可以得到最大得分为0.4)

l(i1)l^{(i-1)}是前一个字符wi1w_{i-1}对应的标签


最后,我们计算w0w_0 --> w1w_1 --> w2w_2:

obs=[x21,x22]obs=[x_{21}, x_{22}]

previous=[0.5,0.4]previous=[0.5, 0.4]

1).扩展previousprevious为:

previous=(previous[1]previous[1]previous[0]previous[0])=(0.40.40.50.5)previous=\left(^{previous[0] \quad previous[0]}_{previous[1] \quad previous[1]}\right)=\left(^{0.5 \quad 0.5}_{0.4 \quad 0.4}\right)

2).扩展obsobs为:

obs=(obs[0]obs[1]obs[0]obs[1])=(x21x22x21x22)obs=\left(^{obs[0] \quad obs[1]}_{obs[0] \quad obs[1]}\right)=\left(^{x_{21} \quad x_{22}}_{x_{21} \quad x_{22}}\right)

3).对previouspreviousobsobs和transition score进行求和:

scores=(0.40.40.50.5)+(x21x22x21x22)+(t21t22t11t12)scores=\left(^{0.5 \quad 0.5}_{0.4 \quad 0.4}\right) +\left(^{x_{21} \quad x_{22}}_{x_{21} \quad x_{22}}\right)+ \left(^{t_{11} \quad t_{12}}_{t_{21} \quad t_{22}}\right)

即:

scores=(0.4+x21+t210.4+x22+t220.5+x21+t110.5+x22+t12)scores=\left(^{0.5+x_{21}+t_{11} \quad 0.5+x_{22}+t_{12}}_{0.4+x_{21}+t{21} \quad 0.4+x_{22}+t_{22}}\right)

更新previousprevious为:

previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[\max (scores[00], scores[10]),\max (scores[01],scores[11])]

比如,我们得到的scores为:

scores=(0.80.70.60.9)scores=\left( ^{0.6 \quad \underline{0.9}}_{\underline{0.8} \quad 0.7}\right)

因此,previousprevious将更新为:

previous=[0.8,0.9]previous=[0.8, 0.9]

实际上,previousp[0]previousp[0]previous[1]previous[1]之间的较大的一个是最好的预测结果的得分。与此同时,每个标签的最大得分和索引将被添加到alpha0alpha_0alpha1alpha_1中:

alpha0=[(0.5,0.4),(scores[10],scores[01])]alpha_0=[(0.5,0.4),\underline{(scores[10],scores[01])}]

   =[(0.5,0.4),(0.8,0.9)]   =[(0.5,0.4),\underline{(0.8,0.9)}]

alpha1=[(1,1),(1,0)]alpha_1=[(1,1),\underline{(1,0)}]


第3步:找出得分最高的最佳序列
在该步骤中,我们将根据previousp[0]previousp[0]previous[1]previous[1]找到最高的得分。我们将从右到左的方式反推最优序列,即最后一个单元反推到第一个单元。


w1w_1 --> w2w_2
首先,检查alpha0alpha_0alpha1alpha_1最后一个元素:(0.8, 0.9)和(1, 0)。0.9是最高分数,其对应的位置是1,因此对应的标签是l2l_2。继续从alpha1alpha_1中对应位置获得w1w_1对应的标签索引, 即(1, 0)[1]=0。索引0表示w1w_1对应的标签是l1l_1。因此我们可以得到w1>w2w_1 -> w_2的最佳序列是l1>l2l_1 -> l_2

w0w_0 --> w1w_1

接着,我们继续向前移动并获得alpha1alpha_1的上一个元素:(1, 1)。从上面可知w1w_1的标签是l1l_1(标签对应的索引为0),因此我们可以得到w0w_0对应的标签索引为(1,1)[0]=1。所以我们可以得到w0>w1w_0 -> w_1的最佳序列是l2>l1l_2 -> l_1

最终可以得到w0>w1>w2w_0 -> w_1 -> w_2的最佳标签序列是l2>l1>l2l_2 -> l_1 -> l_2

参考

[1] Lample, G., Ballesteros, M., Subramanian, S., Kawakami, K. and Dyer, C., 2016. Neural architectures for named entity recognition. arXiv preprint arXiv:1603.01360.

https://arxiv.org/abs/1603.01360