1. 程式人生 > >【windows下CRF++的安裝與使用】

【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 設定INTLBFGS的最大迭代次數 (預設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操作過程:
這裡寫圖片描述