了解了HMM之后,我们可以发现HMM有两个很明显的缺点:

  1. HMM定义的是联合概率,必须列举出所有可能出现的情况,这在很多领域是很困难的。在NLP领域,常知道各种各样但又不完全确定的信息,需要一个统一的模型将这些信息综合起来。
  2. HMM遵循一个假设:输出独立性假设。这要求序列数据严格相互独立才能保证推导的正确性,导致不能考虑上下文特征。而在NLP领域,上下文信息是很重要的。
      因此,引入条件随机场(CRF)。

1. 最大熵模型

  在介绍条件随机场(CRF)之前,首先了解一下什么是最大熵模型。
  简而言之,最大熵模型就是这个式子:
nlp 代码分析 nlp hmm_最大熵模型

nlp 代码分析 nlp hmm_特征函数_02称为归一化因子。

  现在我们举个例子:
  假设我们有一个健康评估的系统,每个人的健康水平分为“优、良、中、差”四个等级,与健康关联的信息包括“血压、血糖、运动、抽烟状况……”。

nlp 代码分析 nlp hmm_nlp 代码分析_03
  我们将“血压、血糖”等信息称为特征,这些特征是需要我们人工进行挑选的,以保证特征与所求目标之间的关联性。
  在这个例子中,如果选取了类似“头发弯曲程度”这样的特征,可能就与“健康水平”这个目标关联性较小,我们要尽量避免这样的特征。

  假设我们现在挑选出了这样四种特征:
{(血压)、(血糖)、(血压 吸烟情况(支/天))、(运动情况(次/天))}
  值得注意的是,这个特征集合中的第三项是由两个属性组合而成的。如果你想的话,可以利用更多属性组合成一个特征。

  在这里,我们只是用上述四个特征举个例子,如果你喜欢,完全可以用其他的特征或者更多的特征进行描述。

nlp 代码分析 nlp hmm_nlp 代码分析_04

nlp 代码分析 nlp hmm_nlp 代码分析_05


  通过这个例子,我们回忆最大熵模型:

nlp 代码分析 nlp hmm_最大熵模型

nlp 代码分析 nlp hmm_最大熵模型_07是给定 nlp 代码分析 nlp hmm_nlp 代码分析_04 之后,输出 nlp 代码分析 nlp hmm_nlp 代码分析_03 的分布,这里的 nlp 代码分析 nlp hmm_nlp 代码分析_04 就是上述特征信息集合(各个特征值组成的集合)。
  我们将 nlp 代码分析 nlp hmm_nlp 代码分析_11称为特征函数,这里面的nlp 代码分析 nlp hmm_nlp 代码分析_04 是特征信息集合中的某一个元素(例如,“血糖=7.0” 或者 “血压=150 烟=5”)。特征函数的参数 nlp 代码分析 nlp hmm_条件随机场_13是系统参数,对每个不同的 nlp 代码分析 nlp hmm_条件随机场_14有不同的值。
值得注意的是,组合特征以组合的形式存在:有一个 nlp 代码分析 nlp hmm_nlp 代码分析_04 是“血压=150”,也有另一个nlp 代码分析 nlp hmm_nlp 代码分析_04 是“血压=150 且 烟=5”,其所对应的 nlp 代码分析 nlp hmm_条件随机场_13也未必相同。

  用一张图直观表示:

nlp 代码分析 nlp hmm_nlp 代码分析_18


  归一化因子的作用是将最后的输出值转化为概率的形式(不同输出的和为1),很好理解,在这里不进行详细阐述。  看到这里,大家一定有这样一个问题:特征函数是什么?

  特征函数 nlp 代码分析 nlp hmm_nlp 代码分析_19 表示了某个特征信息对某个输出是否有影响的事实:

nlp 代码分析 nlp hmm_最大熵模型_20f_i(x,y) = 1nlp 代码分析 nlp hmm_特征函数_21f_i(x,y) = 0$

  以“血压=150”为例:

nlp 代码分析 nlp hmm_条件随机场_22


  对于“中、差”的健康状况也是相同的。

nlp 代码分析 nlp hmm_条件随机场_13控制其所占权重。

  我们可以看出,最大熵模型有这样的特点:

  1. 可以综合多个不完全的信息。
  2. 这些信息可以以某种方式灵活表示(特征函数可以自行定义)。

  好了,现在我们的最大熵模型已经形成了,我们看看它在序列问题中的效果:

nlp 代码分析 nlp hmm_最大熵模型_24


  把图中的两个特征信息nlp 代码分析 nlp hmm_特征函数_25看作句子中的每个词(字)的特征信息,把输出nlp 代码分析 nlp hmm_条件随机场_26看作序列标注结果。

  好像没什么问题?
  不,问题大了。

  我们可以看出,每个输入对应的输出是独立的(和HMM一样)。假设我们进行的是命名实体识别,完全有可能输出两个相邻的B(实体开始符),而从逻辑上来讲,这种情况是完全不可能发生的。

  所以,最大熵模型还不够,我们还需要条件随机场(CRF)。

