CRF原理介绍(以BILSTM-CRF模型为例)
BiLSTM-CRF命名实体识别内容总结
BiLSTM-CRF模型概述
BiLSTM-CRF结合了双向LSTM和CRF层,用于命名实体识别任务。BiLSTM通过前后双向序列学习特征,CRF则建模标签之间的依赖关系,提升识别准确性。
CRF层功能
CRF层用于建模标签序列的全局依赖,通过定义发射分数(Emission)和转移分数(Transition)来计算所有可能标签序列的总得分。发射分数基于BiLSTM的输出,转移分数基于CRF的参数。
损失函数
损失函数由交叉熵损失和CRF层损失组成。交叉熵损失衡量预测概率与真实标签的差异,CRF层损失考虑所有可能标签序列的总得分,选择最佳路径。
推理过程
使用动态规划(维特比算法)解码,逐步计算每个位置的最高得分及对应标签,最终得到最佳标签序列。
实例分析
通过具体句子实例,展示了BiLSTM-CRF在命名实体识别中的应用,包括BiLSTM输出、CRF发射和转移分数计算、损失函数优化以及推理过程。
参考文献
相关论文链接,供进一步学习和研究。总结:BiLSTM-CRF结合了双向LSTM和CRF层,通过建模局部和全局依赖关系,有效提升了命名实体识别的准确性。
文章目录
-
1. BiLSTM-CRF命名实体识别概要
-
- 1.1 模型介绍
- 1.2 CRF在模型中的作用
-
2. CRF层详解
-
2.1 发射得分矩阵(Emission得分矩阵)
- 2.2 转移得分矩阵(Transition得分矩阵)
- 2.3 CRF的损失函数
- 2.4 具体计算方法
- 2.5 所有可能路径的总得分计算
-
3. 新的句子推理
-
4. 参考
-
1. BiLSTM-CRF命名实体识别概要
我们假设有一个数据集,其中有两个实体类别,person和organization。然而,在我们的数据集中,我们实际上拥有5个实体标签。
B-Person
I- Person
B-Organization
I-Organization
O
令x为一个由5个词组成的句子:w0,w1,w2,w3,w4。在句子x中,[w0,w1]标识为Person实体,[w3]标识为Organization实体,其余位置标记为‘O’。
1.1 模型介绍
BiLSTM-CRF模型总体结构图如图1所示

图1. BiLSTM-CRF模型总体结构图
首先,将句子x中的每个单词表示为向量,其中每个单词的向量由单词嵌入和字符嵌入组成。字符嵌入是随机初始化的,而词嵌入通常是从一个预先训练的词嵌入文件中导入的。这些嵌入在训练过程中将被微调以适应特定任务。接着,BiLSTM-CRF模型接收这些嵌入作为输入,并输出每个单词的预测标签及其分数。如图2所示,BiLSTM层为每个标签生成相应的分数。例如,对于w0,BiLSTM节点输出了1.5 (B-Person)、0.9 (I-Person)、0.1 (B-Organization)、0.08 (I-Organization)和0.05 (O)的分数,这些分数将作为CRF层的输入。

图2. BiLSTM 输出示意图
将BiLSTM层的预测分数传递给CRF层。在CRF层中,确定最高得分为对应的最佳标签序列。
1.2 CRF在模型中的作用
如图3所示,该模型能够训练出一个不依赖于CRF层的BiLSTM命名实体识别系统。该系统通过每个单词的BiLSTM输出生成相应的标签分数,从而选择每个单词标签分数最高的类别。
例如,基于w0,“B-Person”的最高得分为1.5,我们可以将其归类为“B-Person”这一最佳预测标签。同样地,为w1我们选择“I-Person”,为w2归类为“O”,为w3选择“B-Organization”,为w4归类为“O”。

图3. 使用BiLSTM做命名实体识别
然而,在这个例子中,我们能够获得正确的句子x的标签,但这种情况并不总是持续。如图所示的例子,“I-Organization I-Person”和“B-Organization I-Person”显然不符合预期。

图4. BILSTM做ner的badcase
加入CRF层后,会尽量避免出现这种情况。这是因为CRF层能够从训练数据中学习约束,从而确保其有效性。这些约束能够由CRF层在训练过程中从训练数据集中自动学习。
学到的约束条件可以是:
在标记序列中,第一个单词的标签应正确使用B标签或O标签,避免使用I标签。具体而言,有效的标签模式应为B标签1、B标签2、B标签3等,确保所有连续的命名实体标签具有相同的名称。例如,正确的标签序列应为O B-实体标签,而非O I-实体标签。这些严格的规则将有效减少无效预测标签序列的数量。
2. CRF层详解
2.1 发射矩阵(emission矩阵)
在CRF层的损失函数中,我们有两种分数类型。这些分数是CRF层的核心概念。第一个分数类型是emission分数。这些emission分数源自BiLSTM层。如图5所示,标记为B-Person的权重w0的值为1.5。

