這是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