Python 条件随机场(CRF) 序列标注 介绍及工具简单用法解析

CRF简介

  Conditional Random Field:条件随机场,一种机器学习技术。

  CRF由Lafferty等人于2001年提出,结合了最大熵模型和隐马尔可夫模型的特点,是一种无向图模型,近年来在分词、词性标注和命名实体识别等序列标注任务中取得了很好的效果。条件随机场是一个典型的判别式模型,其联合概率可以写成若干势函数联乘的形式,其中最常用的是线性链条件随机场。

  感兴趣的同学可以去参看此贴,对CRF的原理进行了详细的介绍:
  如何用简单易懂的例子解释条件随机场(CRF)模型?它和HMM有什么区别?

CRF++ 用法介绍

安装

  在Linux或者Mac OS系统下,下载C++源代码安装包(CRF++-0.58.tar.gz)之后,按照如下步骤进行安装:

  • CD命令进入到代码主目录后,依次输入以下命令configuremake(sudo) make install就可以完成C++库的安装。
    注:最后一条需要管理员模式,输入”sudo”进入

  • 再进入到子目录python下,安装python包:

    python setup.py build
    (sudo) python setup.py install
  • 安装完毕之后,可以在python解释器下测试:import CRFPP, 如果不报错,则准备工作就绪。

用法介绍

  在CRF++ 的example目录下有个seg目录,这个seg目录对应的是一个日文分词的样例,我们后续的工作可以按照这个案例来进行。在安装包目录下,执行cd example/seg命令后,切换到seg目录后,发现有4个文件:

exec.sh(执行脚本)
template(特征模板)
test.data(测试集)
train.data(训练集)    

  有了这4个文件,我们可以做得事情就比较简单,只要按测试集,训练集的格式准备数据就可以了,特征模板和执行脚本可以套用,不过这里简单解读一下这几个CRF++文件。首先来看训练集:

毎 k   B
日 k   I
新 k   I
聞 k   I
社 k   I
特 k   B
別 k   I
顧 k   B
問 k   I 

  这里第一列是待分词的日文字,第二列暂且认为是词性标记,第三列是字标注中的2-tag(B, I)标记,这个很重要,对于我们需要准备的训练集,主要是把这一列的标记做好,不过需要注意的是:列与列之间是制表符“\t”隔开的,否则会导致feature_index.cpp(126) [max_size == size] inconsistent column size错误。

  再来看测试集的格式:

よ h   I
っ h   I
て h   I
私 k   B
た h   B
ち h   I
の h   B
世 k   B

  同样也有3列,第一列是日文字,第二列第三列与上面是相似的,不过在测试集里第三列主要是占位作用。事实上,CRF++对于训练集和测试集文件格式的要求是比较灵活的,首先需要多列,但不能不一致,既在一个文件里有的行是两列,有的行是三列;其次第一列代表的是需要标注的“字或词”,最后一列是输出位”标记tag”,如果有额外的特征,例如词性什么的,可以加到中间列里,所以训练集文件最少要有两列
  接下里我们再来详细的分析一下特征模板文件:
  

# Unigram
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-2,0]/%x[-1,0]/%x[0,0]
U06:%x[-1,0]/%x[0,0]/%x[1,0]
U07:%x[0,0]/%x[1,0]/%x[2,0]
U08:%x[-1,0]/%x[0,0]                                          
U09:%x[0,0]/%x[1,0]

# Bigram
B

关于CRF++中特征模板的说明和举例,请大家参考官方文档上的“Preparing feature templates”这一节,而以下部分的说明拿上述日文分词数据举例。在特征模板文件中,每一行(如:U00:%x[-2,0])代表一个特征,而宏“%x[行位置,列位置]”则代表了相对于当前指向的token的行偏移和列偏移的相对位置,以上述训练集为例,如果当前扫描到“新 k I”这一行:

毎 k   B
日 k   I
新 k   I   <== 扫描到这一行,代表当前位置
聞 k   I
社 k   I
特 k   B
別 k   I
顧 k   B
問 k   I

  那么依据特征模板文件抽取的特征如下:

# Unigram
U00:%x[-2,0] ==> 毎
U01:%x[-1,0] ==> 日
U02:%x[0,0]  ==> 新
U03:%x[1,0]  ==> 聞
U04:%x[2,0]  ==> 社
U05:%x[-2,0]/%x[-1,0]/%x[0,0] ==> 每/日/新
U06:%x[-1,0]/%x[0,0]/%x[1,0]  ==> 日/新/聞
U07:%x[0,0]/%x[1,0]/%x[2,0]   ==> 新/聞/社
U08:%x[-1,0]/%x[0,0]          ==> 日/新
U09:%x[0,0]/%x[1,0]           ==> 新/聞

