CRF模型——打通crf模型的任督二脉(一)

CRF模型 是nlp领域的经典模型,也是公认的不好学习的模型(相比其他机器学习模型)
,我记得作为小蓝书《统计机器学习》的最后一章,当年看得那叫一个晦涩难懂呢2333333,反正看了一两遍是看不太懂,
网上博客中 照抄小蓝书《统计机器学习》的最后一章的尤为多,也不能说不对,只是对我这种 小白,还是希望能有掰开算法细节和公式细节,甚至源代码细节来看的文章。

网上关于CRF模型的各种文章,我觉得问题在于没有 打通 CRF模型的任督二脉,
其中我认为CRF模型之所以被公认为是不好学习的模型,原因就在于相比其他机器学习模型,CRF模型中的特征的处理方式有较大的不同,CRF模型中有特征模板,特征函数,这些都是其他机器学习模型中少有的概念。所以,只要弄清楚 CRF模型中的特征模板,特征函数,特征值 这一条线上的关系,CRF模型就没有什么晦涩难懂的了。其后的 前向概率-后向概率算法以及维特比预测算法都是通用的算法,不算晦涩难懂。

关于CRF模型中的特征模板,特征函数,特征值,我画了一个下面的图。
CRF模型——打通crf模型的任督二脉(一)_第1张图片

一般机器学习模型 的特征 表现方式都比较直观,(虽然构造渠道,方式需要经验和技巧),但CRF模型中由于特征模板的存在,特征 表现方式就不再那么直观了,但不管怎么,由上图可以看到,如果不看中间的第二步(即第二步是透明的),我们能看到,只要 给定语料和特征模板 , 对应的特征值其实就 已经确定下来了,代码要做的事就是按特征函数来统计算出对应的特征值。

搞清楚CRF模型中 最难懂的概念之后,我们再来看一些公式,我相信感受会更好。
下面输markdown 也是累死老子了。
还是先从特征函数的表达式开始,然后再看似然函数或者损失函数的式子,最后再看 对参数求导的过程。

参考 两个我觉得不错的讲解CRF模型的原创博客
条件随机场(Conditional Random Field)简介
https://blog.csdn.net/aws3217150/article/details/68935789
CRF++源码解读
https://blog.csdn.net/aws3217150/article/details/69212445

特征模版

CRF++训练的时候,要求我们提供特征模版,特征模版像下面这样,先来看如下图片:
CRF模型——打通crf模型的任督二脉(一)_第2张图片
“%x[row, column]” 代表获得当前指向位置向上或向下偏移|row|行,并指向第column列的值,绝大多数情况下,我们的训练语料都是(字/词,label),且90%的例子中我们看到的特征模版中的column都是=0的,这意味着column=0,我们只把字/词当作特征。
比如上图中,当前指向位置为 “the DT B-NP”,那么”%x[0,0]”代表获得当前指向偏移0行,第0列的值,也就是”the”,这条模板构成的特征含义是“当前位置的词是“the”且label=xx”是否为真(xx可以是L中label中的任一个)。
而”%x[0,1]”代表获得当前指向偏移0行,第1列的值,也就是”DT”。这条模板构成的特征含义是“当前位置的词性是“DT”且label=xx”是否为真(xx可以是L中label中的任一个)。
”%x[-2,1]”则代表获得当前指向向上偏移2行,第1列的值,也就是”PRP”,这条模板构成的特征含义是“前前位置的词性是“PRP”且label=xx”是否为真(xx可以是L中label中的任一个)。
这就是特征最完整的意思,
之前对一个问题迷茫过,就是
”%x[0,0]”和”%x[-1,0]”遇到“the"是否产生了重复的特征。
后面想明白了,解开了这个困惑。
因为”%x[0,0]”遇到“the",产生的特征函数,举一个label=b为例来说就是,
产生了f1=“当前位置的词是“the”且当前位置label是b"是否为真。
而”%x[-1,0]”遇到“the”,产生的特征函数,举一个label=b为例来说就是,
产生了f2="前一个位置的词是“the”且当前位置label是b"是否为真。
显然不一样,f2在每个位置上都会去检查前一个位置是否为“the”。

看明白了这个,就能准确的知道Unigram模版产生多少个特征函数了。
对每一条Unigram模版的规则而言,它能扫描到M个不同的取值。(一般也就是M个不同的字/词),M个不同的取值中的每一中对当前位置的label(L种)都要考虑,也就要再乘以L.
如果有N条Unigram模版的规则,那么需要再乘以N,为什么因为每一条Unigram模版的规则,参考的位置都不同,正如前面写的,”%x[0,0]”参考当前位置的取值,”%x[-1,0]”参考前一位置的取值,”%x[-2,0]”参考前前位置的取值。
所以N条Unigram模版的规则能产生 N ∗ M ∗ L N*M*L NML种特征函数。

