利用hanlp2.1优化jieba的词库

我面临一个需要快速分词的场景,调研了几个采用预训练模型的“现代”分词器,hanlp2.1的分词最为精准,但是分词速度无法满足,其他几个基于统计和传统方法的分词器分词速度可以满足要求,但是精度都不够。所以我想能不能利用hanlp对语料进行分词和统计词频,再替换掉jieba的词库。这几天利用hanlp对维基百科的中文数据进行分词统计生成jieba的词库,并使用sighan05的pku测试集进行测试,感觉效果还不错。

以下是测试结果:

# R:0.947 P:0.959 F:0.953 hanlp2.1(模型CLOSE_TOK_POS_NER_SRL_DEP_SDP_CON_ERNIE_GRAM_ZH)
# R:0.787 P:0.853 F:0.818 jieba(自带词库)
# R:0.874 P:0.896 F:0.885 jieba(40万wiki生成的词库,模型FINE_ELECTRA_SMALL_ZH)
# R:0.875 P:0.896 F:0.885 jieba(104万wiki生成的词库,模型FINE_ELECTRA_SMALL_ZH)

第一行以hanlp2.1的mtl的分词任务作为参考,后三行分别是jieba使用自带词库、40万维基百科生成词库和104万维基百科生成词库的测试结果。

从结果来看,重新训练的词库对jieba的分词性能有很大提升,但104万行语料训练出的词库仅比40万行在召回率上提升了0.1%,准确率没有提升,是不是可以认为,语料广度比较重要,但是语料覆盖的词达到一定程度以后,规模大小对于词库质量影响不大。

1 Like

HanLP1.x的双数组trie树分词是已知范围内最快的分词算法,没有之一,单线程每秒数千万字符。

的确,赞同:

即便是速度,在同一梯队中,也应该是最快的,特别是训练速度。只不过latency上神经网络必然大于线性模型而已,没有GPU的话你体会不到。

HanLP1.x的二元文法分词是速度与精度的最佳平衡。

不太理解你的选择,这就好比用航空母舰溅起的浪花去提高破旧独木舟的速度一样奇怪。

即便HanLP甩开独木舟十几个点,HanLP的准确率依然被低估了。因为HanLP的分词标准与PKU不同,比如姓氏和名字是合并的而PKU是分开的。在PKU数据集上训练,HanLP可以达到96.7的F1。在我们内部一亿字语料库上,HanLP的准确率可达98.3。

不能说明语料库大小或广度的问题,毕竟HanLP的语料库有一个亿。问题在于对方的算法太简陋了,无法拟合这么多的数据。通俗点说就是小学生的脑袋,装不下高等数学。

建议试试用HanLP1.x的感知机在你的语料库上训练,应该可以达到95%左右准确率。

感谢回复!
因为线上系统类似对web数据的搜索引擎,并不局限在某个行业领域,分词也没有标准,完全依赖人的主观感受,并且受限于一些新词或者特定地名公司名,导致有时候分词效果不佳(比如“华强北华联发店”),因此想测试下各个分词器,在其自带的词库或者模型的基础上(暂时没有人力做标注自己来训练模型),对某个评测标准测出来的效果。

我用pyhanlp调用hanlp1.8的感知机分词模型,直接对pku数据集进行测试得到一下结果:

R P F 分词器 模型
0.849 0.908 0.878 pyhanlp0.1.22(hanlp1.8) perceptron/pku199801
0.793 0.879 0.834 pyhanlp0.1.22(hanlp1.8) perceptron/large

large模型似乎表现更差,粗略查看了一下large模型分出的结果,会有几个问题:
1、“向香港特别行政区同胞、澳门特别行政区同胞”被分成了“向 香港 特别行政区 同胞 、 澳门特别行政区 同胞”,其中“香港特别行政区”和“澳门特别行政区”的分词标准不一致;
2、单独行“谢谢。”,被整个分成了一个词,没有将句号分开来;在“共同发展和共同进步的美好世界!”的切分时也出现了,“共同 发展 和 共同进步 的 美好 世界!”,这种情况在句子结尾出现的比较多;
3、“新华社记者兰红光摄”被分成了“新华社 记者 兰红光摄”,结合2来看似乎对于段末的处理存在一些问题;
4、“从1900年八国联军攻陷北京”被切分成“从 1900年八国联军 攻陷 北京”

