2.6 预测标签

在之前的章节中,我们详细地介绍了BiLSTM-CRF模型和CRF损失函数的细节,大家可以采用开源工具(Keras, Chainer, TensorFlow等)完成自己的BiLSTM-CRF模型。模型搭建过程中,非常重要的是反向传播的实现,不要担心,这些框架在训练过程中可以自动的完成反向传播(即,计算梯度、更新模型参数)。而且,有一些框架已经完成的CRF层,此时,添加CRF层就只是一行代码的工作量了。

这节,我们将介绍,当我们的模型已经训练好时,如何预测一句话的标签。

Step1:BiLSTM-CRF的发射和转移得分
依然,假设我们有只有3个单词组成的一句话: x=[w0,w1,w2]\mathbf{x} = [w_0, w_1, w_2]

而且,我们已经从BiLSTM层获得了发射得分矩阵,从CRF层得到的转移得分矩阵,其示例如下表所示:

l1\mathbf{l_1} l2\mathbf{l_2}
w0\mathbf{w_0} x01x_{01} x02x_{02}
w1\mathbf{w_1} x11x_{11} x12x_{12}
w2\mathbf{w_2} x21x_{21} x22x_{22}

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

l1\mathbf{l_1} l2\mathbf{l_2}
l1\mathbf{l_1} t11t_{11} t12t_{12}
l2\mathbf{l_2} t21t_{21} t22t_{22}

tijt_{ij}从标签ii到标签jj的转移得分。

Step2:开始预测


如果你对维特比算法比较了解的话,这部分内容就很简单,如果不知道该算法,也不要担心,这里将一步一步地解释该算法,如下所示,我们将对这句话从左向右进行最终的标签预测:

  • w0w_0
  • w0w_0w1w_1
  • w0w_0w1w_1w2w_2

这里,会有两个变量obs 和 previous,previous表示前面所有步骤的结果,obs表示当前单词的信息。

alpha0\mathbf{alpha_0}记录最高历史得分,alpha1\mathbf{alpha_1} 对应着相应的索引,这两个变量的细节之后会慢慢讲解。现在,请看下图:当一条小狗前往森林时,会在沿途做一些“标记”,上述两个变量就可以看作这些“标记”,这些“标记”的作用就是帮助狗狗返回。

BiLSTM-CRF中CRF层解析-5

w0w_0:

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

开始,我们先观察单词w0w_0,目前给w0w_0标记的最好标签是显而易见的。
假如: obs=[x01=0.2,x02=0.8]obs = [x_{01}=0.2, x_{02}=0.8],则w0w_0的最好标签就是l2l_2
因为,当前只有一个单词,且没有标签之间的转移,因此没有转移得分。


w0w_0w1w_1:

obs=[x11,x12]obs = [x_{11}, x_{12}]
previous=[x01,x02]previous = [x_{01}, x_{02}]

1)将previous扩展为:
previous=(previous[0]previous[0]previous[1]previous[1])=(x01x01x02x02)previous=\left( \begin{matrix} previous[0] &previous[0] \\previous[1]&previous[1]\end{matrix}\right)=\left( \begin{matrix} x_{01} &x_{01} \\x_{02}&x_{02}\end{matrix}\right)
2)将obs扩展为:
obs=(obs[0]obs[1]obs[0]obs[1])=(x11x12x11x12)obs=\left( \begin{matrix} obs[0] &obs[1] \\obs[0]&obs[1]\end{matrix}\right)=\left( \begin{matrix} x_{11} &x_{12} \\x_{11}&x_{12}\end{matrix}\right)
3)将 previous obs和转移得分相加:
scores=(x01x01x02x02)+(x11x12x11x12)+(t11t12t21t22)scores=\left( \begin{matrix} x_{01} &x_{01} \\x_{02}&x_{02}\end{matrix}\right)+\left( \begin{matrix} x_{11} &x_{12} \\x_{11}&x_{12}\end{matrix}\right)+\left( \begin{matrix} t_{11} &t_{12} \\t_{21}&t_{22}\end{matrix}\right)
最终结果:
scores=(x01+x11+t11x01+x12+t12x02+x11+t21x02+x12+t22)scores=\left( \begin{matrix} x_{01}+x_{11}+t_{11} &x_{01} +x_{12}+t_{12}\\x_{02}+x_{11}+t_{21}&x_{02}+x_{12}+t_{22}\end{matrix}\right)

你可能会奇怪,这与之前章节计算所有路径总得分也没啥区别啊,注意了,马上你就能看出区别了。
更新previous:
previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]

假如,我们的得分是:

scores=(x01+x11+t11x01+x12+t12x02+x11+t21x02+x12+t22)=(0.20.30.50.4)scores=\left( \begin{matrix} x_{01}+x_{11}+t_{11} &x_{01} +x_{12}+t_{12}\\x_{02}+x_{11}+t_{21}&x_{02}+x_{12}+t_{22}\end{matrix}\right)=\left( \begin{matrix} 0.2&0.3\\0.5&0.4\end{matrix}\right)

则更新后previous的值为:
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]
previous的意义就是:其存储了该单词标记为每个标签的最大得分。

