CRF++/CRF/条件随机场的特征函数模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37667364/article/details/82919560

由于最近想实现CRF,学完了理论后就开始怎么想怎么实现,想参照CRF++的开源实现,但首先要解决的怎么理解特征模板,所以写了此文,主要参考了2篇文章,在此感谢。

http://www.52nlp.cn/%E4%B8%AD%E6%96%87%E5%88%86%E8%AF%8D%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AD%97%E6%A0%87%E6%B3%A8%E6%B3%954

http://www.hankcs.com/nlp/the-crf-model-format-description.html

  1. CRF++要求的训练数据格式

对于训练数据,首先需要多列,但不能不一致,既在一个文件里有的行是两列,有的行是三列;其次第一列代表的是需要标注的字或词最后一列是输出位"标记tag"如果有额外的特征,例如词性什么的,可以加到中间列里,所以训练集或者测试集的文件最少要有两列。

例如:下面所有例子都是以下列的分词数据举例

 

2.关于特征模板

CRF++的特征模板通常长下面这个样子:

“%x[行位置,列位置]”代表了相对于当前指向的token行偏移和列的绝对位置。

先来解释以下Unigram特征模板是什么意思。

举例:U00:%x[-2,0]

-2代表是当前行的之前的第2个字符(观测),

0代表第2列,如果遍历到的行如下图:

3.10.1

将产生以下的特征函数:(注:下列伪码的x代表观测,y代表状态,也就是贴的标签)

If(y==’B’&&x==’’) return 1 else return 0;

If(y==’E’&&x==’’) return 1 else return 0;

If(y==’M’&&x==’’) return 1 else return 0;

If(y==’S’&&x==’’) return 1 else return 0;

算一算将产生4*655364是状态个数,65536是不同字符的个数),如果状态数和观测数一样这就对应于HMM的发射矩阵。

这什么意思呢?学过HMM的知道,这类似于发射矩阵,统计状态下的观测分布。

有人可能要问?U01:%x[-1,0]U02:%x[0,0]2个会重复统计吧?确实是啊,目前我还不清楚为什么这样,我猜想这里要表达的是,当前状态下的观测分布不仅仅受当前观测字符的影响,还受前第2U02:%x[0,0],前第1U01:%x[-1,0],后1U03:%x[1,0]等的影响。

至于下面这种特征模板:

我想是统计当前状态下,窗口为3周围观测的分布,

以图3.10.1举例产生下面的特征函数:

if(x1==’’&&x2==’’&x3==’1’&y==’B’) return 1 else return 0;

if(x1==’’&&x2==’’&x3==’1’&y==’M’) return 1 else return 0;

if(x1==’’&&x2==’’&x3==’1’&y==’E’) return 1 else return 0;

if(x1==’’&&x2==’’&x3==’1’&y==’S’) return 1 else return 0;

这样想想确实CRFHMM一个发射矩阵表达了更多的信息。

令人疑惑的是Bigram并没有直接定义模板函数,只写了一个B(如上图),我在HanLp作者的博客中找到这样的解释。如果只写一个B的话,默认生成f(s', s),其中s't – 1时刻的标签.也就是说,Bigram类型与Unigram大致机同,只是还要考虑到t – 1时刻的标签.这意味着前一个output tokencurrent token将组合成bigram features

这样的话唯一一个bigram特征模板的所有特征函数类似于HMM中的转移矩阵。

还是以图3.10.1举例,将产生下列的特征函数:下面y1是前一个状态,y2是后一个状态。

If(y1==’B’&&y2==’B’) return 1 else return 0; 当然这个特征函数应该是不合理的,当前字符是Begin的状态,下一个只能是Middle或者End。我们暂时不考虑是否算法实现考虑了这个特征函数,因为我也没具体实现。

If(y1==’B’&&y2==’B’) return 1 else return 0;

If(y1==’B’&&y2==’M’) return 1 else return 0;

If(y1==’B’&&y2==’E’) return 1 else return 0;

If(y1==’B’&&y2==’S’) return 1 else return 0;

If(y1==’M’&&y2==’B’) return 1 else return 0;

If(y1==’M’&&y2==’M’) return 1 else return 0;

If(y1==’M’&&y2==’E’) return 1 else return 0;

If(y1==’M’&&y2==’S’) return 1 else return 0;

If(y1==’E’&&y2==’B’) return 1 else return 0;

If(y1==’E’&&y2==’M’) return 1 else return 0;

If(y1==’E’&&y2==’E’) return 1 else return 0;

If(y1==’E’&&y2==’S’) return 1 else return 0;

If(y1==’S’&&y2==’B’) return 1 else return 0;

If(y1==’S’&&y2==’M’) return 1 else return 0;

If(y1==’S’&&y2==’E’) return 1 else return 0;

If(y1==’S’&&y2==’S’) return 1 else return 0;

暂时学到这儿,等我实现了这个算法将补充细节或者修正。

猜你喜欢

转载自blog.csdn.net/qq_37667364/article/details/82919560