图5. BILSTM-CRF模型及其输出结果
为了便于起见,我们给每个标签分配一个编号,如下表所示。
| label | index |
|---|---|
| B-Persion | 0 |
| I-Persion | 1 |
| B-Organization | 2 |
| I-Organization | 3 |
| O | 4 |
用x_{iy_{j}}表示emission rate。其中,i表示word的索引,y_j表示label的索引。参考图5可知,x_{i=1, y_{j}=2}=x_{w_{1}, B-\text { Organization }}=0.1,即为w1在B-Organization类别中的得分为0.1。
2.2 转移矩阵(Transition得分)
我们用t_{y_iy_j}这一符号来表示transition分数。例如,t_{B-Person, I-Person}=0.9,表示从B-Person标签转移到I-Person标签的得分为0.9。因此,我们构建了一个transition得分矩阵,该矩阵记录了所有标签之间的转移得分。
为了增强transition评分矩阵的健壮性,我们计划增添两个新的标记,START和END。START标记表示句首,而非第一个词的位置。END标记则标识句尾。
以下是一个transition得分矩阵的示例,其中加入了START和END标签,以更好地进行状态转换的建模。

图6. 转移矩阵
如上表所示,我们可以发现transition矩阵已经学习了一些有用的约束。
实体标签的第一项必须以B-开头,不能以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 B-label"(同样,的分数非常小) 。
那么如何得到transition矩阵?
在模型中,该参数矩阵是BiLSTM-CRF模型的一个重要组成部分。在模型训练初期,可以对矩阵中的所有transition分数进行随机设定。这些随机分数将在模型训练过程中动态调整。进一步说明,CRF层能够自主学习这些约束条件。我们无需人工构建矩阵。随着训练迭代次数的提升,分数值将逐渐趋于合理。
2.3 CRF损失函数
CRF损失函数由真实路径得分和所有可能路径的总得分构成。在所有可能的路径中,真实路径的得分应为最高。
例如,如果我们的数据集中有如下表所示的这些标签:
| label | index |
|---|---|
| B-Persion | 0 |
| I-Persion | 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_{\text{total}} = P_1 + P_2 + \ldots + P_N,其中每个P_i对应指数e^{S_i}。其中,e^{S_i}表示第i条路径的权重,后续将详细说明如何计算它。
我们确认第10条路径为真实路径,即它是我们的训练数据集提供的黄金标准标签。在所有可能的路径中,P_{10}得分应当占据总分的百分比最大。
在训练阶段,我们的BiLSTM-CRF模型参数值将不断更新,以持续提升真实路径的分数百分比。
LossFunction =\frac{P_{\text {RealPath }}}{P_{1}+P_{2}+\ldots+P_{N}}
问题在于,如何确定一个路径的分数?如何计算出所有路径的总分值?在计算总分时,是否需要列出所有路径?答案是否定的。
2.4 实际路径得分计算
可以得出,在所有可能的路径集合中,必定存在一条真实路径。在上一节中提到的例子中,实际路径是“START B-Person I-Person O B-Organization O END”。其他路径不正确,例如“START B-Person B-Organization O I-Person I-Person B-Person”。其中,第i条路径的得分为e^{S_i}。
在训练过程中,CRF损失函数仅需计算两个分数:真实路径的分数与所有可能路径的总分数。在所有可能路径的分数中,真实路径的分数占比会逐步提高。
计算e^{S_i}相对便捷,采用真实路径标记“START B-Person I-Person O B-Organization O END”,其中S_i由两部分组成,其中S_i等于emission_score与transition_score之和。
\text { EmissionScore } equals the sum of x_{0, S T A R T}, x_{1, B-\text { Person }}, x_{2, I-\text { Person }}, x_{3, O}, x_{4, B-\text { Organization }}, x_{5, O}, and x_{6} END$.
其中
x_{\text {index }, \text { 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。
TransitionScore = t_{START-B-PERSON} + t_{B-PERSON-I-PERSON} + t_{I-PERSON->O} + t_{O->B-ORGNIZATION} + t_{B-ORGNIZATION->O} + t_{O->END}
- t_{ {label } 1- label2}> 代表从 label1 到 label2 的 transition 分数。
- 这些分数源自 CRF 层。更明确地说,这些 transition 分数实际上是 CRF 层的参数。
综上可以计算出e^{S_i}
2.5 所有可能路径总分计算
在2.3节中所定义的损失函数变量取对数运算后得到:
{ log(LossFunction) }=\log \frac{P_{\text {RealPath }}}{P_{1}+P_{2}+\ldots+P_{N}}}
为了最小化我们的目标函数,我们引入负号。具体而言,损失函数的最小化过程可以表示为:
因此,我们只需采用一种高效且准确的方法来计算\log \left(e^{S_{1}}+e^{S_{2}}+\ldots+e^{S_{N}}\right)。
准备阶段
| l_1 | l_2 | |
|---|---|---|
| w_0 | x_{01} | x_{02} |
| w_1 | x_{11} | x_{12} |
| w_2 | x_{21} | x_{22} |
x_{ij}表示w_i被标成l_j的得分
此外,我们定义来自CRF层的transition得分为t_{ij},其中t_{ij}表示从标签i到标签j的transition分数,具体来说,t_{ij}表示从标签i到标签j的transition分数,反映了标签间的转换可能性。
这个过程涉及分数的逐步累加。其核心思路类似于动态规划。具体而言,我们需要计算起始状态w0的所有可能路径的总分。然后,利用总分来计算w0到w1的转移分数。最后,以最新的总分来计算w0→w1→w2的总转移分数。这样,我们就能逐步累加出最终的总分。
定义两个变量: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}分别来自上述的Emission分数。
w_0的所有可能路径的总分是
{TotalScore}\left(w_{0}\right)=\log \left(e^{x_{01}}+e^{x_{02}}\right)
\begin{aligned} &w_{0}->w_{1}: \\ &o b s=\left[x_{11}, x_{12}\right] \\ &{ previous }=\left[x_{01}, x_{02}\right] \end{aligned}
\text { prior }可表示为:\left(\begin{array}{ll} x_{01} & x_{01} \\ x_{02} & x_{02} \end{array}\right)
- 把obs展开成:
o b s=\left(\begin{array}{ll} x_{11} & x_{12} \\ x_{11} & x_{12} \end{array}\right)
将 previous、obs 和 transition 的得分进行汇总:
\begin{aligned} &{ Total } \operatorname{Score}\left(w_{0}->w_{1}\right)=\log \left(e^{\text {previous }[0]}+e^{\text {previous }[1]}\right)\\ &=\log \left(e^{\log \left(e^{x_{0}+x_{11}+t_{11}}+e^{\left.x_{2}+x_{11}+t_{21}\right)}\right.}+\right. \left.e^{\log \left(e^{\left.x_{01}+x_{12}+t_{12}+e^{x_{02}+x_{12}+t_{22}}\right)}\right.}\right)\\ &=\log \left(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}}\right) \end{aligned}
这正是我们的目标:\log \left(e^{S_{1}}+e^{S_{2}}+\ldots+e^{S_{N}}\right),其中
\begin{aligned} S_{1} &=x_{01}+x_{11}+t_{11}\left(\text { label }_{1}->\text { label }_{1}\right) \\ S_{2} &=x_{02}+x_{11}+t_{21}\left(\text { label }_{2}->\text { label }_{1}\right) \\ S_{3} &=x_{01}+x_{12}+t_{12}\left(\text { label }_{1}->\text { label }_{2}\right) \\ S_{4} &=x_{02}+x_{12}+t_{22}\left(\text { label }_{2}->\text { label }_{2}\right) \end{aligned}
w_0 \rightarrow w_1 > w_2:
在此迭代中,我们执行的操作与上一迭代相同:
\begin{aligned} &obs = [x_{21}, x_{22}] \\ &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}})] \end{aligned}
initial is defined as:
initial=\left(\begin{array}{ll} \log \left(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}\right) & \log \left(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}\right) \\ \log \left(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}}\right), & \log \left(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}}\right) \end{array}\right)
- 把obs扩展成:
o b s=\left(\begin{array}{ll} x_{21} & x_{22} \\ x_{21} & x_{22} \end{array}\right)
将previous、obs以及transition的分数进行求和。具体而言,scores等于previous分数矩阵与obs分数矩阵之和,再加上transition分数矩阵。数学表达式如下所示:
即,scores等于previous分数矩阵与obs分数矩阵之和,再加上transition分数矩阵。具体而言,scores的每个元素由previous、obs和transition三个矩阵对应元素的和构成。
-
为下一个迭代计算 previous的值:
\begin{aligned} & previews = \left[\log \left(e^{\log \left(e^{\left.x_{01}+x_{11}+t_{11}+e^{x_{02}}+x_{11}+t_{21}\right)+x_{21}+t_{11}}\right.}+e^{\log \left(e^{\left.x_{01}+x_{12}+t_{12}+e^{x_{02}+x_{12}+t_{22}}\right)+x_{21}+t_{21}}\right)}\right.\right.,\\ & \log \left(e^{\log \left(e^{\left.x_{01}+x_{11}+t_{11}+e^{x_{02}+x_{11}+t_{21}}\right)+x_{22}+t_{12}}\right.}+e^{\log \left(e^{\left.x_{01}+x_{12}+t_{12}+e^{x_{02}+x_{12}+t_{22}}\right)+x_{22}+t_{22}}\right)}\right]\\ &=\left[\log \left(\left(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}\right) e^{x_{21}+t_{11}}+\left(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}}\right) e^{x_{21}+t_{21}}\right)\right.,\\ &\left.\log \left(\left(e^{x_{01}+x_{11}+t_{11}}+e^{x_{02}+x_{11}+t_{21}}\right) e^{x_{22}+t_{12}}+\left(e^{x_{01}+x_{12}+t_{12}}+e^{x_{02}+x_{12}+t_{22}}\right) e^{x_{22}+t_{22}}\right)\right] \end{aligned} -
使用新的previous中的元素来计算total score

