CRF

许多随机变量组成一个无向图G = {V, E},V代表顶点,E代表顶点间相连的边,

每个顶点代表一个随机变量,边代表两个随机变量间存在相互影响关系(变量非独立),

如果随机变量根据图的结构而具有对应的条件独立性,

具体来说,两个没有边连接随机变量V1、V2,在其它随机变量O都确定的情况下,是独立的。

即 P(V1, V2 | O) = P(V1 | O) * P(V2 | O)

那么这被称为【成对马尔科夫性】,另有不同定义的【局部马尔科夫性】、【全局马尔科夫性】,它们互为充要条件(此处无证明)

对于满足成对马尔科夫性无向图,可以对最大团作定义

一个最大团是一组随机变量(顶点)的集合,且要满足两个条件

(1).这一组顶点之间,两两都有边相连

(2).任意一个不在这组内的顶点,不能和该组顶点的每一个都有边相连

那么一个无向图G,可以唯一地表示为一个最大团的集合C = {C1, C2, ...}

我们可能会对这组随机变量的联合分布感兴趣,比如计算P(V1=a,V2=b,V3=c...)

可以证明,无向图G的联合分布,可以被最大团表示为 phi1(C1)phi1(C2)....phin(Cn) / Z

其中,phi1~phin称为最大团C1~Cn上的势函数,Z是所有可能的随机变量取值组合下,phi1(C1)phi1(C2)....phin(Cn)的和

可以看出来Z实际上就是一个归一项

因为势函数一般要求是严格正的,所以会用一种指数函数的形式来表示

即phi1(C1)phi1(C2)....phin(Cn) = exp(E1(C1))exp(E2(C2))...exp(En(Cn)) = exp(En(Cn) + E1(Cn) + ... + En(Cn))

其中这个E1~En,可以看做是对某个最大团的随机变量的当前取值的打分

总结起来,如果要求P(Y1Y2...Yn)的值,则应该计算当前每个最大团的分数,求和,并执行softmax,softtmax的底是所有可能的变量值组合。

linear-CRF

线性的CRF,每个Y都只和前一个或后一个随机变量相连,

如 Y1——Y2——Y3——...Yn

每个最大团都是邻近的两个随机变量,如(Y1, Y2)、(Y2、Y3)等

线性CRF通常用于序列预测中,

比如,假设输入为X,输出为序列Y,每一个随机变量的取值都在T = {'B', 'E', 'M', 'O'}之中,

那么计算某个特定序列的条件概率。

更具体地,比如计算

P('BMEOBMEO' | X) / P(Y | X) = exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)

∑Y exp(Y | X)这项作为归一项,实际是求同样长度的所有序列组合的exp分数之和,

对于目标序列'BMEOBMEO',它长度为8,那么同样长度的序列包括'BBBBBBBB'、'BBBBBBBM'等等....

linear-CRF的前向计算

这个同样长度的所有序列,数量是非常巨大的,

确切地说,应该是O(|T|^n)的量级,|T|是状态集的大小,n是序列长度。

如果每一个序列都要计算一次分数,那稍长一点的序列计算时间都会长到无法接受。

此时,根据linear-CRF图结构的特性,可以采用动态规划的方式,减少重复计算量,降低时间复杂度。

考虑Score(Y1:n-1, X)和Score(Y1:n, X)的区别,在两个无向图中,后者比前者增加了两条边,

(1).边Yn-1——Yn (2).边X——Yn

所以Score(Y1:n, X) = Score(Y1:n-1, X) + E-tran(Yn-1, Yn) + E-emmi(X, Yn)

其中E(Yn-1, Yn)又可称为转移分数,E(X, Yn)又可称为发射分数。

发现了该递推关系以后,再思考一个非常重要的递推中间变量:

g(k, tag) = exp(Score(Y1:k-1Yk = tag, X))

也就是,在时间点k上,Yk等于tag,但是前面的Y1:k-1状态随意的分数,

因为Y1:k-1状态随意,它实质上是Y1:k-1字序列所有可能组合,且Yk以tag为结尾的分数和

具体地,g(3, 'B') = ∑(Y1:k-1) exp(Score(Y1:Y2Y3='B', X)) = exp(Score('BBB', X)) + exp(Score('BEB', X)) + exp(Score('BMB', X)) + ... + exp(Score('OOB', X))

最后一个等式,很容易计算到,有 4 * 4 = 16个加和项

定义了g(k, tag),很重要一个点就是计算递推关系,

即,假如知道了g(k, tag),那对于计算g(k+1, Yk+1)又有什么帮助呢?首先展开g(k+1, Yk+1)

g(k+1, Yk+1)  = ∑(Y1:k) exp(Score(Y1:kYk+1, X))

= ∑(Y1:k) exp[Score(Y1:k, X) + E-tran(Yk, Yk+1) + E-emis(X, Yk+1)]

= ∑(Y1:k) exp[Score(Y1:k, X)]exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]

=  ∑(Yk)∑(Y1:k-1) exp[Score(Y1:k-1Yk, X)]exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]

= ∑(Yk) g(k, Yk)exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]

这样,就产生了g(k, tag)的递推公式,也举一个简单的例子
g(3, 'B') = g(2, 'B')exp(E-tran('B', 'B'))exp(E-emis(X, 'B')) + g(2, 'E')exp(E-tran('E', 'B'))exp(E-emis(X, 'B')) + g(2, 'M')exp(E-tran('M', 'B'))exp(E-emis(X, 'B')) + g(2, 'O')exp(E-tran('O', 'B'))exp(E-emis(X, 'B'))

在这种情况下,要计算全序列的exp分数和,就要先计算每个时间点上,以某个状态结束的全序列exp分数和,并向后递推

每次递推都要用前一个时间的全状态,组合后一个时间的每个状态,故递推一次时间复杂度为O(|T|^2)

总时间复杂度为O(n|T|^2),比起强行计算的O(|T|^n)大大减少

linear-CRF的数值优化

我们得到了重要的递推公式

g(k+1, Yk+1) = ∑(Yk) g(k, Yk)exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]

但是,大量exp的相乘,可能导致浮点运算的数值不稳定,故在代码中,会采取一些方法优化数值稳定性

首先求和可以写成对向量的求和

sum(g(k, Yk+1)exp(E-tran('B', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'E')exp(E-tran('E', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'M')exp(E-tran('M', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'O')exp(E-tran('O', Yk+1))exp(E-emis(X, Yk+1)))

进一步,调研向量中的每个分量,以第二个为例

g(k, Yk+1)exp(E-tran('B', Yk+1))exp(E-emis(X, Yk+1))

= exp(log(g(k, 'E')exp(E-tran('E', Yk+1))exp(E-emis(X, Yk+1)))) #先log后exp,数值还是一样的

= exp(log(g(k, 'E')) + E-tran('E', Yk+1) + E-emis(X, Yk+1)) #log掉后两项自带的exp,直接可以用分数相加

这个时候,可以发现原来乘积的第一项,已经由g函数变成了log g函数,但等式左边还是g函数

如果想要保持两边一致,不妨左侧也加上log,就会变成

log g(k+1, Yk+1) = log(sum(exp(vector))),其中vector = (log g(k, Yk+1)+E-tran('E', Yk+1) + E-emis(X, Yk+1))

右侧这个log(sum(exp(xxx)))的计算,在pytorch里有API,直接可以看torch.logsumexp的文档

实际上,这里都还没有讲到真正数值稳定计算的部分,只是做了恒等变换,变成方便观察的形式,

对于logsumexp的数值稳定计算,假设其内部的vector为(v1, v2, ...vn),且max(v1, v2, ...vn) = vmax,可进行如下变形

logsumexp([v1, v2, ..., vn])

= log(sum(exp([v1-vmax+vmax, v2-vmax+vmax, ..., vn-vmax+vmax])))

= log(sum([exp(vmax)exp(v1-vmax), exp(vmax)exp(v2-vmax), ... , exp(vmax)exp(vn-vmax)]))

= log(exp(vmax) * sum([exp(v1-vmax), exp(v2-vmax), ..., exp(vn-vmax)]))

= vmax + log(sum(exp[v1-vmax, v2-vmax, ..., vn-vmax]))

这样子,(v1, v2, ..., vn)中的最大分量vmax将会被直接提出来,不进行一遍exp后再log的计算,

其余的较小值进行exp的计算,使得数值偏差尽可能小,达到数值稳定的效果

linear-CRF的学习

在此前linear-CRF的计算过程中,我们可以使用递推公式(状态转移方程),使得计算指定序列P(Y | X)的时间复杂度降为O(nT^2)

但是,使用递推公式要求E-tran和E-emis函数是已知的

如果仅有观测数据集(X, Y)对,却不值得E-tran和E-emis,应如何计算E-tran和E-emis呢

实际上,当知道确切E-tran、E-emis时,计算出来的exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)可以被认为是条件概率

而不知道E-tran、E-emis时,根据初始化参数计算得的exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)则可以被认为是似然

求解E-tran、E-emis的过程,即对具体的数据集(X, Y)求使得exp(score(Y, X)) /  ∑Y' exp(score(Y'), X)最大的E-train、E-emis参数