另外我测试了一下在线学习的功能(这个功能非常好,能让我们面对分词错误时及时作出调整),下面的代码

analyzer.learn("[华强北/ns 华联发/ns 店/n]/nt")
print(analyzer.analyze("华强北华联发店"))

使用pku199801模型能够正确分成“华强北 华联发 店”,使用large模型分成了“华强北 华联发店”,看来large模型比较难“调教”。

基于上述验证,我打算调整一下sighan05的分词标准,使之更符合我们现在的需求,再做一下测试。

HanLP是有Lucene和ES的插件的。

sighan pku这个数据集本来就有提供训练集,HanLP感知机命令行直接训练,耗时仅仅几分钟。

这是个很常见的错误,第一个回复也提到过,HanLP的分词模型与sighan PKU分词标准不兼容。在不清楚一个模型的分词标准的情况下在PKU上进行比较,会导致分词标准越接近PKU的模型越占便宜。我可能每年都会回复好几遍,持续这么多年,真的累了,以后不会再回复含有这种错误的帖子了 :joy:

该分数被严重低估,因为:

  1. 你需要关闭自定义辞典,自定义辞典的颗粒度比PKU大多了。
  2. 该模型使用的语料与sighan05 pku不同。我对PKU进行了校对,与sighan05的数据集不兼容! 该语料合并了原版中的姓+名=姓名,与原版或sighan2005的分词标准并不相同,不可混用。一些常见语料的分词标准对比可参考《多标准中文分词》。为了评测该模型,你应该用校对后的PKU:https://file.hankcs.com/corpus/pku98.zip , 或者你自己用原版的语料库训练模型在原版的测试集上跑分,在sighan pku上的准确率应该在94%左右。建议你自己跑跑训练,体会一下真正的NLP:结构化感知机标注框架 · hankcs/HanLP Wiki · GitHub 。更详细的知识可参考《自然语言处理入门》

large用的语料库的分词标准,与sighan pku的差别更大了,完全不能说明large模型的准确率比pku199801模型低。所以说,你的方法从一开始就是错的,这两个分数都被严重低估了。

是的,large语料库是一个不断迭代校对低语料库。在1.x的时代,语料库本身的质量还没有现在这么高。

是的,在线学习虽然是感知机的标配,但做成这个功能应该是HanLP的首创?不过这个功能也有许多局限性,简单来说就是它没法创建新的特征,详见《自然语言处理入门》

其实两种分词结果都可以接受,你可以试试多learn几遍。

你们可以试试我校对后的pku语料库,可能比sighan05更符合大众的需求?

看来我还是应该去看看书补充一些常识,贸然想要一个开箱即用的分词器还不太现实。
基于目前获得的信息,我想请教下何博,这个做法是否可行:
1、根据我们心目中的分词标准修正一下sighan05的测试集;
2、利用hanlp2.1现成的大模型进行测试,选取出分词效果最好的模型;
3、利用2选出的模型对我们的语料进行分词获得训练集和测试集;
4、利用hanlp1.x的分词器进行训练和测试,以此获得最终的分词器。

是可行的,几点建议:

  • 分词标准上,CTB标准的定义和标注质量都比PKU更胜一筹。HanLP的细分标准乃至一亿字的语料库都以CTB为参考。与HanLP保持一致,可以搭顺风车,节省你们不少力气。
  • 1.x的分词器算法推荐感知机或二元文法。

您好,请问HanLP2.x中还有这部分的能力么,还是说要用这个能力只能使用HanLP1.x,我需要在python里引用这个能力

1.8里标准分词器就是基于二元文法的吧?果然准确性会比单用词频做计算更高。
而且相较于jieba,在利用用户词典这一块来说,标准分词器非常有意思,如果用默认配置,貌似先用核心词库把句子做一个初步切分,再通过用户词典合并,这就有了3个粒度的切分:一个是长词细分用于建索引,一个是标准分词,一个是短词合并建立短语。
我们有一个实时文本分析的应用,大致是从若干文档中抽取关键词,再对这些关键词进行聚类展现,我们希望抽取出的关键词名称能够足够完整,呈现更多的信息,如果我们预先建立一些实体和短语词库,仅用标准分词器和关键词抽取组件就够了。