再看Bigram模版。
绝大多少例子中的Bigram模版就写了一个B就完事了。
那么写一个B代表什么意思,没有具体写出Bigram模版的规则,会不会是没有用Bigram模版产生特征函数?如果确实产生了特征函数,那么长什么样子,能否像Unigram模版的规则知道每一个特征的具体含义呢?
答案一一解开:
1,写一个B不代表没有Bigram模版的规则,而是这里的B是一个简要记法。还原的话应该是”B01:%x[0,0]”,Bigram模版的B二元的意思是,当前标签取值和上一次标签取值,(一元的意思是只考虑当前位置的标签,就一个。二元的意思是不仅考虑当前位置的标签还考虑前一个位置的标签,所以是两个,原来你是这样的二,笑哭,是不是和开始想象的二不太一样了,哈哈)。

所以假设一条Bigram模版的规则而言,假设它能扫描到M个不同的取值。(一般也就是M个不同的字/词),M个不同的取值中的每一取值对当前位置label和前一个位置的label 这两个位置的label有( L ∗ L L*L LL种组合)。
所以 1 条 B i g r a m 模 版 1条Bigram模版 1Bigram的规则能产生 M ∗ L ∗ L M*L*L MLL种特征函数。

另外再补充一点,为什么写一个B也应该有Bigram特征函数的产生。
那是因为Bigram特征函数本质上就是转移特征,Bigram特征函数对应的权重就是转移特征矩阵中的值。

对应着,Unigram特征函数本质上就是发射特征(或者说状态特征),Unigram特征函数对应的权重就是发射特征矩阵中的值。

小蓝书 《统计机器学习》的最后一章 对特征函数的数学表示是,如下:
条件随机场CRF中的同一特征 会在各个位置上都有定义,可以会对同一特征在各个位置上求和,得到特征函数对应的全局特征值。

特征函数包含两类,
一类是由B开头的模板决定的 定义在边上的特征函数,一般看成是 转移特征,对应有转移特征值,依赖当前位置和上一个位置
另一类是由U开头的模板决定的 定义在节点上的特征函数,一般看成是 转态特征,对应有转态特征值,只依赖当前位置的观测取值(crf++的Unigram特征模版产生的特征函数把“只依赖当前位置”这一条扩展了,变成了依赖当前位置的观测取值,依赖前一位置的观测取值,依赖前前一位置的观测取值)

小蓝书 《统计机器学习》也直白的说了, 条件随机场CRF完全由 转移特征函数值 t k t_k tk、 状态特征函数值 s l s_l sl 和对应的 权重 λ k , μ l \lambda_k,\mu_l λk,μl确定。

看到这里估计对下标 k和l有点疑问了,放后面。
小蓝书 《统计机器学习》提到,首先将转移特征函数和状态特征函数 及其权重用同一的符号表示,设有 K 1 K_1 K1个转移特征( L ∗ L ∗ N L*L*N LLN) , K 2 K_2 K2个转态特征( L ∗ N L*N LN), K = K 1 + K 2 K=K_1+K_2 K=K1+K2,可把特征函数统一记为:

