中文分词模型之最大熵

       学习自然语言处理的相关模型,一直觉得云里雾里。看了好久的《统计学习方法》,也依然无所进益。看了很多博客,也没有具体的,正确率较高分词的实现细节。于是,决定从实际的例子入手,由具体到抽象。于是选取了中文分词任务作为最大熵模型的一个例子。学习最大熵模型之前,先了解一下统计模型处理分词任务的标准方法——字标注法。

 

基于字标注法的分词思想

字标注法是依据汉字在词中的位置,对每个汉字标注一个符号。最简单的是2-tag标注法,该方法将词的第一个字标注为B,其他的字标注为I。比如“汉字”这个词进行标注即为“汉/B /I”。同理,对于已经分好词的文本:

迈向  充满  希望      世纪  ——  一九九八年  新年  讲话      图片       

使用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  /B  /B  /B

 

除了2-tag标注法,还有4-tag标注法、6-tag标注法。最常用的是4-tag标注法。4-tag标注法将单字标注为S,词的第一个字标注为B,词的最后一个字标注为E,词中间的字标注为M

比如,对已经分好词的文本:

迈向  充满  希望      世纪  ——  一九九八年  新年  讲话      图片       

使用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  /S  /S  /S

 

对于未分词的文本,我们的任务就是通过已经分好词的文本,也称为训练集来训练一个数学模型。然后基于该模型为文本中每一个字标注一个tag。这实际上就是为每个字符分类。

 

比如有文本“自然语言处理是很高端的技术”,经过模型为每个字符标注tag后,文本变成“自/B/E/B/E/B/E/S/S/BE/S/BE”。通过4-tag中各个标签的意义,很自然地我们得到分词结果“自然  语言  处理     高端   技术”

 

分词的具体步骤

我们参考论文《maximumentropy chinese word segmentation》来完成分词任务。

第一步,下载工具包源码(openNLP)

       由于是初学最大熵模型,我们直接使用工具包,而不自己编码。一则减少学习的难度,而则快速对最大熵模型建立感性的认知。当然最主要的原因是论文用它。

第二步,下载分词的语料(SIGHAN提供的backoff 2005语料)

       选择该语料是因为众多论文都用它,很权威。

第三步,对训练集语料进行预处理,处理成满足模型需求的格式。

训练集语料原始格式如下(icwb2-data/training/pku_training.utf8)

迈向  充满  希望      世纪  ——  一九九八年  新年  讲话      图片       

中共中央  总书记    国家  主席    泽民 

  一九九七年  十二月  三十一日   

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  /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

/B  /M  /E  /B  /M  /E  /S  /B  /M  /M  /E  /B  /M  /E  /S  /B  /E  /B  /E  /S  /B  /E  /B  /E  /B  /M  /M  /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目录中,有如下的文件:

                           

wKiom1S8VynTSI1DAAHRETQbdnE553.jpg

从上图的样例中就可以看到训练集的格式。

 

接下来就需要提取特征项了。在论文《maximum entropy chinese word segmentation》中,定义了一些特征模板,

wKioL1S8V_vSsqHSAAC3GL05uHk345.jpg

这些特征是什么意思呢?举个简单的例子:假如我们对文本“迈向充满希望的新世纪”的第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格式的最大熵模型训练集。部分数据截图如下:

wKiom1S8Vyqw6_RoAAMYF1mN9SI323.jpg

训练集的处理是用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 InGarbage Out正是这个道理。

本文并没有探讨最大熵的原理,就像人学习骑自行车一样,首先能骑即可,而不是要了解自行车的机械原理。有了感性的认知后,再了解信息论、概率论、高数等数学基础后,再看《统计学习方法》,就应该比较容易地看懂公式原理了。但是最重要的是能够实现出来,毕竟“Talk is cheap. Show me the code.” 

相关代码可以参考https://github.com/shgy/chinese-segmenter/tree/master/maxent

如果对此有兴趣,可加我新浪微博:@帅广应s 一起探讨,共同进步。