Hanlp中使用纯JAVA实现CRF分词

释放双眼,带上耳机,听听看~!

与基于隐马尔可夫模型的最短路径分词、N-
最短路径分词相比,基于条件随机场(
CRF
)的分词对未登录词有更好的支持。本文(
HanLP
)使用纯
Java
实现
CRF
模型的读取与维特比后向解码,内部特征函数采用 双数组
Trie

(DoubleArrayTrie)
储存,得到了一个高性能的中文分词器。

开源项目****

本文代码已集成到HanLP
中开源:
http://hanlp.com/

CRF
简介
****

CRF
是序列标注场景中常用的模型,比
HMM
能利用更多的特征,比
MEMM
更能抵抗标记偏置的问题。

Hanlp中使用纯JAVA实现CRF分词

CRF
训练
****

这类耗时的任务,还是交给了用C++
实现的
CRF++
。关于
CRF++
输出的
CRF
模型,请参考《
CRF++
模型格式说明》。

CRF
解码
****

解码采用维特比算法实现。并且稍有改进,用中文伪码与白话描述如下:

首先任何字的标签不仅取决于它自己的参数,还取决于前一个字的标签。但是第一个字前面并没有字,何来标签?所以第一个字的处理稍有不同,假设第0
个字的标签为
X
,遍历
X
计算第一个字的标签,取分数最大的那一个。

如何计算一个字的某个标签的分数呢?某个字根据CRF
模型提供的模板生成了一系列特征函数,这些函数的输出值乘以该函数的权值最后求和得出了一个分数。该分数只是“点函数”的得分,还需加上“边函数”的得分。边函数在本分词模型中简化为
f(s',s)
,其中
s'
为前一个字的标签,
s
为当前字的标签。于是该边函数就可以用一个
4*4
的矩阵描述,相当于
HMM
中的转移概率。

实现了评分函数后,从第二字开始即可运用维特比后向解码,为所有字打上BEMS
标签。

实例****

还是取经典的“商品和服务”为例,首先
HanLP

CRFSegment
分词器将其拆分为一张表:

 Hanlp中使用纯JAVA实现CRF分词

null
表示分词器还没有对该字标注。

代码****

上面说了这么多,其实我的实现非常简练:

 Hanlp中使用纯JAVA实现CRF分词Hanlp中使用纯JAVA实现CRF分词

标注结果****

标注后将table
打印出来:

 Hanlp中使用纯JAVA实现CRF分词

最终处理****

将BEMS
该合并的合并,得到:

 Hanlp中使用纯JAVA实现CRF分词

然后将词语送到词典中查询一下,没查到的暂时当作nx
,并记下位置(因为这是个新词,为了表示它的特殊性,最后词性设为
null
),再次使用维特比标注词性:

 Hanlp中使用纯JAVA实现CRF分词

新词识别****

CRF
对新词有很好的识别能力,比如:

 Hanlp中使用纯JAVA实现CRF分词

输出:

 Hanlp中使用纯JAVA实现CRF分词

null表示新词。

 

转载自hankcs的博客

给TA打赏
共{{data.count}}人
人已打赏
安全运维

MongoDB最简单的入门教程之三 使用Java代码往MongoDB里插入数据

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索