实现目标\log \left(e^{S_{1}}+e^{S_{2}}+\ldots+e^{S_{N}}\right),该句子由三个单词组成,label set包含两个标签,因此,该label set共有8种可能的label路径。
如图6所示,假设图中有n个字符(其中n=3),以及m个标签(其中m=2)。若采用暴力法,遍历所有路径并计算总分,总共有m^n条路径。每条路径需要进行(n-1)次计算,因此计算复杂度为O((n-1)m^n)。例如,在上述示例中,计算次数为16次。
该方法要求每次向前推一个字符时需进行m^2次计算,总共需要推n-1次,因此,总计算复杂度为O((n-1)m^2)。在该例中,总计算次数为8次。
由此可知上述方法的有效性

图6. 寻找所有路径示意图
3. 新的句子推理
在推理阶段能够计算出所有路径的得分,随后选择得分最高的路径作为最终结果。然而,这种计算量过于庞大,因此转而采用基于动态规划思想的维特比算法来进行解码。
(1)推理准备
命名为previous的变量用于保存前一阶段的最终结果。obs变量记录当前单词的相关信息。alpha_0表示历史阶段的最佳得分数,alpha_1则记录了与该得分相对应的历史位置。
(2)开始推理
step1
w_0:
obs=[x_{01}=0.2, x_{02}=0.8]
previous=None
当前仅观测到第一个单词,由于只有一个单词存在,且没有直接的标签转换途径,因此transition的得分为零。例如,观测结果为obs=[x_{01}=0.2, x_{02}=0.8],显然,w_0的最佳标签应为l_2。
step2
w_0->w_1:
obs=[x_{11}, x_{12}]
previous=[x_{01}, x_{02}]
\text { prior }=\left(\begin{array}{ll} \text { prior }[0] & \text { prior }[0] \\ \text { prior }[1] & \text { prior }[1] \end{array}\right)=\left(\begin{array}{ll} x_{01} & x_{01} \\ x_{02} & x_{02} \end{array}\right)
将观测值obs进行扩展定义为:
\text { obs }=\left(\begin{array}{ll} o b s[0] & o b s[1] \\ o b s[0] & o b s[1] \end{array}\right)=\left(\begin{array}{ll} x_{11} & x_{12} \\ x_{11} & x_{12} \end{array}\right)
- 把previous, obs和transition 分数都加起来:
\text { scores }=\left(\begin{array}{ll} x_{01} & x_{01} \\ x_{02} & x_{02} \end{array}\right)+\left(\begin{array}{ll} x_{11} & x_{12} \\ x_{11} & x_{12} \end{array}\right)+\left(\begin{array}{ll} t_{11} & t_{12} \\ t_{21} & t_{22} \end{array}\right)
即:(后面具体的值为假设的值)
\text { scores }=\left(\begin{array}{ll} 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{array}\right)=\left(\begin{array}{ll} 0.2 & 0.3 \\ 0.5 & 0.4 \end{array}\right)
在下一轮迭代中,更新previous的值:
数学公式...原样保留
例如,我们的得分矩阵为:
\text { scores }=\left(\begin{array}{ll} 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{array}\right)=\left(\begin{array}{ll} 0.2 & 0.3 \\ 0.5 & 0.4 \end{array}\right)
那么,下一轮迭代的previous值为:
\text { previous }=[\max (\text { scores }[00], \text { scores }[10]), \max (\text { scores }[01], \text { scores }[11])]=[0.5,0.4]
图7详细说明了这一过程:当最后一个字符为w_1时,包括两条以标签1结尾的路径和两条以标签2结尾的路径,在每个时间步(字符)时,根据每个标签结尾的最大得分来更新路径得分。

