基于结构化平均感知机的分词器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新版本已经发布,可以去新版本查到看使用】
结构化预测
关于结构化预测和非结构化预测的区别一张讲义说明如下
更多知识请参考Neubig的讲义《The Structured Perceptron》。
本文实现的AP分词器预测是整个句子的BMES标注序列,当然属于结构化预测问题了。
感知机
二分类
感知机的基础形式如《统计学习方法》所述,是定义在一个超平面上的线性二分类模型。作为原著第二章,实在是简单得不能再简单了。然而实际运用中,越简单的模型往往生命力越顽强。
这里唯一需要补充的是,感知机是个在线学习模型,学习一个训练实例后,就可以更新整个模型。
多分类
怎么把二分类拓展到多分类呢?可以用多个分类器,对于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
邓知龙 《基于感知器算法的高效中文分词与词性标注系统设计与实现》
相关推荐
结构化感知器是基于感知器模型的一种扩展,传统的感知器主要用于二分类问题,而结构化感知器则可以处理多类别的序列标注问题。在中文切词中,每个词语被视为一个结构,整个句子则是一个由多个结构组成的序列。目标是...
基于字的用感知机实现的中文分词系统。完全训练后对微软的测试集精度可以达到96%多。我上传的版本是完整的代码(训练和分词),大家自己用附带的微软训练数据训练就可以了,只有一个文件。 代码总的来说写的还是很...
基于 Java 的中文分词器分词效果评估对比项目。它主要实现了以下功能: 分词效果评估:用户可以通过程序对比不同分词器的分词结果,以及计算分词速度、行数完美率、行数错误率、字数完美率、字数错误率等指标。 ...
IK Analyzer 是一个开源的,基于 java 语言开发的轻量级的中文分词工具包。从 2006年 12 月推出 1.0 版开始, IKAnalyzer 已经推出了 4 个大版本。最初,它是以开源项目Luence 为应用主体的,结合词典分词和文法分析...
Java实现的中文分词程序是一种基于Java编程语言的文本处理工具,主要应用于处理中文文本,将其拆分成有意义的词汇单元,这一过程被称为分词。在自然语言处理(NLP)领域,分词是预处理阶段的关键步骤,为后续的文本...
1、lucene-core-3.6.0.jar 2、IKAnalyzer2012.jar(主jar包) 3、IKAnalyzer.cfg.xml(分词器扩展配置文件) 4、stopword.dic(停止词典) 5、IkSegmentation.java(样例类)
"java实现英文文档分词" 本资源摘要信息主要关注java实现英文文档分词的知识点, 涵盖文档读取、分词、词频统计、结果输出等方面的内容。 一、 文档读取 在该实验中,使用java的BufferedReader类来读取文档,读取...
总结来说,中文分词Java实现涉及了对中文文本的预处理、调用分词库进行分词和词性标注,以及后处理阶段的数据分析。通过这些工具,我们可以有效地处理中文文本,为后续的NLP任务提供基础数据。对于Java开发者而言,...
感知器分词软件是自然语言处理(NLP)领域中的一种常见技术,它主要用于中文文本的分词。在这个Python实现中,我们主要关注的是如何利用词的上下文特征来进行精确的分词工作。 感知器(Perceptron)是一种简单的...
我原来发过一个“python写的基于感知机的中文分词系统”的资源,那个是很完整的代码,包括训练数据等。但是代码没有任何注释,所以我又提交这个说明文档。但这个文档是用pageplayer做的(pageplayer压缩后有19M我发...
总的来说,Java实现的中文分词SimHash算法结合了Sanford分词库的分词功能和SimHash的相似度检测,为中文文本的相似度分析提供了一种高效且准确的方法。在实际应用中,这种技术广泛应用于搜索引擎的去重、推荐系统、...
Java版本的结巴分词是基于Java实现的中文分词工具,它在处理中文文本时具有高效、灵活和易用的特点。结巴分词(Jieba)最初是由Python开发的,但为了满足Java开发者的需求,也有了Java版本。本文将深入探讨Java版...
Java版的jieba分词器使得Java开发者也能轻松地在项目中集成这个强大的分词引擎。 1. **jieba分词器原理**: jieba分词基于最大匹配法(MaxMatch,MM)和HMM(Hidden Markov Model,隐马尔科夫模型)。在精确模式下...
IKAnalyzer是一个基于Java实现的全文检索分析器,主要目标是为Java开发人员提供一个简单、易用的中文分词组件。它的设计思想是灵活和可扩展,支持自定义词典和热更新,使得用户可以根据实际需求对分词结果进行调整...
**IK分词器兼容Java详解** IK分词器(Intelligent Chinese Analyzer for Java)是一款针对中文文本处理的开源分词工具,专为Java平台设计。它致力于提供高效、灵活的中文分词解决方案,广泛应用于搜索引擎、信息...
jieba分词是中文处理领域的一个著名...综上所述,jieba分词Java版项目提供了一种在Java环境下进行中文分词的解决方案,通过Eclipse导入并运行测试,你可以快速了解和使用这个工具,为你的中文信息处理任务带来便利。
protobuf-java是Google的Protocol Buffers,用于序列化结构化数据,可能用在地址数据的存储和传输中。 综上所述,这个项目是围绕中文地址处理展开的,它采用了混合分词技术来处理复杂的中文地址,并利用Double ...
word分词是一个Java实现的中文分词组件,提供了多种基于词典的分词算法,并利用ngram模型来消除歧义。 能准确识别英文、数字,以及日期、时间等数量词,能识别人名、地名、组织机构名等未登录词。 同时提供了Lucene...
标题中的“基于树的一个小型分词器实现”指的是在自然语言处理(NLP)领域,使用数据结构——树来设计和实现的一个简单的分词工具。分词是将连续的文本序列划分为有意义的词语单元,它是许多NLP任务的基础,如信息...
用java实现的,利用了lucene里面的standardAnalyzer分析器实现的分词,可以去停用词,再利用波特算法实现 词干提取 最后排序 和词频统计输出