条件随机场(CRF)及CRF++安装使用

1 min read

CRF简介

CRF是用来标注和划分序列结构数据的概率化结构模型。言下之意,就是对于给定的输出,标识序列Y和观测序列X,条件随机场通过定义条件概率P(Y | X),而不是联合概率分布P(X, Y)来描述模型。

设G = (V, E)为一个无向图,V为结点集合,E为无向边的结合。Y = {Yv | v ∈ V},即V中的每个结点对应于一个随机变量Yv,其取值范围为可能的标记集合{y}。如果以观察序列X为条件,每一个随机变量Yv都满足以下马尔可夫特性:p(Yv | X, Yw, w ≠ v) = p(Yv | X, Yw, w ~ v),其中,w ~ v表示两个结点在图G中是邻近结点。那么(X,Y)为一个条件随机场。

从定义中看出:CRF考虑一件东西,不但要考虑自身,还要考虑周围的情况。举个例子,我们做命名实体识别,例句:“Google的总部在硅谷”。我们知道地址是“硅谷”,其他位置的词对我们识别“硅谷”有啥帮助呢?例如,“硅谷”前面是“在”,是不是这个字后面经常接地址呢?“在”前面的词是不是应该是名词?这样的综合考虑,就是CRF中的特征选择或者叫特征模板。简要的说,CRF算法,需要解决三个问题:

  • 特征的选择。在CRF中,很重要的工作就是找特征函数,然后利用特征函数来构建特征方程。在自然语言处理领域,特征函数主要是指一个句子 s,词在句子中的位置 i,当前词的标签 l_{i},前一个词的标签 l_{i-1}。
  • 参数训练。在每一个特征函数之前,都有一个参数,也就是训练它们的权重。CRF的参数训练,可以采用梯度下降法。
  • 解码。解码问题,如果来一个句子,遍历所有可能的分割,会导致计算量过大。因此,可以采用类似viterbi这样的动态规划算法,来提高效率。

CRF++的安装

CRF++是著名的条件随机场的开源工具,也是目前综合性能最佳的CRF工具。

Windows下的安装

在Windows下的安装很简单,其实严格来讲不能说是安装。我们解压我们下载的压缩包文件到某一个目录下面。你可能会得到如下所示的文件,(版本不同,可能会有所不同。)

其中:(实际上,需要使用的就是crf_learn.exe,crf_test.exe和libcrfpp.dll,这三个文件。)

  • doc文件夹:就是官方主页的内容
  • example文件夹:有四个任务的训练数据(data)、测试数据(train.data)和模板文件(template),还有一个执行脚本文件exec.sh。
  • sdk文件夹:CRF++的头文件和静态链接库。
  • exe:CRF++的训练程序
  • exe:CRF++的测试程序
  • dll:训练程序和测试程序需要使用的静态链接库。

Linux下的安装

默认安装的位置为:/usr/local/bin

安装Python包(此部分可省略):

import CRFPP 直接向后报如下错误:

解决方案:

CRF++的使用

命令行使用

训练

这个训练过程的时间、迭代次数等信息会输出到控制台上(感觉上是crf_learn程序的输出信息到标准输出流上了),如果想保存这些信息,我们可以将这些标准输出流到文件上,命令格式如下:

从上面可以看到,训练时需要传入的参数是template_file、train_file这两个文件,输出model_file文件。四个主要参数:

  • -a CRF-L2 or CRF-L1规范化算法选择。默认是CRF-L2。一般来说L2算法效果要比L1算法稍微好一点,虽然L1算法中非零特征的数值要比L2中大幅度的小。
  • -c float 这个参数设置CRF的hyper-parameter。c的数值越大,CRF拟合训练数据的程度越高。这个参数可以调整过度拟合和不拟合之间的平衡度。这个参数可以通过交叉验证等方法寻找较优的参数。
  • -f NUM 这个参数设置特征的cut-off threshold。CRF++使用训练数据中至少NUM次出现的特征。默认值为1。当使用CRF++到大规模数据时,只出现一次的特征可能会有几百万,这个选项就会在这样的情况下起到作用。
  • -p NUM 如果电脑有多个CPU,那么那么可以通过多线程提升训练速度。NUM是线程数量。

更详细介绍:

测试

同样,与crf_learn类似,输出的结果放到了标准输出流上,而这个输出结果是最重要的预测结果信息(预测文件的内容+预测标注),同样可以使用重定向,将结果保存下来,命令为:

在这里的参数有两个:-v 和-n,都是用来显示一些信息的。-v 可以用来预测标签概率值, -n可以显示不同可能序列的概率值。对于准确率、召回率、运行效率,没有影响。

训练语料格式

训练文件

样例:

训练文件由若干个句子组成(可以理解为若干个训练样例),不同句子之间通过换行符分隔,上图中显示出的有两个句子。每个句子可以有若干组标签,最后一组标签是标注,上图中有三列,即第一列和第二列都是已知的数据,第三列是要预测的标注,以上面例子为例是,根据第一列的词语和和第二列的词性,预测第三列的标注。涉及到标注的问题,这个就是很多paper要研究的了,比如命名实体识别就有很多不同的标注集。这个超出本文范围。

测试文件

测试文件与训练文件格式自然是一样的。与SVM不同,CRF++没有单独的结果文件,预测结果通过标准输出流输出了,因此将结果重定向到文件中。结果文件比测试文件多了一列,即为预测的标签,我们可以计算最后两列,一列的标注的标签,一列的预测的标签,来得到标签预测的准确率。

模板文件

1、模板基础

