[转] LSTM+ CRF中的损失函数

from https://blog.csdn.net/u013963380/article/details/108696552

本文翻译,原文地址:

https://createmomo.github.io/2017/10/08/CRF-Layer-on-the-Top-of-BiLSTM-3/

https://createmomo.github.io/2017/10/17/CRF-Layer-on-the-Top-of-BiLSTM-4/

https://createmomo.github.io/2017/11/11/CRF-Layer-on-the-Top-of-BiLSTM-5/

三、CRF损失函数

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

例如,我们的数据集中有如下几种类别:

Label Index
B-Person 0
I-Person 1
B-Organization 2
I-Organization 3
O 4
START 5
END 6

一个包含5个单词的句子,可能的类别序列如下:

  • 1) START B-Person B-Person B-Person B-Person B-Person END
  • 2) 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},共有N条路径,则路径的总分是:

P_{total}=P_{1}+P_{2}+...+P_{N}=e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}e是一个数学常量。(下节会详细介绍如何计算S_{i},这里你可以把它当作这条路径的分数)。

如果第十条路径是真实路径,也就是说第十条是正确预测结果,那么P_{10}应该是所有可能路径里分数最高的。根据如下损失函数,在训练过程中,BiLSTM-CRF模型的参数值将随着训练过程的迭代不断更新,使得真实路径所占的比值越来越大。

LossFunction=\frac{P_{RealPath}}{P_{1}+P_{2}+...+P_{N}}

那么现在的问题就是:

  • 如何定义路径的分数
  • 怎么计算所有路径的分数
  • 当计算所有的路径分时,是否需要穷举多有可能的路径?(答案是不需要)

四、真实路径分数

很明显,在所有的可能的路径中有一条是真实的路径。比如在上述的类别序列中,“START B-Person I-Person O B-Organization O END”是一条真实的路径。不正确的路径如“START B-Person B-Organization O I-Person I-Person B-Person”。e^{S_{1}}是第i条路径的分数。

在训练阶段,crf的损失函数只需要两种类别的分数,真实路径的分数 和 所有路径的总分数。在所有的可能路径的分数中,真实路径的分数应该是最高的。

当然计算e^{S_{1}}是十分简单的,下面让我们聚焦如何来计算S_{i}

我们假设“START B-Person I-Person O B-Organization O END”是一条真实的路径:

  • 一个句子中有5个单词,分别是w_{1},w_{2},w_{3},w_{4},w_{5}
  • 添加开始和结尾单词,分别是w_{0},w_{6}
  • S_{i}包含两个部分,S_{i}=EmissionScore+TransitionScore

tips:Emission Score 和 Transition Score在《BiLSTM中的CRF层(二)CRF层》一文中已经介绍。

(1)Emission Score(发射分数):

EmissionScore=x_{0,START}+x_{1,B-Person}+x_{2,I-Person}+x_{3,O}+x_{4,B-Organization}+x_{5,O}+x_{6,END}

  • x_{index,label}是第index索引的单词被标注为label的分数
  • x_{1,B-Person},x_{2,I-Person},x_{3,O},x_{4,B-Organization},x_{5,O}这些分数来自前一层BiLstm的输出
  • x_{0,START},x_{6,END}可以设置为0

(2)Transition Score(转移分数):

TransitionScore=t_{START->B-Person}+t_{B-Person->I-Person}+t_{I-Person->O}+t_{O->B-Organization}+t_{B-Organization->O}+t_{O->END}

  • t_{label1->label2}是从label1转移到label2的分数
  • 这些分数来自于CRF层。换句话说,这些分数其实是CRF层的参数

五、所有路径的分数

上面提到所有路径的分数P_{total}=P_{1}+P_{2}+...+P_{N}=e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}。计算所有路径的总分最简单的方式是:穷举所有可能的路径,分别计算路径分,最后求和。但是这种方式是十分低效的,而且训练时间也是不可忍受的。

下面以一个简单的例子来说明如何高效的计算所有路径的分数。

Step1: recall the CRF loss function

CRF损失函数的定义是LossFunction=\frac{P_{RealPath}}{P_{1}+P_{2}+...+P_{N}},我们把它变成log损失函数如下:

LogLossFunction=log\frac{P_{RealPath}}{P_{1}+P_{2}+...+P_{N}},由于我们训练的目标通常是最小化损失函数,所以我们加上负号:

LogLossFunction=log\frac{P_{RealPath}}{P_{1}+P_{2}+...+P_{N}}\\=-log\frac{e^{S_{RealPath}}}{e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}}\\=-(loge^{S_{RealPath}}-log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}))\\ =-(S_{RealPath}-log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}))\\ =-(\sum_{i=1}^{N}x_{iyi}+\sum_{i=1}^{N-1}t_{yiyi+1}-log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}}))