[示例:START]
例如:
在语料库中有两个标签 label1(l1)label1(l_1) and label2(l2)label2(l_2),这两个标签的索引分别是0和1。
previous[0]previous[0]是以第0个标签 label1(l1)label1(l_1) 结束时路径的最大得分;previous[1]previous[1]是以第1个标签 label2(l2)label2(l_2)结束时路径的最大得分,在每次迭代中,变量previousprevious 存储了以每个标签结束时路径的最大得分,即,在每次迭代中,我们仅保留到每个标签的最好信息previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[max(scores[00],scores[10]),max(scores[01],scores[11])],较少得分的路径信息直接丢弃。
[示例:END]
言归正传:
同时,我们设置两个变量来存储历史信息(得分和索引): alpha0alpha_0 and alpha1alpha_1
这次迭代中,我们将最好的得分存储到alpha0alpha_0。为了方便观察,我们将每个标签的最好得分加下划线:
scores=(x01+x11+t11x01+x12+t12x02+x11+t21x02+x12+t22)=(0.20.30.50.4)scores=\left( \begin{matrix} x_{01}+x_{11}+t_{11} &x_{01} +x_{12}+t_{12}\\\underline{x_{02}+x_{11}+t_{21}}&\underline{x_{02}+x_{12}+t_{22}}\end{matrix}\right)=\left( \begin{matrix} 0.2&0.3\\\underline{0.5}&\underline{0.4}\end{matrix}\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)(1,1)
=(l2,l2)=(l_2,l_2)
==(we can get the maximum score 0.5 when the path is l(i1)=l2\underline{l^{(i-1)}=l_2}l(i)=l1\underline{l^{(i)}=l_1}) ,
we can get the maximum score 0.4 when the path is l(i1)=l2\underline{l^{(i-1)}=l_2}l(i)=l2\underline{l^{(i)}=l_2})

l(i1)l^{(i-1)}是前个单词wi1w_{i-1}的标签。


w0w_0w1w_1w2w_2:

obs=[x21,x22]obs = [x_{21}, x_{22}]
previous=[0.5,0.4]previous = [0.5, 0.4]
1)将previous扩展为:
previous=(previous[0]previous[0]previous[1]previous[1])=(0.50.50.40.4)previous=\left( \begin{matrix} previous[0]&previous[0]\\previous[1]&previous[1]\end{matrix}\right)=\left( \begin{matrix} 0.5&0.5\\0.4&0.4\end{matrix}\right)
2)将obs扩展为:
obs=(obs[0]obs[1]obs[0]obs[1])=(x21x22x21x22)obs=\left( \begin{matrix} obs[0]&obs[1]\\obs[0]&obs[1]\end{matrix}\right)=\left( \begin{matrix} x_{21}&x_{22}\\x_{21}&x_{22}\end{matrix}\right)

3)将previous、obs和转移得分加起来:

scores=(0.50.50.40.4)+(x21x22x21x22)+(t11t12t21t22)scores=\left( \begin{matrix} 0.5&0.5\\0.4&0.4\end{matrix}\right)+\left( \begin{matrix} x_{21}&x_{22}\\x_{21}&x_{22}\end{matrix}\right)+\left( \begin{matrix} t_{11}&t_{12}\\t_{21}&t_{22}\end{matrix}\right)

最终得分:

scores=(0.5+x21+t11x0.5+x22+t120.4+x21+t210.4+x22+t22)scores=\left( \begin{matrix} 0.5+x_{21}+t_{11} &x_0.5+x_{22}+t_{12}\\0.4+x_{21}+t_{21}&0.4+x_{22}+t_{22}\end{matrix}\right)

更新previous:
previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]
则该轮的得分为:
scores=(0.60.90.80.7)scores=\left( \begin{matrix} 0.6&\underline{0.9}\\\underline{0.8}&0.7\end{matrix}\right)

因此,更新previous:
scores=[0.8,0.9]scores=[0.8,0.9]
事实上,previous[0]和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)}]

Step3:找到具有最高得分的路径
这是最后一步了,这该步骤中,alpha0alpha_0alpha1alpha_1将用来寻找具有最高得分的路径,这一步从后向前做。


w1w_1w2w_2:
首先,查看alpha0alpha_0alpha1alpha_1的最后元素: (0.8,0.9)(0.8,0.9)(1,0)(1,0). 0.9 是当标签为 l2l_2时我们获取到的最高路径得分,l2l_2 的索引是1, therefore check the value of (1,0)[1]=0(1,0)[1]=0. The index “0” means the previous label is l1l_1(the index of l1l_1 is 0). So we can get the best path of w1w_1w2w_2: is l1l_1l2l_2.

w0w_0w1w_1:
我们继续向前移动,获取alpha1alpha_1的元素:(1,1),上述中我们知道,w1w_1的标签是l1l_1(索引是0),因此我们检查(1,1)[0]=1,因此,我们可以获取这部分的最佳路径(w0>w1w_0->w_1):l2>l1l_2->l_1
至此,我们已经获得了最佳路径l2l_2l1l_1l2l_2

代码

https://github.com/createmomo/CRF-Layer-on-the-Top-of-BiLSTM

相关文章: