條件隨機場(4)——CRF++分詞訓練和預測

這是CRF的最後一篇總結。這篇總結是訓練分詞模型和預測。CRF、最大熵、隱馬爾科夫模型貌似都可以做分詞、詞性標註、命名實體識別,以前只是在hanLP裏面用這些工具,實際上是不明所以的。現在要開始弄明白其中原理,並自己訓練模型了。好吧,又囉嗦了。

先說一說CRF++的訓練和預測吧,在《條件隨機場(3)——學習和預測》中提到CRF++訓練接口爲crf_learn,預測接口爲crf_test,直接調用就可以了,官網上有調用命令。
crf_learn需要的訓練數據是有標註的,如果是分詞,就對一個詞中的每一個字進行標註,標註值爲每個字在詞中的位置,4tag標註的話,標註集合爲Y={S,B,M,E},S表示單字爲詞,B表示詞的首字,M表示詞的中間字,E表示詞的結尾字。同時,同一個詞字與標註之間用’\t’分隔,字與字之間通過’\n’分隔。句子與句子之間通過一行空白行分隔。
crf_learn接受的數據是這樣的:

邁      B
向      E
充      B
滿      E
希      B
望      E
的      S
新      S
世      B
紀      E
—       B
—       E
一      B
九      M
九      M
八      M
年      E
新      B
年      E
講      B
話      E
(      S
附      S
圖      B
片      E
1      S
張      S
)      S

中      B
共      M
中      M

crf_test接收的預測語句也不是通常的句子,之前直接將一整句話預測,預測出來的結果是

今天天氣很好,出去逛逛。    S

以爲是模型訓練問題,後來發現,是crf_test對預測數據要求的格式不同,這句話被crf_test會當做一個字來處理的。crf_test接收的預測數據是這個樣子的

共      B
同      B
創      B
造      B
美      B
好      B
的      B
新      B
世      B
紀      B
—       B
—       B
二      B
○       B
○       B
一      B
年      B
新      B
年      B
賀      B
詞      B

(      B
二      B
○       B
○       B
○       B
年      B
十      B
二      B
月      B
三      B

本笨妞採用了pku的語料來訓練。pku的語料是這種格式的:

邁向  充滿  希望  的  新  世紀  ——  一九九八年  新年  講話  (  附  圖片  1  張  )  
中共中央  總書記  、  國家  主席  江  澤民  
(  一九九七年  十二月  三十一日  )  
12月  31日  ,  中共中央  總書記  、  國家  主席  江  澤民  發表  1998年  新年  講話  《  邁向  充滿  希望  的  新  世紀  》  。  (  新華社  記者  蘭  紅光  攝  )  
同胞  們  、  朋友  們  、  女士  們  、  先生  們  :  
在  1998年  來臨  之際  ,  我  十分  高興  地  通過  中央  人民  廣播  電臺  、  中國  國際  廣播  電臺  和  中央  電視臺  ,  向  全國  各族  人民  ,  向  香港  特別  行政區  同胞  、  澳門  和  臺灣  同胞  、  海外  僑胞  ,  向  世界  各國  的  朋友  們  ,  致以  誠摯  的  問候  和  良好  的  祝願  !  

預測語料是這樣的:

共同創造美好的新世紀——二○○一年新年賀詞
(二○○○年十二月三十一日)(附圖片1張)
女士們,先生們,同志們,朋友們:
2001年新年鐘聲即將敲響。人類社會前進的航船就要駛入21世紀的新航程。中國人民進入了向現代化建設第三步戰略目標邁進的新徵程。
在這個激動人心的時刻,我很高興通過中國國際廣播電臺、中央人民廣播電臺和中央電視臺,向全國各族人民,向香港特別行政區同胞、澳門特別行政區同胞和臺灣同胞、海外僑胞,向世界各國的朋友們,致以新世紀>第一個新年的祝賀!

採用通用的4tag標註法,下面是從“我愛自然語言”的博客copy來的代碼,用於對訓練語料和預測語料進行標註,代碼如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: [email protected]
# Copyright 2014 @ YuZhen Technology
#
# 4 tags for character tagging: B(Begin), E(End), M(Middle), S(Single)

import codecs
import sys

def character_tagging(input_file, output_file):
    input_data = codecs.open(input_file, 'r', 'utf-8')
    output_data = codecs.open(output_file, 'w', 'utf-8')
    for line in input_data.readlines():
        word_list = line.strip().split()
        for word in word_list:
            if len(word) == 1:
                output_data.write(word + "\tS\n")
            else:
                output_data.write(word[0] + "\tB\n")
                for w in word[1:len(word)-1]:
                    output_data.write(w + "\tM\n")
                output_data.write(word[len(word)-1] + "\tE\n")
        output_data.write("\n")
    input_data.close()
    output_data.close()

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print "pls use: python make_crf_train_data.py input output"
        sys.exit()
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    character_tagging(input_file, output_file)

同樣,預測語料標註代碼如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: [email protected]
# Copyright 2014 @ YuZhen Technology
#
# 4 tags for character tagging: B(Begin), E(End), M(Middle), S(Single)

import codecs
import sys

def character_split(input_file, output_file):
    input_data = codecs.open(input_file, 'r', 'utf-8')
    output_data = codecs.open(output_file, 'w', 'utf-8')
    for line in input_data.readlines():
        for word in line.strip():
            word = word.strip()
            if word:
                output_data.write(word + "\tB\n")
        output_data.write("\n")
    input_data.close()
    output_data.close()

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print "pls use: python make_crf_test_data.py input output"
        sys.exit()
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    character_split(input_file, output_file)

數據處理完之後,用以下命令訓練

crf_learn -f 3 -c 4.0 example/seg/template data/tagging/pku_train_tagging.utf8 model/crf_model_pku -t

crf_learn可自定義的參數還有很多,具體參見官網。以上命令中,template是特徵模板,偷懶直接將example裏面的分詞模板拿來用了。
模板是這樣的:

# 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

特徵模板的解釋這裏最權威。Unigram和Bigram是特徵模板的類型。U00:%x[-2,0]中,U表示類型爲Unigram,00表示特徵的id,%x[-2,0]表示x(在這裏爲字)的位置,-2表示x的行偏移,0表示x的列偏移。
用pku語料爲例

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]            ==>充/滿