其实就是最大似然,可以使用梯度下降等优化方法求解。实际操作中,会去最小化负对数似然,即,

minimize log(∑Y' exp(score(Y'), X)) - score(Y, X)

那具体的参数应该如何设置呢,按照流行的LSTM + linear-CRF的方法,

E-tran被直接设置为一个 T * T 的参数矩阵,矩阵代表了序列状态间的转移分数

E-emis则不直接设置为参数,而是由LSTM + dense_layer把X映射成一个feature,

feature的维度是 n * T,第一个维度代表时间(序列长度),第二维度代表每个时间状态上都有T个发射分数,

这T个发射分数则对应每个时间段的E-emis

即E-emis(Yk, X) = E-emis(Yk, feature) = feature[k, tags.index(Yk)]

这样,E-emis的参数便被暗含在LSTM + dense_layer的参数中

LSTM + linear-CRF的动机

既然如此,那么可能出现疑问,为什么E-tran可以单独设置,E-emis却不单独设置呢?

换句话说,既然单纯的linear-CRF就能完整解决一个序列预测的问题,为什么还要在前面加一个LSTM呢?

这个问题其实又可以反过来问,既然单纯的LSTM已经可以完整解决一个序列预测的问题,为什么还要在后面加一个CRF呢?

实际上,这两种方法的能力各有侧重,有刚刚好可以互补,所以在序列预测中被放在一起,成为了非常流行的结构。

LSTM的优点是具有非常强大的特征提取能力,因为它可以使用许多非线性函数、上下文关系等,构建出高维又稠密的非线性特征,

如果不使用LSTM的特征提取,像E-trans一样,设置一个纯粹参数化的E-emis矩阵,

那这种矩阵相乘的特征提取是线性的,且同时还是稀疏的,也无法结合X序列的上下文关系,效果差距非常非常大。

LSTM虽然具有以上特点,但是如果仅仅使用它进行序列预测,它则缺少一个显式地对转移关系的建模。

很明显地,LSTM只能模拟发射函数,却不能模拟转移函数,它可以提取复杂的特征,但是有时会对不合理的局部过于宽容。

例如,BMEO分词标注中(可以是分词标注、实体标注,以分词为例),

B代表词语开始,E代表词语结束,M代表词语中部,O代表单字词,

逻辑上而言,一组距离最近的B和E的中间只能存在M,而像BB、MB这种局部结构,是绝对错误的,

但LSTM更关注总体的loss最小化,不显式地对邻近转移关系进行建模,所以总是免不了出现这样的局部小错

linear-CRF则带来了一个转移矩阵参数,能够很有效地解决这个问题。

这就是LSTM与linear-CRF配合使用的原因,一句话总结,LSTM负责特征提取,linear-CRF负责邻近转移关系管理。

