2.6 预测标签
在之前的章节中,我们详细地介绍了BiLSTM-CRF模型和CRF损失函数的细节,大家可以采用开源工具(Keras, Chainer, TensorFlow等)完成自己的BiLSTM-CRF模型。模型搭建过程中,非常重要的是反向传播的实现,不要担心,这些框架在训练过程中可以自动的完成反向传播(即,计算梯度、更新模型参数)。而且,有一些框架已经完成的CRF层,此时,添加CRF层就只是一行代码的工作量了。
这节,我们将介绍,当我们的模型已经训练好时,如何预测一句话的标签。
Step1:BiLSTM-CRF的发射和转移得分
依然,假设我们有只有3个单词组成的一句话: x=[w0,w1,w2]。
而且,我们已经从BiLSTM层获得了发射得分矩阵,从CRF层得到的转移得分矩阵,其示例如下表所示:
|
l1 |
l2 |
| w0 |
x01 |
x02 |
| w1 |
x11 |
x12 |
| w2 |
x21 |
x22 |
xij表示单词 wi 被标记为lj的得分。
|
l1 |
l2 |
| l1 |
t11 |
t12 |
| l2 |
t21 |
t22 |
tij从标签i到标签j的转移得分。
Step2:开始预测
如果你对维特比算法比较了解的话,这部分内容就很简单,如果不知道该算法,也不要担心,这里将一步一步地解释该算法,如下所示,我们将对这句话从左向右进行最终的标签预测:
- w0
-
w0 → w1
-
w0 → w1 → w2
这里,会有两个变量obs 和 previous,previous表示前面所有步骤的结果,obs表示当前单词的信息。
alpha0记录最高历史得分,alpha1 对应着相应的索引,这两个变量的细节之后会慢慢讲解。现在,请看下图:当一条小狗前往森林时,会在沿途做一些“标记”,上述两个变量就可以看作这些“标记”,这些“标记”的作用就是帮助狗狗返回。
w0:
obs=[x01,x02]
previous=None
开始,我们先观察单词w0,目前给w0标记的最好标签是显而易见的。
假如: obs=[x01=0.2,x02=0.8],则w0的最好标签就是l2。
因为,当前只有一个单词,且没有标签之间的转移,因此没有转移得分。
w0 → w1:
obs=[x11,x12]
previous=[x01,x02]
1)将previous扩展为:
previous=(previous[0]previous[1]previous[0]previous[1])=(x01x02x01x02)
2)将obs扩展为:
obs=(obs[0]obs[0]obs[1]obs[1])=(x11x11x12x12)
3)将 previous obs和转移得分相加:
scores=(x01x02x01x02)+(x11x11x12x12)+(t11t21t12t22)
最终结果:
scores=(x01+x11+t11x02+x11+t21x01+x12+t12x02+x12+t22)
你可能会奇怪,这与之前章节计算所有路径总得分也没啥区别啊,注意了,马上你就能看出区别了。
更新previous:
previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]
假如,我们的得分是:
scores=(x01+x11+t11x02+x11+t21x01+x12+t12x02+x12+t22)=(0.20.50.30.4)
则更新后previous的值为:
previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]=[0.5,0.4]
previous的意义就是:其存储了该单词标记为每个标签的最大得分。
[示例:START]
例如:
在语料库中有两个标签 label1(l1) and label2(l2),这两个标签的索引分别是0和1。
previous[0]是以第0个标签 label1(l1) 结束时路径的最大得分;previous[1]是以第1个标签 label2(l2)结束时路径的最大得分,在每次迭代中,变量previous 存储了以每个标签结束时路径的最大得分,即,在每次迭代中,我们仅保留到每个标签的最好信息previous=[max(scores[00],scores[10]),max(scores[01],scores[11])],较少得分的路径信息直接丢弃。
[示例:END]
言归正传:
同时,我们设置两个变量来存储历史信息(得分和索引): alpha0 and alpha1。
这次迭代中,我们将最好的得分存储到alpha0。为了方便观察,我们将每个标签的最好得分加下划线:
scores=(x01+x11+t11x02+x11+t21x01+x12+t12x02+x12+t22)=(0.20.50.30.4)
alpha0=[(scores[10],scores[11])]=[(0.5,0.4)]
同时相应的列索引将保存到alpha1:
alpha1=[(ColumnIndex(scores[10]),ColumnIndex(scores[11]))]=[(1,1)]
如上所述, l1 的索引是0,l2的索引是1,所以, (1,1)=(l2,l2)表明:对于当前单词 wi和标签l(i):
(1,1)
=(l2,l2)
=(we can get the maximum score 0.5 when the path is l(i−1)=l2 → l(i)=l1) ,
we can get the maximum score 0.4 when the path is l(i−1)=l2 → l(i)=l2)
l(i−1)是前个单词wi−1的标签。
w0 → w1 → w2:
obs=[x21,x22]
previous=[0.5,0.4]
1)将previous扩展为:
previous=(previous[0]previous[1]previous[0]previous[1])=(0.50.40.50.4)
2)将obs扩展为:
obs=(obs[0]obs[0]obs[1]obs[1])=(x21x21x22x22)
3)将previous、obs和转移得分加起来:
scores=(0.50.40.50.4)+(x21x21x22x22)+(t11t21t12t22)
最终得分:
scores=(0.5+x21+t110.4+x21+t21x0.5+x22+t120.4+x22+t22)
更新previous:
previous=[max(scores[00],scores[10]),max(scores[01],scores[11])]
则该轮的得分为:
scores=(0.60.80.90.7)
因此,更新previous:
scores=[0.8,0.9]
事实上,previous[0]和previous[1]之间较大的那个值则是最佳预测路径得分。
同时,每个标签的最大得分和索引添加到相应的alpha0 和 alpha1:
alpha0=[(0.5,0.4),(scores[10],scores[01])]
=[(0.5,0.4),(0.8,0.9)]
alpha1=[(1,1),(1,0)]
Step3:找到具有最高得分的路径
这是最后一步了,这该步骤中,alpha0和alpha1将用来寻找具有最高得分的路径,这一步从后向前做。
w1 → w2:
首先,查看alpha0 和 alpha1的最后元素: (0.8,0.9) 和 (1,0). 0.9 是当标签为 l2时我们获取到的最高路径得分,l2 的索引是1, therefore check the value of (1,0)[1]=0. The index “0” means the previous label is l1(the index of l1 is 0). So we can get the best path of w1 → w2: is l1 → l2.
w0 → w1:
我们继续向前移动,获取alpha1的元素:(1,1),上述中我们知道,w1的标签是l1(索引是0),因此我们检查(1,1)[0]=1,因此,我们可以获取这部分的最佳路径(w0−>w1):l2−>l1。
至此,我们已经获得了最佳路径l2 → l1 → l2 。
代码
https://github.com/createmomo/CRF-Layer-on-the-Top-of-BiLSTM