最近优化NER识别过程中,需要分词边界信息,现有的开源分词系统HANLP没有垂直领域词典的支持,效果差强人意。赶上pku开源了pkuseg,利用一些时间学习一下,记录一下个人一点见解。
github地址
不得不说pku对于开发者非常友好,包括训练、场景模型切换(msra/新闻领域、ctb8/混合领域、weibo/网页领域)、硬编码词典加载、模型支持对文件的处理、支持python多进程处理、提供预训练好的模型。
论文(Jingjing Xu, Xu Sun. Dependency-based Gated Recursive Neural Network for Chinese Word Segmentation. ACL 2016: 567-572)是12年,有兴趣的可以去网上看一下,基于CRF来训练的,得分函数中不仅结合了unigram和bigram等word feature、重复出现词特征,还加入了High Dimensional Edge Features 也就是观察序列的转换特征,以往传统的CRF只有隐藏状态的转移,代码中CRF模板(7.c-1c.路.之 316457,第一位为特征在整个特征组的位置,c-1c:前一个字,当前字,316457特征的索引),可以一同探讨。CRF优化方面论文中提出了基于词频自适应随机梯度下降方法,词频越高,梯度优化步调放缓。损失函数方面加入L2正则化。论文另一个创新之处为此模型还可以用于新词发现,结合CRF条件概率(p>0.5)和现有词典。实验结果在各个竞赛数据集(微软研究院、香港城市大学、北京大学)上取得很好的P值及F值。对于处理速度方面,在个人笔记本上,1045篇新闻文章,10进程,220s(和个人硬件环境有关)。以下为测试代码,主要参考的github文档。
# seg = pkuseg.pkuseg()
# text = '四川人用普通话与川普通电话'
# text = '欢迎 新老师生前来就餐'
#text = '沿海南方向前进'
# text = '黑天鹅和灰犀牛是两个突发事件'
# text = '统计局局长宁长吉'
# text = seg.cut(text)
# print(text)
#带有用户自定义词典的
# user_dictionary = ['马桶LV']
# seg = pkuseg.pkuseg(user_dict=user_dictionary)
# text = seg.cut('王欣发布马桶LVapp')
# print(text)
# 新闻分词模型、网络文本模型、微博数据模型
seg = pkuseg.pkuseg(model_name='../pkuseg/models/test')
text = seg.cut('沿海南方向前进')
print(text)
#对文件进行分词
# from datetime import datetime
# seg = pkuseg.pkuseg(model_name='../pkuseg/models/msra')
# start = datetime.now()
# pkuseg.test('./data.txt','./data_seg.txt',nthread = 10)
# end = datetime.now()
# print(end - start)
#训练模型
# pkuseg.train('./data_seg.txt','./data_seg.txt','./models',nthread=20)
本人在64G服务器上训练,训练过程进程,20进程,语料大小为74M,加载完成消耗内存61.7%。以下为训练log,仅供参考,还没有训练完成。
length = 1 : 2646488
length = 2 : 2476114
length = 3 : 294463
length = 4 : 132263
length = 5 : 47769
length = 6 : 28708
length = 7 : 31896
length = 8 : 26539
length = 9 : 29071
length = 10 : 31487
length = 11 : 33062
length = 12 : 33925
length = 13 : 33907
length = 14 : 34027
length = 15 : 34071
getting feature set
file /tmp/tmp64i03_wp/.pkuseg/temp/train.txt converting…
file converting…
file converting…
start training…
reading training & test data…
done! train/test data sizes: 868968/1025
r: 1
iter1 diff=1.00e+100 train-time(sec)=33362.17 f-score=89.92%