(原文中在求真实路径的分数的时候,求和用的是N和N-1,但是从上面的求解发射分数和转移分数公式看,这里的N应该是句子的长度words,N-1应该是标签数num_tag,所有的路径总数N应该是N=(num_tag)^(words),否则对应不上。不知道是不是作者为了简化统一用N表示,还是本人理解错误。。。囧囧囧)

在上面,我们已经知道如何计算真实路径的分数,下面我们只需要找到一种高效的方式来计算log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}})

Step2:recall the Emission and Transition Score

为了简化说明,这里我们假设我们训练模型的句子只有3的长度,标签只有2种:

x=[w_{0},w_{1},w_{2}]

labelset=[l_{1}, l_{2}]

我们从Bi-Lstm层获得的发射分数如下:

  l_{1} l_{2}
w_{0} x_{01} x_{02}
w_{1} x_{11} x_{12}
w_{2} x_{21} x_{22}

tips:x_{ij}表示单词w_{i}被标签为l_{j}的分数。

从CRF层获得的转移分数如下:

  l_{1} l_{2}
l_{1} t_{11} t_{12}
l_{2} t_{21} t_{22}

tips:t_{ij}表示从标签i转移到标签j的分数

Step3:START FIGHTING! 

首先要记得我们的目标是log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}})

整个过程其实是分数累加的过程。它的思想和动态规划如出一辙。总而言之就是,首先单词w_{0}的所有路径的总分被计算出来;然后,计算从w_{0}->w_{1} 的所有路径的得分,最后计算w_{0}->w_{1}->w_{2}的所有路径的得分,也就是我们最终要的结果。

接下来,你会看到两个变量:obs和 previous。previous存储了之前步骤的结果,obs代表当前单词的信息。

=======================================================================================================

w_{0}

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

previous=None

如果我们的句子只有一个单词w_{0},前一个步骤没有任何的结果,因此previous=None。另外,我们只能获取到obs=[x_{01},x_{02}]x_{01}x_{02}是上面提到的从BiLSTM层获得的发射分数。

因此,这里单词w_{0}的所有路径分数为:

TotalScore(w_{0})=log(e^{x_{01}}+e^{x_{02}})

=======================================================================================================

w_{0}->w_{1}

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

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

(1) 将previous扩展为:

previous=\begin{pmatrix} x_{01} & x_{01} \\ x_{02} & x_{02} \end{pmatrix}

(2) 将obs扩展为:

obs=\begin{pmatrix} x_{11} & x_{12} \\ x_{11} & x_{12} \end{pmatrix}

将previos和obs扩展是为了计算总分更加高效。下面将会看到

(3) 对previou、obs和转移分数求和:

scores=\begin{pmatrix} x_{01} & x_{01}\\ x_{02} & x_{02} \end{pmatrix} + \begin{pmatrix} x_{11} & x_{11}\\ x_{12} & x_{12} \end{pmatrix} + \begin{pmatrix} t_{11} & t_{12}\\ t_{21} & t_{22} \end{pmatrix}

score=\begin{pmatrix} 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{pmatrix}

然后改变previos的值

previous=[log(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}),log(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}})]

到这里,第二次迭代实际上已经完成了。然后,我们使用新的previous值来计算w_{0}->w_{1}的所有路径总分:

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^{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}})

从上面公式可以看出,这就是我们的求解目标log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}})

在上述公式中:

  • S_{1}=x_{01}+x_{11}+t_{11}\ (label1->label1)
  • S_{2}=x_{02}+x_{11}+t_{21}\ (label2->label1)
  • S_{3}=x_{01}+x_{12}+t_{12}\ (label1->label2)
  • S_{4}=x_{02}+x_{12}+t_{22}\ (label2->label2)

=======================================================================================================

下面的手码太累了,直接贴原文的截图,截图出自(https://createmomo.github.io/2017/11/11/CRF-Layer-on-the-Top-of-BiLSTM-5/),原理是一样的。

=======================================================================================================

上述过程建议用手推一遍,对理解这个过程十分有用。。。

至此,我们完成了log(e^{S_{1}}+e^{S_{2}}+...+e^{S_{N}})的求解过程。

六、如何利用CRF来推理

前面几节介绍了Bi-Lstm-CRF的模型结构以及CRF损失函数。我们可以使用开源的深度学习框架(Keras、tensorflow等)来实现一个Bi-Lstm-CRF模型。而且用这些框架最好的是不用自己来实现反向传播这个过程,更有的框架已经实现了CRF层,只需要添加一行代码就可以完全实现Bi-Lstm-CRF模型。

推理的过程和上述求解所有路径总分的过程有点相似,每次获取得分最高的路径,最终选择所有路径中得分最高的路径为最佳路径。

详细过程见原文:https://createmomo.github.io/2017/11/24/CRF-Layer-on-the-Top-of-BiLSTM-6/

这里不再讲述,因为整个过程十分简单,理解了第五节中的求解过程即可。

 

posted @ 2021-08-12 10:12  凌波微步_Arborday  阅读(945)  评论(0编辑  收藏  举报