2. 条件随机场(CRF)

  先来描述几个(没什么用)的概念:
  随机场:随机场可以看作一组随机变量的集合,这些随机变量间可能有依赖关系,给每一个位置中随机变量按照某种分布随机赋予相空间的一个值之后,其全体就叫做随机场。
  马尔可夫性质:指的是一个随机变量序列按时间先后关系依次排开的时候,第 n+1n+1n+1 时刻的分布特性,与 nnn 时刻以前的随机变量的取值无关。
  马尔科夫随机场(MRF):具有马尔科夫性质的随机场。
  条件随机场(CRF):如果给定的MRF中每个随机变量下面还有观察值,要确定的是给定观察集合下,这个MRF的分布,也就是条件分布,那么这个MRF就称为CRF(Conditional Random Field)。

  这几个概念大家了解一下就好~

  在上面的介绍中,最大熵模型是这样的:

nlp 代码分析 nlp hmm_nlp 代码分析_27


  在此基础上,条件随机场是这样的:

nlp 代码分析 nlp hmm_条件随机场_28


  条件随机场将最大熵模型中“特征函数”的概念分为两个类别:

  1. 结点特征函数:类似于最大熵模型中的特征函数,描述特征信息对当前输出的影响;
  2. 边特征函数:描述特征信息对输出转换的影响。

  图中各个部分的解释已经很清晰了,在这里就不再赘述。

  相比于最大熵模型,条件随机场多了“边特征函数”,用以解决不合理标注问题。很明显,在条件随机场边特征函数的约束下,输出两个相邻B的情况是不可能发生的。

  由此定义的线性条件随机场基本形式如下:
nlp 代码分析 nlp hmm_特征函数_29
其中,
nlp 代码分析 nlp hmm_条件随机场_30

  同样为归一化项。

  式子中各部分与最大熵模型类似,在这里不再一一进行解释。

  该模型中,
  输入为:nlp 代码分析 nlp hmm_特征函数_31(观测序列)
  输出为:nlp 代码分析 nlp hmm_条件随机场_32(标记序列)
  参数为:nlp 代码分析 nlp hmm_条件随机场_33
  注意,特征函数是预先定义的。

nlp 代码分析 nlp hmm_nlp 代码分析_34
以及对应权重 nlp 代码分析 nlp hmm_条件随机场_33

  在应用方面,有很多实现条件随机场的开源工具包,例如CRF++。这些工具包的使用我们不在这里进行详细描述,有兴趣的朋友们可以自行查阅相关资料。但是有一点是在使用任何工具包时都要注意的:
  特征函数是CRF最重要的部分,CRF的效果与特征函数的定义密不可分

3. RNN+CRF

  在结合CRF之前,我们先想象一下只用RNN解决序列标注问题的方法。
  回想一下,无论是单向RNN还是双向RNN,都没有在输出层建立前后文联系。因此,与HMM类似,仅用RNN解决序列标注问题同样存在不合理标注(例如两个相邻的B)的问题。
  所以,在此基础上,提出了RNN+CRF的方法。

  RNN+CRF的结构是这个样子的:

nlp 代码分析 nlp hmm_特征函数_36

  模型结构看起来很复杂是不是?
  拆开来看,其实它只是在双向RNN上堆了一层CRF。
  双向RNN的部分在这里不再赘述

nlp 代码分析 nlp hmm_特征函数_37矩阵,表示了每个位置对每个标注标签的打分(序列长度为 nlp 代码分析 nlp hmm_特征函数_38,每个位置有 nlp 代码分析 nlp hmm_nlp 代码分析_39 种标签,对于B E I O标签,nlp 代码分析 nlp hmm_特征函数_40),但正如我们刚刚所分析的,这可能导致不合理标注问题的出现。
  于是,在RNN输出的基础上,又堆叠了一层CRF,利用边特征函数规避不合理标注问题。很明显,每个RNN输出之间的边特征函数可以用一个nlp 代码分析 nlp hmm_nlp 代码分析_41矩阵描述,表示了由每个标注标签到其他标注标签的转移打分(类似马尔可夫模型中的转移概率矩阵)。

nlp 代码分析 nlp hmm_特征函数_37)描述了结点特征函数,而输出之间的连接矩阵(nlp 代码分析 nlp hmm_nlp 代码分析_41)描述了边特征函数。

  模型的学习过程与预测过程与RNN类似,在这里就不再赘述。

  在这里,值得注意的是,在模型的学习过程中,RNN自动提取了特征函数(每当想到这里,都会感叹道“神经网络真是个神奇的东西”),这也避免了人工挑选特征函数的工作。

  这一部分中,我们介绍了解决序列标注问题的另外两种方法:CRF、RNN+CRF。目前,RNN+CRF的方法是处理序列标注问题的方法中相对较好的一种方法。