而這些x的標註爲

邁      B
向      E
充      B
滿      E
希      B

根據特徵模板和標註數據可以做出的特徵是這樣的:

func1 = if (output = S and feature="U00:邁") return 1 else return 0
func2 = if (output = B and feature="U00:邁") return 1 else return 0
func3 = if (output = M and feature="U00:邁") return 1  else return 0
func4 = if (output = E and feature="U00:邁") return 1  else return 0
...

對於這5個字來說,能生成(4*10)個特徵函數(L*N),4是Y的取值個數,我們是4tag標註,所以L是4,這5個字通過特徵模板,擴展成了上面的10個特徵,N是10。對於整個語料來說,L還是4,N則是整個語料根據特徵模板能擴展出來的特徵個數。
在上一篇總結訓練過程中提到,當特徵與實際的標註匹配上時,會影響該特徵對應的權重的梯度,以此來更新各特徵對應的權重。
上面只是官方給出的特徵模板,很多同道中人都直接用這個模板(我也直接用了),但是實際上模板是可以自己根據實際情況自定義的哦。

根據命令訓練完之後,得到模型crf_model_pku,然後拿模型來預測句子,命令如下:

crf_test -m model/crf_model_pku data/tagging/pku_test_tagging.utf8 >> data/result/pku_test_result

結果是這樣的

揚      B       B
帆      B       E
遠      B       B
東      B       E
做      B       S
與      B       S
中      B       B
國      B       E
合      B       B
作      B       E
的      B       S
先      B       B
行      B       E

希      B       B
臘      B       E
的      B       S
經      B       B
濟      B       E
結      B       B
構      B       E
較      B       S
特      B       B
殊      B       E
。      B       S

海      B       B
運      B       E
業      B       S
雄      B       B
踞      B       E
全      B       B

用make_crf_train_data.py相反的過程,就可以將結果通過第三列標註將詞分開了。

至此,CRF的學習基本完成了。接下來就是BiLSTM-CRF了,這個算法貌似纔是現在segment、NER、詞性標註的主流算法。不過以手上的pku、msr的數據跑LSTM,也不知道效果如何哦。先不管了,研究之後再說。

另,我手上的中文語料全部存在這裏的:https://pan.baidu.com/s/1jIu2j9W
密碼:z2b6

發佈了101 篇原創文章 · 獲贊 92 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章