基于结构化平均感知机的分词器Java实现

基于结构化平均感知机的分词器Java实现算法

做者:hankcs性能

最近高产似母猪,写了个基于AP的中文分词器,在Bakeoff-05的MSR语料上F值有96.11%。最重要的是,只训练了5个迭代;包含语料加载等IO操做在内,整个训练一共才花费23秒。应用裁剪算法去掉模型中80%的特征后,F值才降低不到0.1个百分点,体积控制在11兆。若是训练一百个迭代,F值可达到96.31%,训练时间两分多钟。学习

数据在一台普通的IBM兼容机上获得:优化

本模块已集成到HanLP 1.6以上版本开源,文档位于项目wiki中,欢迎使用!【hanlp1.7新版本已经发布,能够去新版本查到看使用spa

结构化预测设计

关于结构化预测和非结构化预测的区别一张讲义说明以下:blog

更多知识请参考Neubig的讲义《The Structured Perceptron》。文档

 

本文实现的AP分词器预测是整个句子的BMES标注序列,固然属于结构化预测问题了。原型

感知机it

二分类

感知机的基础形式如《统计学习方法》所述,是定义在一个超平面上的线性二分类模型。做为原著第二章,实在是简单得不能再简单了。然而实际运用中,越简单的模型每每生命力越顽强。

这里惟一须要补充的是,感知机是个在线学习模型,学习一个训练实例后,就能够更新整个模型。

多分类

怎么把二分类拓展到多分类呢?能够用多个分类器,对于BMES这4种分类,就是4个感知机了。每一个感知机分别负责分辨“是否是B”“是否是M”“是否是E”“是否是S”这4个二分类问题。在实现中,固然没必要傻乎乎地建立4个感知机啦。把它们的权值向量拼接在一块儿,就能够输出“是B的分数”“是M的分数”“是E的分数”“是S的分数”了。取其最大者,就能够初步实现多分类。但在分词中,还涉及到转移特征和HMM-viterbi搜索算法等,留到下文再说。

平均感知机

平均感知机指的是记录每一个特征权值的累计值,最后平均得出最终模型的感知机。为何要大费周章搞个平均算法出来呢?

前面提到过,感知机是个在线学习模型,学习一个训练实例后,就能够更新整个模型。假设有10000个实例,模型在前9999个实例的学习中都完美地获得正确答案,说明此时的模型接近完美了。但是最后一个实例是个噪音点,朴素感知机模型预测错误后直接修改了模型,致使前面9999个实例预测错误,模型训练前功尽弃。

有什么解决方案呢?一种方案是投票式的,即记录每一个模型分类正确的次数,做为它的得票。训练结束时取得票最高的模型做为最终模型。但这种算法是不实际的,若是训练5个迭代,10000个实例,那么就须要储存50000个模型及其票数,太浪费了。

 

最好用的方法是平均感知机,将这50000个模型的权值向量累加起来,最后除以50000就好了,这样任什么时候候咱们只额外记录了一个累加值,很是高效了。关于平均感知机的详情请参考《200行Python代码实现感知机词性标注器》。虽然那篇文章是讲解词性标注的,但相信做为万物灵长的读者必定拥有触类旁通的泛化能力。

语言模型

HMM

咱们不是在讲解感知机分词吗?怎么跟HMM扯上关系了?

其实任何基于序列标注的分词器都离不开隐马尔科夫链,即BMES这四个标签之间的Bigram(乃至更高阶的n-gram)转移几率。做为其中一员的AP分词器,也不例外地将前一个字符的标签做为了一个特征。该特征对预测当前的标签毫无疑问是有用的,好比前一个标签是B,当前标签就毫不多是S。

这种相似于y[i-1]的特征在线性图模型中通常称为转移特征,而那些不涉及y[i-1]的特征一般称为状态特征。

viterbi

因为AP分词器用到了转移特征,因此确定少不了维特比搜索。从序列全体的准确率考虑,搜索也是必不可少的。给定隐马尔可夫模型的3要素,我用Java写了一段“可运行的伪码”:

 

上述实现是个重视条理胜于效率的原型,古人云“过早优化是魔鬼”。相信聪明的读者必定能看懂这里面在干什么。

特征提取

定义字符序列为x,标注序列为y。

转移特征

转移特征就是上面说的y[i-1]。

状态特征

我一共使用了7种状态特征:

在邓知龙的《基于感知器算法的高效中文分词与词性标注系统设计与实现》中提到,要利用更复杂的字符n-gram、字符类别n-gram、叠字、词典等特征。但在个人实践中,除了上述7种特征外,我每减小一个特征,个人AP分词器的准确率就提升一点,也许是语料不一样吧,也许是特征提取的实现不一样。总之,主打精简、高效。

训练

迭代数目其实不须要太多,在3个迭代内模型基本就收敛了:

 

第4个迭代彷佛帮了倒忙,但万幸的是,咱们使用的是平均感知机。权值平均以后,模型的性能反而有所提高。

此时模型大小:

模型裁剪

《基于感知器算法的高效中文分词与词性标注系统设计与实现》提到的模型裁剪策略是有效的,我将压缩率设为0.2,即压缩掉20%的特征,模型准确率没有变化:

因为我使用了随机shuffle算法,因此每次训练准确率都略有微小的上下波动。此时能够看到模型裁剪过程花了额外的1分钟,裁剪完毕后准确率维持96.11不变。

此时模型大小:

 

裁减掉50%如何呢?

 

此时模型大小:

 

可见裁剪了80%的特征,体积从54M降低到11M,模型的准确率才跌了不到0.1个百分点!这说明大部分特征都是没用的,特征裁剪很是有用、很是好用!

Reference

邓知龙 《基于感知器算法的高效中文分词与词性标注系统设计与实现》

相关文章
相关标签/搜索