但是写到这里还有一个有趣的思考:虽然linear-CRF要注重转移关系,

但是E-trans是否可以像E-emis一样,使用一个复杂网络来模拟,而不直接使用一个线性矩阵呢?

这个似乎是一个很有趣的话题,到时要去算算间复杂度是否能允许这种情况下的前向计算,说不定是一个很有趣的点?

linear-CRF的预测

在linear-CRF的计算问题中,刚刚已经讨论了两种,一个是概率计算问题,一个是参数学习问题

概率计算问题知道E-tran和E-emis,要计算P(Y | X),

参数学习问题知道一批(X, Y),希望参数估计E-tran,E-emis,

最后剩下一个预测问题,也称解码问题,模型训练好以后,得到了估计的E-tran,E-emis,此时来一个新的X,最可能的Y是什么?

即,预测问题,知道E-tran,E-emis,X,要计算argmaxY P(Y | X)

这个式子可以作一些简化,

argmaxY P(Y | X)

= argmaxY exp(score(Y, X)) / ∑Y exp(score(Y), X)

= argmaxY exp(score(Y, X))  #normalize项对Y的取值不影响

= argmaxY score(Y, X)  #exp是单调函数

这三个问题,实际上跟HMM的三个问题也是完全对应的。

linear-CRF的预测问题,实际上和概率计算问题是极其类似的,

只不过前者是求最大的概率路线,后者是前全路线的概率和,

同样地,如果不使用动态规划方法,枚举的时间复杂度是O(T^n),使用后时间复杂度是O(nT^2)

然而最大概率路线的算法还有个独有的名字,也就是平常非常常见的viterbi算法233333

在前向概率计算时,我们定义的递推公式单元是

g(k, tag) = exp(Score(Y1:k-1Yk = tag, X))

思想是,只要知道了k时间点Yk为特定状态的全路线概率,就可以知道k+1时间点Yk+1位特定状态的全路线概率

同理,定义一个 h(k, tag) = argmax Y1:k-1 score(Y1:k-1Yk=tag, X)

思想是,只要知道了k时间点Yk为特定状态的最大概率路线,希望能够递推出k+1时间点Yk+1位特定状态的最大概率路线

假设,后者这个路线,在k时间点Yk要经过状态t,且k时间点Yk经过状态t的最大概率路线是Yt1:k-1,

那么后者的路线必定是Yt1:k-1,Yk=t,Yk+1,否则,不存在更大概率的路线。

h(k+1, Yk+1)

= argmax Y:k score(Y1:kYk+1, X)

= argmax Y:k score(Y1:kYkYk+1, X)

= argmax Y:k-1Yk score(Y1:k-1Yk, X) + E-tran(Yk, Yk+1) + E-emis(Yk, X)

= Y1:k-1argmaxYk (argmax Y:k-1 score(Y1:k-1Yk, X) + E-tran(Yk, Yk+1) + E-emis(Yk, X))

= Y1:k-1argmaxYk (h(k, Yk) + E-tran(Yk, Yk+1) + E-emis(Yk, X))

这样就可以求得最大的概率路线

