OrdinAry
win10
Python 3.7.0
CRF++-0.58
条件随机场(CRF):
条件随机场定义:令 G = ( V , E ) 表示一个无向图, 任意一个节点v对应一个随机变量Y,因此Y = (v ∈ V) , Y中元素与无向图 G中的顶点一一对应。当在条件 Χ 下,随机变量 Y v 的条件概率分布服从图的马尔可夫属性:p ( | Χ , , w ≠ v ) = p ( | Χ , , w ~ v ) ,其中 w ~ v 表示 ( w , v) 是无向图 G 的边。这时我们称 ( Χ , Y ) 是一个条件随机场。
我们可以推出最终条件随机场的条件概率为:
其中,
训练CRF主要就是要训练特征函数的权重(即),对于训练集(x1,y1),(x2,y2),…,(xn,yn)(x1,y1),(x2,y2),…,(xn,yn),采用极大似然估计法计算权重参数,条件概率的对数似然函数为:
其中
为训练样本集中xy的经验概率,它等于xy同时出现的次数除以样本空间容量;
为训练样本集中x的经验概率,它等于x出现的次数除以样本空间容量。
只需要对似然函数求导为0,进行优化求解即可。
1)对语料进行预处理。在本次实验中,采用的1998年人民日报分词数据集,格式如下:
需要将其处理为crf++需要的训练数据格式:
其中,O标识不是查找的中文名,S标识该中文名只有一个字符,B表示中文名的第一个字符,M标识中文名的非开始/结束字符,E表示中文名的最后一个字符
在处理过程中,需要将语料转换为对应的标注,并将形如[华北/ns 电管局/n]nt进行合并,合并为华北电管局/nt。同时,从中去除部分数据作为测试集数据。在本次实验中,我抽取了25%的数据用作测试。
具体实现见代码setTag.py
2)编写特征模板文件,该文件描述了用来训练以及进行测试的特征。
# Unigram
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-2,0]
U06:%x[0,0]/%x[-1,0]
U07:%x[0,0]/%x[1,0]
U08:%x[-1,0]/%x[-2,0]
U09:%x[1,0]/%x[2,0]
U10:%x[-1,0]/%x[1,0]
# Bigram
B
3)执行crf_learn -f 3 -p 8 template.txt train.txt model命令,完成模型的学习,模型文件为model。
其中,各参数含义为:
-f, –freq=INT使用属性的出现次数不少于INT(默认为1)
-p, –thread=INT线程数(默认1),利用多个CPU减少训练时间
训练过程如下:
4)通过crf_test -m model test.txt > test.rst命令完成对测试集数据的标注,标注后的test.tst文件如下:
第一列为进行标注的中文字符,第二列为按照模型进行标注的结果,第三列为人工标注的结果。
5)根据对测试集的标注结果计算模型的各项参数:Precision,Recall,F1-Score.
def test(path):
file = open(path)
tags = 0#被标记字的总数
right = 0#标记正确的数目
precisionTags = 0#所有标记出来的数目
recallTags = 0#应该被标记的字的数目
for line in file:
line = line.strip()
if(len(line)==0):
continue
tags += 1
_word, tag_real, tag_point = line.split()
if tag_point == tag_real and tag_point != 'O':
right += 1
if tag_point != 'O':#被标注的数据
precisionTags += 1
if tag_real != 'O':#应该被标注的数据
recallTags += 1
precision = float(right)/precisionTags
recall = float(right)/recallTags
f1Score = 2*precision*recall/(precision+recall)
print("precision:%f, recall:%f, F1Score:%f\n"%(precision,recall,f1Score))
test('test.rst')
测试内容:
Precision:所有标注正确的词的数量/所标注出来的词的总数
Recall:所有标注正确的词的数量/应该标注的词的数量
执行结果如下:
分析test.rst文件我们可以看出:
1) 人工标注为地名而模型未能成功标注的结果:
, O O
中 O B
国 O E
驻 O O
阿 O B
联 O M
酋 O M
使 O M
馆 O E
内 O O
对于中国,阿联酋这两个地名,模型未能成功识别
2)人工未标注为地名而模型识别为地名的情况:
(1)
增 O O
加 O O
从 O O
巴 B O
自 M O
治 M O
区 E O
进 O O
口 O O
(2)
为 O O
什 O O
么 O O
维 B O
也 M O
纳 E O
音 O O
乐 O O
会 O O
在人工标注中,巴自治区以及维也纳未被标注为地名,而在模型中,将其识别为地名。
分析上述结果,我们可以看出:CRF算法通过对地名前后的词语进行提取,将其纳入模型的考虑范围中。在判断一个词是否为地名时,主要通过对前后的特征进行匹配,从而进行判断。因此,当前后不具有明显特征时,不能够对特征进行有效提取。同时,对于具有多重含义的词进行识别时,可能会识别错误。
CRF可以有效对中文名词进行识别,其主要通过对特征进行提取,生成模型,然后用模型来进行匹配。由于本次实验中,仅通过对词进行特征提取,效果没有达到最佳,为了提升识别的效果,可以将语料的词性作为特征进行提取或者扩充训练的语料。同时,可以对语料进行事先整理,提升识别效果
采用1998年人民日报分词数据集,文件为renmin.txt
执行setTag.py文件(python setTag.py),用以生成CRF++格式标注的训练集以及测试集数据
执行crf_learn -f 3 -p 8 template.txt train.txt model命令,生成模型(template可修改)
执行crf_test -m model test.txt > test.rst命令,将该模型在测试集数据上进行测试,标注结果写到test.rst文件中
test.rst文件格式如下:
进行标记的字 完成的标记 真正的标记
执行testResult.py文件(python testResult.py),查看识别效果