模板文件中的每一行是一个模板。每个模板都是由%x[row,col]来指定输入数据中的一个token。row指定到当前token的行偏移,col指定列位置。

由上图可见,当前token是the这个单词。%x[-2,1]就就是the的前两行,1号列的元素(注意,列是从0号列开始的),即为PRP。

2、模板类型

有两种类型的模板,模板类型通过第一个字符指定。

Unigram template: first character, ‘U’

当给出一个”U01:%x[0,1]”的模板时,CRF++会产生如下的一些特征函数集合(func1 … funcN) 。

这几个函数我说明一下,%x[0,1]这个特征到前面的例子就是说,根据词语(第1列)的词性(第2列)来预测其标注(第3列),这些函数就是反应了训练样例的情况,func1反映了“训练样例中,词性是DT且标注是B-NP的情况”,func2反映了“训练样例中,词性是DT且标注是I-NP的情况”。模板函数的数量是L*N,其中L是标注集中类别数量,N是从模板中扩展处理的字符串种类。

Bigram template: first character, ‘B’

这个模板用来描述二元特征。这个模板会自动产生当前output token和前一个output token的合并。注意,这种类型的模板会产生L * L * N种不同的特征。

Unigram feature 和 Bigram feature有什么区别呢?

unigram/bigram很容易混淆,因为通过unigram-features也可以写出类似%x[-1,0]%x[0,0]这样的单词级别的bigram(二元特征)。而这里的unigram和bigram features指定是uni/bigrams的输出标签。

  • unigram: |output tag| x |all possible strings expanded with a macro|
  • bigram: |output tag| x |output tag| x |all possible strings expanded with a macro|

这里的一元/二元指的就是输出标签的情况,这个具体的例子我还没看到,example文件夹中四个例子,也都是只用了Unigram,没有用Bigarm,因此感觉一般Unigram feature就够了。

3、模板例子

这是CoNLL 2000的Base-NP chunking任务的模板例子。只使用了一个bigram template (‘B’)。这意味着只有前一个output token和当前token被当作bigram features。“#”开始的行是注释,空行没有意义。

4、样例数据

example文件夹中有四个任务,basenp,chunking,JapaneseNE,seg。前两个是英文数据,后两个是日文数据。第一个应该是英文命名实体识别,第二个应该是英文分词,第三个应该是日文命名实体识别,第四个是日文分词。

CRF++实战:中文分词

使用人民日报的语料,为了方便切割,将其中的\t替换为了空格。对于语料有嵌套的标注,例如:[中央/n 电视台/n]nt,为了处理方便,只考虑最细粒度的分词结果,即当作是 中央/n 电视台/n 两个词进行处理。

生成训练数据

通过下面python脚本,根据人民日报的语料库生成crf的测试和训练数据。原始数据中随机10%是测试数据,90%是训练数据。程序打印出来了不少调试信息,可以忽略。生成训练数据的时候,支持4tag和6tag两个格式,6tag的格式是:

S,单个词;B,词首;E,词尾;M1/M2/M,词中

4tag和6tag的区别就是没有词中顺序状态。具体代码:

使用模板

训练和测试

计算F

输出结果:

CRF++实战:地名实体识别

类似使用CRF实现分词和词性标注,地域识别也是需要生成相应的tag进行标注。这里使用的语料库是1998年1月人民日报语料集。最终学习出来的模型,对复杂的地名识别准确率(F值)非常低,推测是预料中对地名的标注多处是前后矛盾。例如  [华南/ns 地区/n]ns  标为地名实体,但是 东北/f 地区/n 确分开标注,类似错误还有很多。

生成训练和测试数据

通过一个python脚本按照一定比例生成训练和测试数据,生成过程中按照BMES对语料进行标识,具体规则如下:

转换代码:

模板文件

开始训练和测试

分类型计算F

执行结果:

参考链接:https://x-algo.cn/index.php/2016/02/29/crf-name-entity-recognition/

CRF++实战:词性标注

训练和测试的语料都是人民日报98年标注语料,训练和测试比例是10:1,直接通过CRF++标注词性的准确率:0.933882。由于训练时间较慢,此部分未进行正式测试。

生成训练和测试数据

模板文件

执行训练

计算准确率

参考链接:https://x-algo.cn/index.php/2016/02/28/crf-tagging/

CRF++实战:依存句法分析

语料是清华大学的句法标注语料,包括训练集(train.conll)和开发集合文件(dev.conll),根据模板文件生成了将近两千万个特征,由于训练较慢,以下内容未做测试。

生成训练和开发语料

依存关系本身是一个树结构,每一个词看成一个节点,依存关系就是一条有向边。语料本身格式:

数据格式说明:

通过python脚本生成所需要的训练数据和测试使用的开发数据:

模板文件

进行训练和测试过程

参考链接:

其他参考:

打赏作者
微信支付标点符 wechat qrcode
支付宝标点符 alipay qrcode

黑客马拉松 (Hackathon):POI去重记录

10月24日参加了公司举办的黑客马拉松,我们选的题目是POI的去重。给到的数据格式如下: 目标是去重重复数据。
标点符
2 min read

scikit-learn中的文本特征提取

文本分析是机器学习算法的主要应用领域。由于大部分机器学习算法只能接收固定长度的数值型矩阵特征,导致文本字符串等
标点符
2 min read

斯坦福大学自然语言处理包StanfordNLP

最近在推荐点评的影响抽取,中间涉及到分词后的词性识别,看了各种开源分词工具,主要是词性标注集存在差异,最终选定
标点符
3 min read

发表评论

电子邮件地址不会被公开。 必填项已用*标注