LSTM + linear-CRF序列标注笔记的更多相关文章

  1. 基于CRF序列标注的中文依存句法分析器的Java实现

    这是一个基于CRF的中文依存句法分析器,内部CRF模型的特征函数采用 双数组Trie树(DoubleArrayTrie)储存,解码采用特化的维特比后向算法.相较于<最大熵依存句法分析器的实现&g ...

  2. BI-LSTM-CRF在序列标注中的应用

    1. 前言 在NLP中有几个经典的序列标注问题,词性标注(POS),chunking和命名实体识别(NER).序列标注器的输出可用于另外的应用程序.例如,可以利用在用户搜索查询上训练的命名实体识别器来 ...

  3. End to End Sequence Labeling via Bi-directional LSTM CNNs CRF

    来看看今日头条首席科学家的论文: End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF 使用LSTM方法进行序列标注,完成大规模标 ...

  4. TensorFlow (RNN)深度学习 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 序列标注问题 源码下载

    http://blog.csdn.net/scotfield_msn/article/details/60339415 在TensorFlow (RNN)深度学习下 双向LSTM(BiLSTM)+CR ...

  5. LSTM+CRF进行序列标注

    为什么使用LSTM+CRF进行序列标注 直接使用LSTM进行序列标注时只考虑了输入序列的信息,即单词信息,没有考虑输出信息,即标签信息,这样无法对标签信息进行建模,所以在LSTM的基础上引入一个标签转 ...

  6. HanLP《自然语言处理入门》笔记--6.条件随机场与序列标注

    笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 6. 条件随机场与序列标注 本章介绍一种新的序列标注模型条件随机场.这种模型与感知 ...

  7. Bi-LSTM+CRF在文本序列标注中的应用

    传统 CRF 中的输入 X 向量一般是 word 的 one-hot 形式,前面提到这种形式的输入损失了很多词语的语义信息.有了词嵌入方法之后,词向量形式的词表征一般效果比 one-hot 表示的特征 ...

  8. TensorFlow教程——Bi-LSTM+CRF进行序列标注(代码浅析)

    https://blog.csdn.net/guolindonggld/article/details/79044574 Bi-LSTM 使用TensorFlow构建Bi-LSTM时经常是下面的代码: ...

  9. 序列标注(BiLSTM-CRF/Lattice LSTM)

    前言 在三大特征提取器中,我们已经接触了LSTM/CNN/Transormer三种特征提取器,这一节我们将介绍如何使用BiLSTM实现序列标注中的命名实体识别任务,以及Lattice-LSTM的模型原 ...

随机推荐

  1. Android目录结构(详解)

    Android目录结构(详解) 下面是HelloAndroid项目在eclipse中的目录层次结构: 由上图可以看出项目的根目录下共有九个文件(夹),下面就这九个文件(夹)进行详解: 1.1src文件 ...

  2. HDU-1040-As Easy As A+B(各种排序)

    希尔排序 Accepted 1040 0MS 1224K 564 B G++ #include "cstdio" using namespace std; ]; int main( ...

  3. js页面--年份自动增加

    ) { document.write("-" + new Date().getFullYear()); }</script> // 大于2017年自动加上 - 年份

  4. Java IO: 字节和字符数组

    原文链接  作者: Jakob Jenkov   译者:homesick 内容列表 从InputStream或者Reader中读入数组 从OutputStream或者Writer中写数组 在java中 ...

  5. 一下午简单写个搭建Flutter开发环境,dome跑起来!

    1.下载flutter包由于需要翻墙,国内下载会出现问题,所有需要先配置一下用户环境变量. export PUB_HOSTED_URL=https://pub.flutter-io.cn export ...

  6. Django ORM必会13条之外的查询方法

    基于双下划线的查询 # 价格 大于 小于 大于等于 小于等于 filter(price__gt=') # 筛选出大于90 filter(price__lt=') # 筛选出小于90 filter(pr ...

  7. 从ArrayList的优化中想到的

    在JDK7中ArrayList有一个小的改动,使用延迟加载的思想,默认构造函数不再初始化生成一个大小为10的数组,而是将elementData先赋值为一个共享的空数组. package java.ut ...

  8. GNS3(1)——OSPF多区域配置

    GNS3(1)——OSPF多区域配置 RIP适用于中小网络,比较简单.没有系统内外.系统分区,边界等概念,用到不是分类的路由. OSPF适用于较大规模网络.它把自治系统分成若干个区域,通过系列内外路由 ...

  9. js中的函数应用

    js中的函数应用 什么是函数,函数的概念 函数就像一个黑匣子,里面的东西你都不知道,但是你提供一些材料放进去,他可以制造出你需要的东西; 可以让多个一样的功能封装组合起来,然后想执行几次就执行几次 函 ...

  10. Python使用input方法输入字母显示NameError

    如图,每次用input方法,输入数字正常,但是输入字母就会报错. 到网上查找资料之后,明白了原来在python2.7中应该用raw_input. 修改之后,代码就正常了.