# Bigram
B

  CRF++里将特征分成两种类型,一种是Unigram的,即“U”起头,另外一种是Bigram的,即“B”起头。
  对于Unigram的特征,假如一个特征模板是”U01:%x[-1,0]“, CRF++会自动的生成一组特征函数(func1 … funcN) 集合:

func1 = if (output = B and feature="U01:日") return 1 else return 0
func2 = if (output = I and feature="U01:日") return 1 else return 0
....
funcXX = if (output = B and feature="U01:問") return 1  else return 0
funcXY = if (output = I and feature="U01:問") return 1  else return 0

  生成的特征函数的数目 = (L * N),其中L是输出的类型的个数(这里是B,I这两个tag),N是通过模板扩展出来的所有单个字符串(特征)的个数,这里指的是在扫描所有训练集的过程中找到的日文字(特征)。

  我们可以根据自己需要自行添加特征,例如,要将第二列的特征加入训练:
 

# Unigram
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-2,0]/%x[-1,0]/%x[0,0]
U06:%x[-1,0]/%x[0,0]/%x[1,0]
U07:%x[0,0]/%x[1,0]/%x[2,0]
U08:%x[-1,0]/%x[0,0]
U09:%x[0,0]/%x[1,0]

U10:%x[-2,1]
U11:%x[-1,1]
U12:%x[0,1]
U13:%x[1,1]
U14:%x[2,1]
U15:%x[-2,1]/%x[-1,1]
U16:%x[-1,1]/%x[0,1]
U17:%x[0,1]/%x[1,1]
U18:%x[1,1]/%x[2,1]

# Bigram
B

  最后我们再来看一下执行脚本:

#!/bin/sh
../../crf_learn -f 3 -c 4.0 template train.data model
../../crf_test -m model test.data

../../crf_learn -a MIRA -f 3 template train.data model
../../crf_test -m model test.data
rm -f model

  参数解释如下:

可选参数 

-f, –freq=INT 使用属性的出现次数不少于INT(默认为1)

-m, –maxiter=INT 设置INTLBFGS的最大迭代次数 (默认10k)

-c, –cost=FLOAT 设置FLOAT为代价参数,过大会过度拟合 (默认1.0)

-e, –eta=FLOAT 设置终止标准FLOAT(默认0.0001)

-C, –convert 将文本模式转为二进制模式

-t, –textmodel 为调试建立文本模型文件

-a, –algorithm=(CRF-L2/CRF-L1/MIRA) 选择训练算法,默认为CRF-L2

-p, –thread=INT 线程数(默认1),利用多个CPU减少训练时间

-H, –shrinking-size=INT 设置INT为最适宜的跌代变量次数 (默认20)

-v, –version 显示版本号并退出

-h, –help 显示帮助并退出

  执行脚本告诉了我们如何训练一个CRF模型,以及如何利用这个模型来进行测试,执行这个脚本之后,对于输入的测试集,输出结果多了一列,也就是倒数第二列:

よ h   I   B
っ h   I   I
て h   I   B
私 k   B   B
た h   B   B
ち h   I   I
の h   B   B
世 k   B   B
代 k   I   I

  而这一列才是模型预测的改字的标记tag,也正是我们所需要的结果。到此为止,关于日文分词样例的介绍已经完毕。接下来举个简单的中文分词例子:

示例

  首先需要将训练语料处理成对应的格式。假设我们的训练语料如下:

“/S 人/B 们/E 常/S 说/S 生/B 活/E 是/S  一/S 部/S ...

  处理算法这里就不赘诉了,处理后的格式如下:

“ S
人 B
们 E
常 S
说 S
生 B
活 E
是 S
一 S
部 S
...

  有了训练语料,就可以利用CRF++来训练模型了,执行如下命令:

crf_learn -f 3 -c 4.0 template train2.data(语料名) crf_model(模型名)

  有了模型,现在我们需要做得还是准备一份CRF++用的测试语料,然后利用CRF++的测试工具crf_test进行字标注。同样,测试语料也要处理成和训练语料相同的格式。处理完测试语料后,输入如下命令:

crf_test -m model test.data > result.txt

  这样,结果就保存在名为“result.txt”的文件中了。是不是很简单,赶紧去试试吧。

你可能感兴趣的:(Python 条件随机场(CRF) 序列标注 介绍及工具简单用法解析)