图7. previous迭代原理
举例来说,在我们的语料中,仅包含两个标签,l_1和l_2,其索引分别为0和1。在动态规划过程中,previous[0]的值代表以第0个标签为结尾的路径的最大得分,类似地,previous[1]的值代表以第1个标签为结尾的路径的最大得分。换句话说,在每次迭代中,变量previous记录了以每个标签为结尾的路径的最大得分。换句话说,在每次迭代中,我们只保留了每个标签对应的最佳路径得分(即previous =\max ( scores [00], scores [10]), \max ( scores [01], scores [11]))。具有较低得分的路径信息会被舍弃。
此外,我们还引入了两个变量用于存储历史信息,即得分和索引,分别表示为alpha_0和alpha_1。在这一轮迭代中,我们将最佳得分加入到alpha_0中,为了简化表示,每个标签的最大得分都会在其下方加上下划线。

图8. alpha1索引含义说明
step3
w_{0}->w_{1}->w_{2}:
{ obs }=\left[x_{21}, x_{22}\right]
{ previous }=[0.5,0.4]
\text { prior }=\left(\begin{array}{ll} \text { prior }[0] & \text { prior }[0] \\ \text { prior[1] } & \text { prior }[1] \end{array}\right)=\left(\begin{array}{ll} 0.5 & 0.5 \\ 0.4 & 0.4 \end{array}\right),其中\text { prior }表示一个2x2的矩阵,其第一行和第一列的元素均为0.5,第二行和第二列的元素均为0.4。
为了便于后续分析,我们将其表示为:
o b s=\left(\begin{array}{ll} o b s[0] & o b s[1] \\ o b s[0] & o b s[1] \end{array}\right)=\left(\begin{array}{ll} x_{21} & x_{22} \\ x_{21} & x_{22} \end{array}\right)
将previous、obs以及transition的分数进行汇总:计算得到的scores值由以下三部分组成,包括previous分数矩阵、obs分数矩阵以及transition分数矩阵。具体来说,scores值的计算公式如下所示:
具体来说,scores值的计算公式如下所示:
在下一轮迭代中更新previous的值,其定义为\text { previous }=[\max (\text { scores }[0][0], \text { scores }[0][1]), \max (\text { scores }[1][0], \text { scores }[1][1])]。
在本次迭代过程中,我们计算得到的分数为:
scores = \left(\begin{array}{ll} 0.6 & 0.9 \\ 0.8 & 0.7 \end{array}\right)
其中,previous被定义为[0.8, 0.9]。其中,previous[0]和previous[1]中的最大值对应于预测的最佳路径。同时,对于每个标签及其对应的索引,其最大得分分别被加到alpha_0和alpha_1中:
alpha_0 = [(0.5, 0.4), (scores[10], scores[01])] = [(0.5, 0.4), (0.8, 0.9)]
alpha_1 = [(1, 1), (1, 0)]
step4 确定最高得分数值的路径
首先,通过检查alpha_0和alpha_1的最后一个元素,即(0.8,0.9)和(1,0),我们可以明确路径分数的分配情况。其中,0.9表示在标签l_2的情况下,可以得到最高路径分数0.9。由于标签l_2的索引为1,因此我们关注(1,0)这一元素。其中,索引0表示前一个标签为l_1(因为l_1的索引为0),因此可以推断出w_1->w_2的最佳路径为l_1->l_2。
在接下来的步骤中,我们向后推进,从而获得了alpha_1:(1,1)这一元素。参考上文,我们了解到w1的标签是l_1,其索引为0。因此,我们对(1,1)[0]的值进行检查。由此,我们确定了这一部分的最佳路径:w_0->w_1对应l_2->l_1。
最后我们可以得到最佳路径为:l_2->l_1->l_2
4. 参考
BiLSTM架构上结合CRF模型,通过命名实体识别任务来解释CRF模型的作用机制(1)
