学习自然语言处理的相关模型,一直觉得云里雾里。看了好久的《统计学习方法》,也依然无所进益。看了很多博客,也没有具体的,正确率较高分词的实现细节。于是,决定从实际的例子入手,由具体到抽象。于是选取了中文分词任务作为最大熵模型的一个例子。学习最大熵模型之前,先了解一下统计模型处理分词任务的标准方法――字标注法。
基于字标注法的分词思想
字标注法是依据汉字在词中的位置,对每个汉字标注一个符号。最简单的是2-tag标注法,该方法将词的第一个字标注为B,其他的字标注为I。比如“汉字”这个词进行标注即为“汉/B 字/I”。同理,对于已经分好词的文本:
迈向 充满 希望 的 新 世纪 ―― 一九九八年 新年 讲话 ( 附 图片 1 张 )
使用2-tag标注为:
迈/B 向/I 充/B 满/I 希/B 望/I 的/B 新/B 世/B 纪/I ―/B ―/I 一/B 九/I 九/I 八/I 年/I 新/B 年/I 讲/B 话/I (/B 附/B 图/B 片/I 1/B 张/B )/B
除了2-tag标注法,还有4-tag标注法、6-tag标注法。最常用的是4-tag标注法。4-tag标注法将单字标注为S,词的第一个字标注为B,词的最后一个字标注为E,词中间的字标注为M。
比如,对已经分好词的文本:
迈向 充满 希望 的 新 世纪 ―― 一九九八年 新年 讲话 ( 附 图片 1 张 )
使用4-tag标注为为:
迈/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
对于未分词的文本,我们的任务就是通过已经分好词的文本,也称为训练集来训练一个数学模型。然后基于该模型为文本中每一个字标注一个tag。这实际上就是为每个字符分类。
比如有文本“自然语言处理是很高端的技术”,经过模型为每个字符标注tag后,文本变成“自/B然/E语/B言/E处/B理/E是/S很/S高/B端E的/S技/B术E”。通过4-tag中各个标签的意义,很自然地我们得到分词结果“自然 语言 处理 是 很 高端 的 技术”
我们参考论文《maximumentropy chinese word segmentation》来完成分词任务。
第一步,下载工具包源码(openNLP)
由于是初学最大熵模型,我们直接使用工具包,而不自己编码。一则减少学习的难度,而则快速对最大熵模型建立感性的认知。当然最主要的原因是论文用它。
第二步,下载分词的语料(SIGHAN提供的backoff 2005语料)
选择该语料是因为众多论文都用它,很权威。
第三步,对训练集语料进行预处理,处理成满足模型需求的格式。
训练集语料原始格式如下(icwb2-data/training/pku_training.utf8):
迈向 充满 希望 的 新 世纪 ―― 一九九八年 新年 讲话 ( 附 图片 1 张 )
中共中央 总书记 、 国家 主席 江 泽民
( 一九九七年 十二月 三十一日 )
12月 31日 , 中共中央 总书记 、 国家 主席 江 泽民 发表 1998年 新年 讲话 《 迈向 充满 希望 的 新 世纪 》 。 ( 新华社 记者 兰 红光 摄 )
同胞 们 、 朋友 们 、 女士 们 、 先生 们 :
像上面训练集的文本用4-tag标注后,如下:
迈/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 央/E 总/B 书/M 记/E 、/S 国/B 家/E 主/B 席/E 江/S 泽/B 民/E
(/S 一/B 九/M 九/M 七/M 年/E 十/B 二/M 月/E 三/B 十/M 一/M 日/E )/S
1/B 2/M 月/E 3/B 1/M 日/E ,/S 中/B 共/M 中/M 央/E 总/B 书/M 记/E 、/S 国/B 家/E 主/B 席/E 江/S 泽/B 民/E 发/B 表/E 1/B 9/M 9/M 8/M 年/E 新/B 年/E 讲/B 话/E 《/S 迈/B 向/E 充/B 满/E 希/B 望/E 的/S 新/S 世/B 纪/E 》/S 。/S (/S 新/B 华/M 社/E 记/B 者/E 兰/S 红/B 光/E 摄/S )/S
同/B 胞/E 们/S 、/S 朋/B 友/E 们/S 、/S 女/B 士/E 们/S 、/S 先/B 生/E 们/S :/S
然而,openNLP支持的格式并非上面的格式,因此,需要对4-tag法标注后的文本进行处理,使之满足openNLP的训练集输入格式要求。可能有人会问,我怎么知道openNLP的训练集格式是怎么样的? 前面下载了openNLP的源码,在源码包中,就有答案。
在apache-opennlp-1.5.3-src\opennlp-maxent\samples\sports目录中,有如下的文件:
从上图的样例中就可以看到训练集的格式。
接下来就需要提取特征项了。在论文《maximum entropy chinese word segmentation》中,定义了一些特征模板,
这些特征是什么意思呢?举个简单的例子:假如我们对文本“迈向充满希望的新世纪”的第3个字“充”进行特征提取,其结果如下:
C-2=迈 C-1=向 C0=充 C1=满 C2=希
C-2C-1=迈向 C-1C0=向充 C0C1=充满 C1C2=满希
C-1C1=向满
Pu=NO
TC=4444
关于特征具体的解释说明见论文《maximum entropychinese word segmentation》
这些特征项结合标注标签就形成了一条训练样本:
C-2=迈 C-1=向 C0=充 C1=满 C2=希C-2C-1=迈向 C-1C0=向充 C0C1=充满 C1C2=满希C-1C1=向满Pu=NO TC=4444 B
对训练集中的每个字进行上述的处理,就形成了符合openNLP格式的最大熵模型训练集。部分数据截图如下:
训练集的处理是用Python写的脚本。相关的脚本可以在
https://github.com/shgy/chinese-segmenter/tree/master/maxent/scripts
中看到。
第四步,创建JavaProject,然后用openNLP工具对模型进行训练。
准备好训练集后,就可以训练模型了。训练参考apache-opennlp-1.5.3-src\opennlp-maxent\samples\sports目录中的CreateModel.java源码。相关的Java项目参看:
https://github.com/shgy/chinese-segmenter/tree/master/maxent
需要注意的是,我用的是GIS算法 cutoff=2 ,迭代200次。(没有调优,随机设置的两个值)
model = GIS.trainModel(es,200,2,USE_SMOOTHING,true);
第五步,使用训练好的模型对测试集进行分词,将分词结果保存到文件中。最后的分词结果示例如下:
(选自icwb2-data\testing\pku_test.utf8)
共同 创造 美好 的 新 世纪 ―― 二○○一 年 新年 贺词
( 二○○○年 十二月 三十一日 ) ( 附 图片 1 张 )
女士 们 , 先生 们 , 同志 们 , 朋友 们 :
第六步,使用backoff2005的测试脚本进行测试。
关于backoff2005的测试脚本如何在windows系统中使用,请参考我的另一篇博客:http://sbp810050504.blog.51cto.com/2799422/1600586
测试的结果如下:
开放测试:
=== TOTAL TRUE WORDS RECALL: 0.902
=== TOTAL TEST WORDS PRECISION: 0.908
=== F MEASURE: 0.905
=== OOV Rate: 0.058
=== OOV Recall Rate: 0.705
=== IV Recall Rate: 0.914
### pku_open_results.utf8 2638 3284 6898 12820 104372 103726 0.902 0.908 0.905 0.058 0.705 0.914
封闭测试
=== TOTAL TRUE WORDS RECALL: 0.973
=== TOTAL TEST WORDS PRECISION: 0.946
=== F MEASURE: 0.959
=== OOV Rate: 0.000
=== OOV Recall Rate: --
=== IV Recall Rate: 0.973
### pku_closed_results.utf8 32341 5 29470 61816 1109947 1142283 0.973 0.946 0.959 0.000 -- 0.973
可以看到,正确率都在90%以上。当然这与论文中达到的正确率还有很大的差距,但是并没有添加论文中的两个特征。例子也仅供学习参考,并不求达到最好的结果,毕竟中文分词目前最好的模型是CRFs。
总结:用最大熵模型进行分类,其核心点在于依赖当前字符的上下文特征,计算该字符属于每个类别(B/S/E/M)的概率分布,然后选择分布概率最大的那个类别作为当前字符的类别。这从形式上与朴素贝叶斯是一样的。对于最大熵模型而言,个人觉得特征的选择在具体问题中比算法本身更为重要。所谓Garbage In,Garbage Out正是这个道理。
本文并没有探讨最大熵的原理,就像人学习骑自行车一样,首先能骑即可,而不是要了解自行车的机械原理。有了感性的认知后,再了解信息论、概率论、高数等数学基础后,再看《统计学习方法》,就应该比较容易地看懂公式原理了。但是最重要的是能够实现出来,毕竟“Talk is cheap. Show me the code.”
相关代码可以参考https://github.com/shgy/chinese-segmenter/tree/master/maxent。
如果对此有兴趣,可加我新浪微博:@帅广应s 一起探讨,共同进步。