伏尔加的鱼条件随机场python_条件随机场(crf)及tensorflow代码实例⼀、定义
条件随机场(crf):是给定⼀组输⼊随机变量条件下,另⼀组输出随机变量的条件概率的分布模型,其特点是假设输出随机变量构成马尔科夫随机场。本⽂所指线性链条件随机场。
隐马尔科夫模型(HMM):描述由隐藏的马尔科夫链随机⽣成观测序列的过程,属于⽣成模型。
当然,作为初学者,从概念上直观感受不到两者的区别与联系,甚⾄感觉两个概念都理解不了了,不过这没啥问题,继续学下去吧。
⼆、学习CRF包含的知识点
参考李航的统计学习⽅法,将该部分内容的主要知识点梳理如图,可以看到,CRF和HMM由很多共同点,譬如,都和马尔科夫有关、都有三个问题要解决,解决的⽅法也有相同的地⽅。
三、概率⽆向图
概率⽆向图,⼜称马尔科夫随机场,也就是定义中假设输出随机变量构成的。关于模型的构建,其实就是⼀个由节点(node,记作V)和节点链接关系的边(edge,记作E)组成的图G = (V,E),所谓⽆向图,就是边没有⽅向。
随机变量存在的关系包括:成对马尔科夫性、局部马尔科夫性和全局马尔科夫性。假设随机变量的联合概率分布P(Y)和表⽰它的⽆向图G,若P(Y)满⾜上述三种关系,则此联合概率分布为概率⽆向图或称为马尔科夫随机场。
提出该定义事实上是为了求联合概率分布做铺垫,为了求联合概率,给出⽆向图中的团与最⼤团的定义。
团:{Y1,Y2},{Y1,Y3},{Y2,Y3},{Y2,Y4},{Y3,Y4}
最⼤团:{Y1,Y2,Y3},{Y4,Y2,Y3}
概率⽆向图模型的联合概率分布表⽰为其最⼤团上的随机变量的函数的乘积的形式的操作。概率⽆向图模型的链和概率分布P(Y)可以表⽰为如下形式:
C为⽆向图的最⼤团,Yc是C的结点对应的随机变量,Ψ就是⼀个函数,暂且不⽤管是什么,就是⼀个转换关系。
看到这⾥,其实对于CRF的结果的图的理解已经有了铺垫,实际上,CRF就是将输⼊X,经过变换,获得输出Y的过程,当然这个Y就满⾜了上⾯所画的⽆向图。但是这个概率是⼲什么的呢?
继续看CRF的内容,等看完再第四章返回来看该处内容,我相信会有进⼀步了解,知道概率是怎么求的了吧。
四、条件随机场的定义
突然来的⼀点感悟,和内容⽆关:虽然这⼀章和第⼀章内容有点重合,但是我觉得作为初学者,最应该的是⼀个循序渐进的过程,有很多书都是为了内容的连续性,⽽忽略初学者的接受能⼒,事实上很多东西需要不断学习,不断深⼊的过程,这个在很多教程并不能体现出来,⽽且有时候,⽹上查问题找资料,总是⼀搜⼀⼤堆,⼀打开都是⼀样的,可能是很多⼈看到别⼈的博客,学习完了,理解了然后就复制粘贴上了,也懒得再改改或者加点⾃⼰的东西。我觉得是可以理解的,最好百度能做⼀个机制,相同的东西别都索引上了。
条件概率模型:P(Y|X),Y为输出变量,表⽰标记的序列,X为输⼊变量,表⽰需要标注的观测序列(再HMM中也称为状态序列)。
学习问题中,利⽤极⼤似然估计,估计P^(Y|X)
预测问题中,利⽤给定的序列x,求出条件概率P^(Y|X)最⼤的输出序列y^
⼀般的线性链条件随机场表⽰如图,通常假设X和Y有相同的结构,那么表⽰图就如下所⽰:
⽽此时,最⼤团,就是相邻两个结点的集合。可以引出公式:
当然,后续会有CRF的参数化形式、简化形式等表⽰形式,但实际上都是第三章求概率的表达。
五、CRF的三个需要解决的问题
5.1 概率计算问题
条件随机场的概率计算问题,就是给定x,y,求它的P(Yi = yi | x),P(Yi-1 = yi-1 ,Yi = yi | x)以及相应的数学期望的问题。其解决⼿段⽤的是HMM那样的前向-后向算法。
前向-后向算法:
定义前向向量:ai(x):
递推公式表⽰为:
ai(yi|x)表⽰在位置i的标记为yi并且到位置i的前部分标记序列的⾮规范化概率,yi可取m个,所以ai(x)是m维列向量。同理也可以定义后向算法。其中M的定义是在上述条件随机场的矩阵形式中定义的,本⽂中未介绍,直接给出定义:
Mi表⽰的是随机变量Y取值为yi的⾮规范化的条件概率,这个概率依赖于当前和前⼀个位置。
对于此处的理解,我觉得如果⾮要和HMM中类⽐的化,a类似于前向概率,只不过此处叫做:前向向量,两者的不同就是在CRF中,a的求法没有状态转移矩阵;⽽M类似于HMM中状态转移概率位置。并且,CRF的这个式⼦中,没有观测矩阵。总之虽然都叫前向求法,但是⾥⾯参数意义是不⼀样的,不好对⽐,CRF中,并不是依赖状态转移矩阵和观测矩阵的过程,⽽是⼀个依赖于前⼀时刻⽣成结果的概率的预测概率。因为我们要计算的是⼀个已知yi排列的概率嘛,所以是⼀个连乘的关系,按序列顺序将概率相乘(i时刻的概率依赖于i-1时刻的概率)。
后向向量,表⽰在位置i的标记为yi并且从i+1到n的后部分标记序列的⾮规范化概率。
当然,前向向量是从前往后扫描,扫到头的化,就和后向向量第⼀个值相同了。。。
概率计算:
按照前向-后向向量的定义,可知,αi表⽰位置i处标记为yi,从1到i-1处为某⼀排列的概率,βi表⽰位置i处标记为yi,从i+1到n处为某⼀排列的概率。因此,得到条件概率:
对于下⾯⼀个式⼦的理解:事实上,这两个概率都是根据定义直接列出来的,αi-1表⽰i-1标记为yi-1时,以及之前排序为某⼀序列的概率,因为yi-1与yi并不是独⽴的,所以联合概率就表⽰成上⾯的式⼦
了。
期望值的计算:
利⽤前向-后向算法,可以求出特征函数fk关于P(X,Y)和P(Y|X)的数学期望。不过要求P(X , Y)的话,需要假设经验分布P^(X)。该期望值的计算公式此处略过,就是⼀个求期望的公式嘛。
5.2 条件随机场的学习算法
该节研究的是给定训练数据集估计CRF模型参数的问题。参数估计通常⽤极⼤似然估计,HMM中,如果隐层状态未知的话,也是⽤极⼤似然估计。
具体的优化实现算法有改进的迭代尺度法IIS、梯度下降法以及拟⽜顿法。直接给出优化函数吧:
其实就是⼀个EM算法,道理和HMM中的⼀样,先对权值w进⾏优化,优化完求状态特征和转移特征的期望,然后再根据期望再迭代优化w,最后满⾜概率最⼤就可以了。
5.3 条件随机场的预测算法
条件随机场的预测问题,是给定CRF和输⼊x,求输出y的问题。这个求法就是使⽤viterbi算法。求法
同HMM⼀样,只不过HMM中反推的时候,利⽤的是上⼀时刻某⼀状态转移到当前时刻状态概率最⼤的那个上⼀时刻的状态。
此处,结合序列标记问题,定义为δi(l),表⽰在位置i标记l各个可能取值(),递推公式:
其中,
就是⾮规范化的P(yi|x),因此,这⾥采⽤了相加的⽅法。反推的时候,选择上⼀时刻某⼀Ψ,在李航书中那个例⼦的观察⽅法如下,其中画
调整生物钟黄框的是取值⼤的那⼀项。
六、CRF与HMM的区别联系
来⾃:Sutton, Charles, and Andrew McCallum. "An introduction to conditional random fields." Machine Learning 4.4 (2011): 267-373.
虽然⽹上这个图都在抄,不过我感觉都解释的不够详细啊。⾸先从HMM看,⽩⾊圆代表状态,⿊⾊代表观测值,可以看到,他们之间有⼀个顺序的依赖关系;⽽采⽤CRF的话,状态和观测值(或者说⽤词性和词语表⽰),可以看到没有这种顺序的依赖关系。HMM中的状态只与前⼀个有关,⽽CRF综合考虑了前后的依赖关系。
判别式模型和⽣成式模型
蒹葭赏析HMM是⽣成式模型,CRF是判别式模型,⾸先介绍两种模型。判别模型是给定输⼊序列 X,直接评估对应的输出Y ;⽣成模型是评估给定输出 Y,如何从概率分布上⽣成输⼊序列 X。其实两者的评估⽬标都是要得到最终的类别标签Y, 即Y=argmax p(y|x)。判别式模型直接通过解在满⾜训练样本分布下的最优化问题得到模型参数,主要⽤到拉格朗⽇乘算法、梯度下降法,常见的判别式模型如最⼤熵模型、CRF、LR、SVM等;⽽⽣成式模型先经过贝叶斯转换成Y = argmax p(y|x) = argmax p(x|y)*p(y),然后分别学习p(y)和p(x|y)的概率分布,常见的如n-Gram、HMM、Naive Bayes。
交换舞伴
判别模型和⽣成模型只是描述⼀种问题的两种⽅式,在理论上,它们是可以互相转换的。 对于上述HMM和CRF的区别,最主要的就是对于HMM,需要加⼊状态概率分布的先验知识,即:
在HMM中有这样⼀个过程,但是CRF就不需要了。
最⼤后验估计 vs最⼤似然估计
频率学派:最⼤似然估计(MLE):在进⾏推论时,我们只关⼼似然度,并选择给出所最⼤化 p(data|hypo) 的假设作为预测。
贝叶斯学派:最⼤后验估计(MAP):我们也需要把先验 p(hypo) 纳⼊计算,不仅是似然度,还要选择
给出最⼤ p(data|hypo) * p(hypo)
的假设作为预测。
如果我们认为所有假设都服从均匀分布,那么MAP = MLE 。
可以看到,HMM和CRF是两种思路,CRF是频率学派,⽽HMM是贝叶斯学派的。效益性
七、CRF与Softmax
对于序列标注问题,可以简单的理解为分类问题,既然是分类,为什么NLP中通常不直接⽤softmax等分类器,⽽使⽤CRF\HMM呢?这是因为⽬标输出序列本⾝会带有⼀些上下⽂关联,⽽softmax等不能体现出这种联系。当然,CRF体现的不仅仅是上下⽂的联系,更重要的是利⽤viterbi算法,体现的是⼀种路径规划的概率。
另外,通常在NLP中,输⼊每个batch的语句长度是不⼀样的(单个batch语句长度可以通过padding补齐),如果⽤CNN做特征提取的
话,batch之间的结果的维度是不同的。⽽采⽤CRF的话,就不⽤考虑这个维度不同的问题了。
softmax在tf中的接⼝:
@tf_export("nn.sampled_softmax_loss")
def sampled_softmax_loss(weights,
bias,
labels,
inputs,
num_sampled,
num_class,
num_true=1,
sampled_values=None,
remove_accidental_hits=True,
partition_strategy="mod",
name="sampled_softmax_loss",
ed=None):
#num_sampled则是Sample Softmax时候⽤到的⼀个超参数,确定选⼏个词来对⽐优化'''
weights: A `Tensor` of shape `[num_class, dim]`, or a list of `Tensor`
objects who concatenation along dimension 0 has shape
[num_class, dim]. The (possibly-sharded) class embeddings.
bias: A `Tensor` of shape `[num_class]`. The class bias.世界货币有哪些
labels: A `Tensor` of type `int64` and shape `[batch_size,
num_true]`. The target class. Note that this format differs from
the `labels` argument of `nn.softmax_cross_entropy_with_logits`.
外交英文inputs: A `Tensor` of shape `[batch_size, dim]`. The forward
activations of the input network.
num_sampled: An `int`. The number of class to randomly sample per batch. num_class: An `int`. The number of possible class.
'''
⽽crf的接⼝:
def crf_log_likelihood(inputs,
tag_indices,
quence_lengths,
transition_params=None):
"""Computes the log-likelihood of tag quences in a CRF.
Args:
inputs: A [batch_size, max_q_len, num_tags] tensor of unary potentials
to u as input to the CRF layer.
tag_indices: A [batch_size, max_q_len] matrix of tag indices for which we compute the log-likelihood.
quence_lengths: A [batch_size] vector of true quence lengths.
transition_params: A [num_tags, num_tags] transition matrix, if available.
"""
可以看到,虽然两者都是实现分类的功能,但是实际上是不⼀样的,基于q2q的时候⽤softmax判断字典中是哪⼀个字,其softmax 的输⼊是⼀个固定维度的向量,因为整个q2q是基于序列的。⽽CRF输⼊就需要句⼦的长度做内部处理,它本⾝是基于序列的。
⼋、条件随机场的tensorflow代码实现
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
TIME_STEPS = 15#20 # backpropagation through time 的time_steps
BATCH_SIZE = 1#50
INPUT_SIZE = 1 # x数据输⼊size
LR = 0.05 # learning rate
num_tags = 2
# 定义⼀个⽣成数据的 get_batch function:
def get_batch():
xs = np.array([[2, 3, 4, 5, 5, 5, 1, 5, 3, 2, 5, 5, 5, 3, 5]])
res = np.array([[0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1]])
return [xs[:, :, np.newaxis], res]
# 定义 CRF 的主体结构
class CRF(object):
def __init__(lf, n_steps, input_size, num_tags, batch_size):
lf.n_steps = n_steps
lf.input_size = input_size
lf.num_tags = num_tags
lf.batch_size = batch_size
lf.xs = tf.placeholder(tf.float32, [None, lf.n_steps, lf.input_size], name='xs')
lf.ys = tf.placeholder(tf.int32, [lf.batch_size, lf.n_steps], name='ys')
#将输⼊ batch_size x q_length x input_size 映射到 batch_size x q_length x num_tags
weights = tf.get_variable("weights", [lf.input_size, lf.num_tags])
matricized_x_t = tf.reshape(lf.xs, [-1, lf.input_size])
matricized_unary_scores = tf.matmul(matricized_x_t, weights)
莫扎特死因
unary_scores = tf.reshape(matricized_unary_scores, [lf.batch_size, lf.n_steps, lf.num_tags])
quence_lengths = np.full(lf.batch_size,lf.n_steps,dtype=np.int32)
log_likelihood,transition_params = f.crf_log_likelihood(unary_scores,lf.ys,quence_lengths)
lf.pred, viterbi_score = f.crf_decode(unary_scores, transition_params, quence_lengths)
# add a training op to tune the parameters.