【windows下CRF++的安裝與使用】
一、CRF++工具包的下載與安裝
CRF 的工具有兩種,一種是支援Linux環境的,一種是支援Windows環境的,大家可以自行根據自己的系統進行下載。
(在此我下載的是CRF++0.58,有需要的請留言。)
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
其中引數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)
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]
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
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 顯示幫助並退出
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))
操作過程如下:
追加-t操作過程: