CRF++的参数设置

特征模板

# Unigram template 模板
# unigram-features一元特征  
U00:%x[-2,0]  
U01:%x[-1,0]  
U02:%x[0,0]  
U03:%x[1,0]  
U04:%x[2,0]  
# bigram-features二元特征
U08:%x[-1,0]/%x[0,0]  
U09:%x[0,0]/%x[1,0]
# trigram-featuress三元特征
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]
# Bigram template 模板
B

T**:%x[#,#]中的T表示模板类型,两个"#"分别表示相对的行偏移与列偏移。

一共有两种模板:

第一种是Unigram template:第一个字符是U,这是用于描述unigram feature的模板。每一行%x[#,#]生成一个CRFs中的点(state)函数: f(s, o), 其中s为t时刻的的标签(output),o为t时刻的上下文.如CRF++说明文件中的示例函数:

func1 = if (output = B and feature="U02:那") return 1 else return 0

它是由U02:%x[0,0]在输入文件的第一行生成的点函数.将输入文件的第一行"代入"到函数中,函数返回1,同时,如果输入文件的某一行在第1列也是“那”,并且它的output(第2列)同样也为B,那么这个函数在这一行也返回1。

第二种是Bigram template:第一个字符是B,每一行%x[#,#]生成一个CRFs中的边(Edge)函数:f(s', s, o), 其中s'为t – 1时刻的标签.也就是说,Bigram类型与Unigram大致机同,只是还要考虑到t – 1时刻的标签.如果只写一个B的话,默认生成f(s', s),这意味着前一个output token和current token将组合成bigram features。

命令行

使用下列命令可以得到一个model文件和一个model.txt文件,后者是本文的主要研究对象。

..\..\crf_learn  -f 3 -c 4.0 template pku_training.bmes.txt model -t

参数解释如下:

可选参数 

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

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

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

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

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

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

-a, –algorithm=(CRF|MIRA)

选择训练算法,默认为CRF-L2

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

-H, –shrinking-size=INT

设置INT为最适宜的跌代变量次数 (默认20)

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

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

输出

训练过程中会输出一些信息,其意义如下:



    iter:迭代次数。当迭代次数达到maxiter时,迭代终止

    terr:标记错误率

    serr:句子错误率

    obj:当前对象的值。当这个值收敛到一个确定值的时候,训练完成

    diff:与上一个对象值之间的相对差。当此值低于eta时,训练完成

###一、CRF++工具包的下载与安装
CRF 的工具有两种,一种是支持Linux环境的,一种是支持Windows环境的,大家可以自行根据自己的系统进行下载。
CRF++0.58资源链接:https://pan.baidu.com/s/1GKjKYSsgw46pLqjyMwf23A 密码:oj1q

在windows下安装很简单,解压到某目录下即可。
在此附CRF理论及工具包的使用讲解:https://wenku.baidu.com/view/5f805e0d8762caaedd33d491.html

windows下解压得到如下:


doc文件夹:就是官方主页的内容
example文件夹:有四个任务的训练数据(test.data)、测试数据(train.data)和模板文件(template),还有一个执行脚本文件exec.sh。
sdk文件夹:CRF++的头文件和静态链接库。
clr_learn.exe:CRF++的训练程序
crl_test.exe:CRF++的测试程序
libcrffpp.dll:训练程序和测试程序需要使用的静态链接库。
实际上,需要使用的就是crf_learn.exe,crf_test.exe和libcrfpp.dll,这三个文件。
###2 测试和体验
在源码包中有example,可以执行./exec.sh体验一下(Linux下的操作)
exec.sh #训练和测试脚本
template #模板文件
test.data #测试文件
train.data #训练文件

###3.生成训练数据【中文】
下载人民日报语料,对于语料有嵌套的标注,例如:[中央/n 电视台/n]nt,为了处理方便,只考虑最细粒度的分词结果,即当作是 中央/n 电视台/n 两个词进行处理。

通过下面python脚本,根据人民日报的语料库生成crf的测试和训练数据。原始数据中随机10%是测试数据,90%是训练数据。

两种格式:
6tag:S,单个词;B,词首;E,词尾;M1/M2/M,词中
4tag:S,单个词;B,词首;E,词尾;M,词中

运行Python脚本示例:

C:\Users\Administrator>python F:\pycodes\NLP\trainDataGenerate.py 4
1
其中参数4是传给了sys.argv[1] ,原因见:Python中 sys.argv[]的用法简明解释,因此执行main方法中的else部分。

# -*- coding: utf8  -*-
 
import sys
 
home_dir = "F:/pycodes/NLP/people_daily//"
def splitWord(words):
    uni = words.decode('utf-8')
    li = list()    
    for u in uni:
        li.append(u.encode('utf-8'))
    return li    
 
#4 tag
#S/B/E/M
def get4Tag(li):
    length = len(li)
    #print length
    if length   == 1:
        return ['S']
    elif length == 2:
        return ['B','E']
    elif length > 2:
        li = list()
        li.append('B')
    for i in range(0,length-2):
        li.append('M')
    li.append('E')
    return li

#6 tag
#S/B/E/M/M1/M2
def get6Tag(li):
    length = len(li)
    #print length
    if length   == 1:
        return ['S']
    elif length == 2:
        return ['B','E']
    elif length == 3:
        return ['B','M','E']
    elif length == 4:
        return ['B','M1','M','E']
    elif length == 5:
        return ['B','M1','M2','M','E']
    elif length > 5:
        li = list()
        li.append('B')
        li.append('M1')
        li.append('M2')
    for i in range(0,length-4):
        li.append('M')
    li.append('E')
    return li
 
def saveDataFile(trainobj,testobj,isTest,word,handle,tag):
    if isTest:
        saveTrainFile(testobj,word,handle,tag)
    else:
        saveTrainFile(trainobj,word,handle,tag)
 
def saveTrainFile(fiobj,word,handle,tag): 
    if len(word) > 0:
        wordli = splitWord(word)
        if tag == '4':
            tagli = get4Tag(wordli)
        if tag == '6':
            tagli = get6Tag(wordli)
        for i in range(0,len(wordli)):
            w = wordli[i]
            h = handle
            t = tagli[i]
            fiobj.write(w + '\t' + h + '\t' + t + '\n')
    else:
    #print 'New line'
        fiobj.write('\n')
 
#B,M,M1,M2,M3,E,S
def convertTag(tag):    
    fiobj    = open( home_dir + 'people-daily.txt','r')
    trainobj = open( home_dir + tag + '.train.data','w' )
    testobj  = open( home_dir + tag + '.test.data','w')
 
    arr = fiobj.readlines()
    i = 0
    for a in arr:
        i += 1
        a = a.strip('\r\n\t ')
        if a=="":continue
        words = a.split(" ")
        test = False
        if i % 10 == 0:
            test = True
        for word in words:
            # print "---->", word
            word = word.strip('\t ')
            if len(word) > 0:        
                i1 = word.find('[')
            if i1 >= 0:
                word = word[i1+1:]
            i2 = word.find(']')
            if i2 > 0:
                w = word[:i2]
            word_hand = word.split('/')
            # print "----",word
            w,h = word_hand
            #print w,h
            if h == 'nr':    #ren min
                #print 'NR',w
                if w.find('·') >= 0:
                    tmpArr = w.split('·')
                    for tmp in tmpArr:
                        saveDataFile(trainobj,testobj,test,tmp,h,tag)
                continue
            if h != 'm':
                saveDataFile(trainobj,testobj,test,w,h,tag)
            
            if h == 'w':
                saveDataFile(trainobj,testobj,test,"","",tag) #split
 
    trainobj.flush()
    testobj.flush()
 

# sys.argv[0]表示代码本身文件路径
# Sys.argv[ ]其实就是一个列表,里边的项为用户输入的参数,关键就是要明白这参数是从程序外部输入的

if __name__ == '__main__':    
    if len(sys.argv) < 2:
        print 'tag[6,4] convert raw data to train.data and tag.test.data'
    else:
        tag = sys.argv[1]
        convertTag(tag)
    # print len(sys.argv)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
####4、模板
template格式
a) 特征选取的行是相对的,列是绝对的,一般选取相对行前后m行,选取n-1列(假设语料总共有n列),特征表示方法为:%x[行,列],行列的初始位置都为0。

# Unigram  
U00:%x[-1,0]  
U01:%x[0,0]  
U02:%x[1,0]  
U03:%x[-1,0]/%x[0,0]  
U04:%x[0,0]/%x[1,0]  
U05:%x[-1,0]/%x[1,0] 
1
2
3
4
5
6
7
###5、训练和测试

#!/bin/sh  
crf_learn -f 3 -c 4.0 template 4_train.data 4_model > 4_train.rst  
crf_test -m 4_model 4_test.data > 4_test.rst
1
2
3
crf_learn <模板> <训练语料> <模板文件> > <训练输出文件>
其中模板和训练语料是需要事先准备好的,模板文件(4_model)在训练完成后生成。
通过追加-t可以得到CRF模型文件。
crf_learn -f 3 -c 4.0 template 4_train.data 4_model -t > 4_train.txt 可以得到4_model.txt这个CRF模型文件。
crf_test <模板文件> <测试语料> > <测试输出文件>
测试用到训练过程的模板文件。

可选参数说明:

-f, –freq=INT 使用属性的出现次数不少于INT(默认为1)
-m, –maxiter=INT 设置INT为LBFGS的最大迭代次数 (默认10k)
-c, –cost=FLOAT 设置FLOAT为代价参数,过大会过度拟合 (默认1.0)
-e, –eta=FLOAT 设置终止标准FLOAT(默认0.0001)
-C, –convert 将文本模式转为二进制模式
-t, –textmodel 为调试建立文本模型文件
-a, –algorithm=(CRF|MIRA)  选择训练算法,默认为CRF-L2
-p, –thread=INT线程数(默认1),利用多个CPU减少训练时间
-H, –shrinking-size=INT 设置INT为最适宜的迭代变量次数 (默认20)
-v, –version 显示版本号并退出
-h, –help 显示帮助并退出
1
2
3
4
5
6
7
8
9
10
11
###6、计算F值

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sys
 
if __name__=="__main__":
    try:
        file = open(sys.argv[1], "r")
    except:
        print "result file is not specified, or open failed!"
        sys.exit()
    
    wc_of_test = 0
    wc_of_gold = 0
    wc_of_correct = 0
    flag = True
    
    for l in file:
        if l=='\n': continue
    
        _, _, g, r = l.strip().split()
     
        if r != g:
            flag = False
    
        if r in ('E', 'S'):
            wc_of_test += 1
            if flag:
                wc_of_correct +=1
            flag = True
    
        if g in ('E', 'S'):
            wc_of_gold += 1
 
    print "WordCount from test result:", wc_of_test
    print "WordCount from golden data:", wc_of_gold
    print "WordCount of correct segs :", wc_of_correct
            
    #查全率
    P = wc_of_correct/float(wc_of_test)
    #查准率,召回率
    R = wc_of_correct/float(wc_of_gold)
    
    print "P = %f, R = %f, F-score = %f" % (P, R, (2*P*R)/(P+R))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
操作过程如下:

追加-t操作过程:


参考:
CRF++中文分词使用指南
条件随机场
CRF++模型格式说明
CRF++的使用
CRF++代码分析
--------------------- 
作者:feng_zhiyu 
来源:CSDN 
原文:https://blog.csdn.net/feng_zhiyu/article/details/80793316 
版权声明:本文为博主原创文章,转载请附上博文链接!

https://blog.csdn.net/lilong117194/article/details/81204349

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值