f k ( y i − 1 , y i , x , i ) = { t k ( y i − 1 , y i , x , i ) k = 1 , 2 , . . . , K 1 s l ( y i , x , i ) k = K 1 + l , l = 1 , 2 , . . . , K 2 f_k(y_{i-1},y_{i},x,i)=\left\{ \begin{array}{rcl} t_k(y_{i-1},y_{i},x,i) & & {k=1,2,...,K_1} \\ s_l(y_{i},x,i) & & { k=K_1+l, l=1,2,...,K_2}\\ \end{array} \right. fk(yi1,yi,x,i)={tk(yi1,yi,x,i)sl(yi,x,i)k=1,2,...,K1k=K1+l,l=1,2,...,K2

状态特征函数需要在 各个位置上求和 ,得到对应特征值,
转移特征也是如此,得到对应的特征值,记作:

f k ( y , x , i ) = ∑ i = 1 n f k ( y i − 1 , y i , x , i ) , k = 1 , 2 , . . . , K f_k(y,x,i) = \sum_{i=1}^{n} f_k(y_{i-1},y_{i},x,i) ,k=1,2,...,K fk(y,x,i)=i=1nfk(yi1,yi,x,i),k=1,2,...,K

并且各特征的权重值是一一对应的:

w k = { λ k k = 1 , 2 , . . . , K 1 μ l k = K 1 + l , l = 1 , 2 , . . . , K 2 w_k=\left\{ \begin{array}{rcl} \lambda_{k} & & {k=1,2,...,K_1} \\ \mu_{l} & & { k=K_1+l, l=1,2,...,K_2}\\ \end{array} \right. wk={λkμlk=1,2,...,K1k=K1+l,l=1,2,...,K2

看了上面之后,我们再看
https://blog.csdn.net/aws3217150/article/details/69212445
博客中,提到的Lafferty的原始论文中的表示方法:
原始论文的阐述形式是CRF是一种概率图模型,而一幅图可以由它的边和节点来表达,也就是
G=(V,E)
其中,V是节点集合,E是边集合,对于链式CRF,模型对于输入序列和输出序列可以建立如下的概率模型:
p ( y ⃗ ∣ x ⃗ ) = e x p ( ∑ e ∈ E ∑ k w k ϕ k ( e = ( y i − 1 , y i ) , x ⃗ ) + ∑ v ∈ V ∑ t w t ϕ t ( v = y i , x ⃗ ) ) Z p(\vec{y}|\vec{x})=\dfrac{exp( \sum_{e \in E}\sum_{k} w_k \phi_k (e=(y_{i-1},y_{i}), \vec{x}) +\sum_{v \in V}\sum_{t} w_t \phi_t (v=y_{i}, \vec{x})) }{Z} p(y x )=Zexp(eEkwkϕk(e=(yi1,yi),x )+vVtwtϕt(v=yi,x ))

这种形式和我们常见的另一种形式其实又很大区别,另一种形式是:

p ( y ⃗ ∣ x ⃗ ) = e x p ( ∑ i ∑ k w k ϕ k ( y i − 1 , y i , x ⃗ ) ) ∑ y ′ ∈ Y e x p ( ∑ i ∑ k w k ϕ k ( y i − 1 ′ , y i ′ , x ⃗ ) ) p(\vec{y}|\vec{x})=\dfrac{exp( \sum_{i}\sum_{k} w_k \phi_k (y_{i-1},y_{i}, \vec{x}) ) }{\sum_{y^{'} \in Y} exp( \sum_{i}\sum_{k} w_k \phi_k (y_{i-1}^{'},y_{i}^{'}, \vec{x}) ) } p(y x )=yYexp(ikwkϕk(yi1,yi,x ))exp(ikwkϕk(yi1,yi,x ))

下面的这种形式是没有将边和节点区分开来,看上去只是写了边的特征函数,因为从某种程度上看,边包含的信息其实已经涵盖了节点所拥有的所有信息,将这两者统一起来只是有利于我们数学公式表达的方便性,另一方面,将边和节点进行单独讨论,从理论上可能有一点冗余, 但从实际效果来讲以及实际源码编写中看,都是边和节点区分开来写源码的,节点信息可以充当一种backoff,起到一定的平滑效果(Smoothing)。

下面我们就看 CRF的似然函数或者损失函数的式子:

L = − ∑ i N l o g p ( y ⃗ i ∣ x ⃗ i ) L=- \sum_{i}^{N} log p(\vec y^{i} |\vec x^{i}) L=iNlogp(y ix i)

其实我看到这个式子,总觉得和以前看到的机器学习的损失函数式子不一样,就在于这个 ∑ i N \sum_{i}^{N} iN, 按之前看到的,应该不需要这个 ∑ i N \sum_{i}^{N} iN,直接用 L = − l o g p ( y ⃗ i ∣ x ⃗ i ) L=- log p(\vec y^{i} |\vec x^{i}) L=logp(y ix i)就行了好像。

N应该不是句子的个数,而是语料中按词或者子拆分后的行数才对。

在直接看对损失函数的求导推导之前,应该再回一下,CRF的模型的损失函数的由来,并由此带出CRF模型中的前向后向算法。

MEMM(Maximum Entropy Markov Model)最大熵马尔科夫模型,解决标注问题的假设,也是认为状态的转移仅仅依赖于上一状态(这里我将标注标签称为一种状态)

CRF模型——打通crf模型的任督二脉(一)_第3张图片

这其实和crf很像, crf 大致一看其实也是这样,crf本来就是基于这个改进的,后面再说

上述MEMM虽然可以很优雅地解决标注问题,但存在标注偏好的问题,就是说模型在为输入序列x 打标签的时候,存在偏袒心里,会倾向于选择某些标签,
如果 s1只有两种转移状态:s1,s2,而s2有5种转移状态:s1,s2,s3,s4,s5
因为s1的转移状态很少,所以不管实际训练观测值有多少,由于每一步的状态转移概率都要归一化,所以s1的转移概率都会被放大,而s2由于转移状态多,因此每一步转移概率归一化的时候都被平均分摊了。因此在计算最优序列的时候,MEMM会偏袒那些状态转移少的标签,而忽略了实际观察值,
为了说明该现象,我们可以参考原始论文的识别 rob和rib例子,可参考https://blog.csdn.net/aws3217150/article/details/68935789

MEMM产生Label Bias的根源是什么,
这是因为MEMM的状态转移概率的计算方式,为了获得转移概率,它每一步的状态转移都会进行归一化,从而导致问题的产生。
CRF认清了问题的根源,只要不要在每一步状态转移进行归一化,而在全局进行归一化 就能一下子化解了MEMM产生的Label Bias标注偏好这个大问题。

p ( s ⃗ ∣ x ⃗ ) = ∏ i = 0 n p ( s i ∣ s i − 1 , x 1 , x 2 , . . . , x n ) = ∏ i = 0 n e x p ( w ⃗ T f ( s i , s i − 1 , x ⃗ ) ) ∑ s ′ ∈ S e x p ( w ⃗ T f ( s ⃗ ′ , s i − 1 , x ⃗ ) ) p(\vec s| \vec x)=\prod_{i=0}^n p(s_i|s_{i-1},x_1,x_2,...,x_n)=\prod_{i=0}^n \dfrac{exp(\vec w^{T} f(s_i,s_{i-1},\vec x))}{ \sum_{s^{'} \in S} exp(\vec w^{T} f(\vec s^{'},s_{i-1},\vec x))} p(s x )=i=0np(sisi1,x1,x2,...,xn)=i=0nsSexp(w Tf(s ,si1,x ))exp(w Tf(si,si1,x ))

p ( s ⃗ ∣ x ⃗ ) = e x p ( w ⃗ T Φ ( s ⃗ , x ⃗ ) ) ∑ s ′ ∈ S n e x p ( w ⃗ T Φ ( s ⃗ ′ , x ⃗ ) ) p(\vec s| \vec x)=\dfrac{exp(\vec w^{T} \Phi(\vec s,\vec x))}{ \sum_{s^{'} \in S^{n}} exp(\vec w^{T} \Phi(\vec s^{'},\vec x))} p(s x )=sSnexp(w TΦ(s ,x ))exp(w TΦ(s ,x ))

第一个是MEMM 对条件概率做的表达式,
第二个是CRF 对条件概率做的表达式,
分母中的 s ′ ∈ S , s ′ ∈ S n s^{'} \in S , s^{'} \in S^{n} sS,sSn 一点点不同,表示的含义就千差万别了,前者只是局部的,后者是全局的。

CRF相对于MEMM做了几个改动,首先在特征函数上面做了变动:
Φ ( s ⃗ , x ⃗ ) → R d \Phi(\vec s,\vec x) \rightarrow R^{d} Φ(s ,x )Rd
第一个是它将输入序列 x ⃗ \vec x x 和输出标注 s ⃗ \vec s s 映射为一个d维实数向量(这个d其实就是特征函数的个数,联系前面讲到的特征函数的内容, L ∗ N , L ∗ L ∗ N L*N,L*L*N LN,LLN),而MEMM的特征函数拥有的信息只是输入序列 x ⃗ \vec x x 和当前状态以及上一个状态,也就是说CRF的特征函数掌握信息量更多,从而表达能力更强。

第二个的改进是它不再针对每一次状态转移进行归一化,而是在全局进行归一化,这样完美解决Label Bias问题。

有得必有失,注意到全局进行归一化就意味着 模型的分母需要罗列所有的状态序列,对于序列长度为n的输入序列,状态序列的个数为 ∣ S ∣ n |S|^{n} Sn,对于这种指数增长问题,在实际应用中一般都是intractable的,只能付诸于近似求解,比如我们之前提过的Variational Bayes或者Gibbs Sampling等等。不过有一种特殊结构的CRF,精确快速求解的方式是存在的(前向后向算法帮助我们),因此在早期得以广泛应用。

你可能感兴趣的:(NLP)