PR Structured Ⅲ:马尔可夫、隐马尔可夫 HMM 、条件随机场 CRF 全解析及其python实现
Content
归纳性长文,不断更新中...欢迎关注收藏
本章承接概率图知识
马尔可夫不仅是强化学习在时序决策上的理论基础,也是语音、NLP等领域处理时序数据并进行预测的基础。在使用这一族方法的时候,我们的目的是什么?
与普通的回归和分类不同,时序数据相邻数据间是有关系的,而非相互独立的。因此我们可以用上下文(主要是上文)所提供的信息,更好地对这类数据做分类或回归。
本章分以下三个递进的环节:将之前所有的观测作为未来预测的依据是不现实的,因为其复杂度会随着观测数量的增加而无限制地增长。因此,就有了马尔科夫模型,即假定未来的预测仅与最近的观测有关,而独立于其他所有的观测;
通过引入隐变量,解决Markov Model需要强独立性的问题,即隐马尔可夫模型 HMM;
HMM等为生成式模型,计算联合概率分布
;CRF则是判别式模型,计算条件概率
。由于 CRF 利用最大熵模型的思路建立条件概率模型,对于观测序列并没有做马尔科夫假设,可以得到全局最优,而HMM则是在马尔科夫假设下建立的联合分布,会出现局部最优的情况。(此处
均代表隐变量,
为观测)
1 马尔可夫 Markov引例:假设我们观测⼀个⼆值变量,这个⼆值变量表⽰某⼀天是否下⾬。给定这个变量的⼀系列观测,我们希望预测下⼀天是否会下⾬。如果我们将所有的数据都看成独⽴同分布的, 那么我们能够从数据中得到的唯⼀的信息就是⾬天的相对频率;
然而,我们知道天⽓经常会呈现出持续若⼲天的趋势。因此,观测到今天是否下⾬对于预测明天是否下⾬会 有极⼤的帮助。
我们可以使用概率的乘积规则来表示观测序列的联合概率分布,形式为
利用马尔科夫性,可以将上式变为⼀阶马尔科夫链(first-order Markov chain):
Image
根据我们在概率图模型中讲的 d-分离 性质,观测
的条件概率分布为
当然了,还可以有⼆阶马尔科夫链,其中特定的观测
依赖于前两次观测
和
的值:
Image
还有M阶马尔可夫链,当然计算代价也很大:如果有K个状态的离散变量,⼀阶马尔可夫链
需要
个参数;
而M阶马尔可夫
需要
个参数。
1.1 连续变量
1.1.1 Autoregressive (AR)
使⽤线性⾼斯条件概率分布, 每个结点都是⼀个⾼斯概率分布,均值是⽗结点的⼀个线性函数。
1.1.2 Tapped delay line
使用神经网络等参数化模型拟合
,因为它对应于存储(延迟)观测变量的前⾯M个值来预测下⼀个值。
2 状态空间模型 state space model
问题来了,我们既想构造任意阶数的、不受马尔可夫假设限制的序列模型,同时能够使⽤较少数量的⾃由参数确定。怎么做呢?引入隐变量。
对于每 个观测
,我们引⼊⼀个对应的潜在变量
(类型或维度可能与观测变量不同)。我们现在假设潜在变量构成了马尔科夫链,得到的图结构被称为状态空间模型(state space model)。
Image
它满⾜下⾯的关键的条件独⽴性质,即给定
的条件下,
和
是独⽴的,从而
联合概率分布为
HMM 这类引入隐变量的模型好处在于:根据d-分离准则,总存在⼀个通过隐变量连接任意两个观测变量
和
的路径,且这个路径永远不会被阻隔。这也就间接地解决了马尔可夫模型中需要直接连接多个之前观测的问题,相当于将
之前的观测信息全部包含在对应的隐变量
中。
2.1 隐马尔可夫 HMM隐变量:离散
观测变量:离散或连续
引例:以句子和词性对应为例,观测变量
为显式的句子,隐变量
为每一个单词对应的词性。
观测变量和隐变量上的联合概率分布为:
首先,定义HMM中用到的变量(2.1节适用)
给定模型
和观测序列
,求观测序列
在模型
下出现的条件概率
:是隐状态转移概率矩阵,其中
,
为从隐状态
转移到
的频率计数;
是观测状态生成概率矩阵,其中
,
是从隐状态
对应观测
的频率计数;
是隐状态的初始概率分布,
是初始隐状态为
的频率计数。
HMM可以解决的三个问题:评估观察序列概率。
给定模型
和观测序列
,计算在该模型下,观测序列
出现的概率 (因此HMM是生成式算法)。用前向后向算法求解。
模型参数学习。
给定观测序列
,估计模型参数
,使该模型下观测序列的条件概率
最大。用到基于EM算法的鲍姆-韦尔奇算法求解。
预测问题/解码问题。
给定模型
和观测序列
,求给定观测序列条件下,最可能出现的对应的隐状态序列
。用到基于动态规划的维特比算法求解。
以下对上述三种问题及三种解法展开叙述。
2.1.1 观测序列概率A. 暴力解法:任意一个隐状态序列
出现的概率是:
对于固定的状态序列
,我们要求的观察序列
出现的概率是
则
和
联合出现的概率是:
边缘概率分布,即可得到观测序列
在模型
下出现的条件概率
:
B. 前向后向算法:
前向后向算法是 前向 + 后向 的形式,即分别从 start 和 stop 位置开始递推,这样才能承接上下文。用动态规划的思想从子问题的最优解得到整个问题的最优解。定义前向概率:定义位置
时对应的隐状态为
,从
观测为
,记作
计算位置 1 的各个隐藏状态前向概率:
递推
位置的前向概率:
最终结果:
后向算法同理定义后向概率:定义位置
时对应的隐状态为
,从
观测为
,记作
初始化位置 T 的各个隐藏状态后向概率:
递推
位置的后向概率:
最终结果:
统一形式
2.1.2 观测序列概率 Python 实现
本章使用 hmmlearn 库实现,文档地址
import numpy as np
from hmmlearn import hmm
states = ["box 1", "box 2", "box3"]
n_states = len(states)
observations = ["red", "white"]
n_observations = len(observations)
start_probability = np.array([0.2, 0.4, 0.4])
transition_probability = np.array([
[0.5, 0.2, 0.3],
[0.3, 0.5, 0.2],
[0.2, 0.3, 0.5]
])
emission_probability = np.array([
[0.5, 0.5],
[0.4, 0.6],
[0.7, 0.3]
])
model = hmm.MultinomialHMM(n_components=n_states)
model.startprob_=start_probability
model.transmat_=transition_probability
model.emissionprob_=emission_probability
seen = np.array([[0,1,0]]).T
print model.score(seen)
注意:score函数返回的是以自然对数为底的对数概率值,因此会是负数。
2.1.3 HMM 参数学习A. 鲍姆-韦尔奇算法原理
HMM 的参数学习一般采用 鲍姆-韦尔奇算法,其思想就是 EM算法。E步:求出联合分布
基于条件概率
的期望,其中
为模型当前的参数:
M步:最大化上式的期望,得到更新的模型参数λ。
不断进行EM迭代,直到模型参数的值收敛为止。B. 鲍姆-韦尔奇算法推导
TODOC. 鲍姆-韦尔奇算法流程
输入:
个观测序列样本
输出:HMM模型参数随机初始化三个矩阵参数
对于每个样本
,用前向后向算法计算
更新模型参数:
重复 2-3 直至三种参数收敛。
2.1.4 HMM 参数学习 Python 实现
import numpy as np
from hmmlearn import hmm
states = ["box 1", "box 2", "box3"]
n_states = len(states)
observations = ["red", "white"]
n_observations = len(observations)
model2 = hmm.MultinomialHMM(n_components=n_states, n_iter=20, tol=0.01)
X2 = np.array([[0],[1],[0],[1],[0],[0],[0],[1],[1],[0],[1],[1]])
model2.fit(X2,lengths=[4,4,4])
print model2.startprob_
print model2.transmat_
print model2.emissionprob_
print model2.score(X2)
model2.fit(X2)
print model2.startprob_
print model2.transmat_
print model2.emissionprob_
print model2.score(X2)
model2.fit(X2)
print model2.startprob_
print model2.transmat_
print model2.emissionprob_
print model2.score(X2)有现成的库真的是简单,仿佛上一节是在讲另一件事。
2.1.5 HMM 解码问题A. HMM 解码问题概述
HMM 的解码问题是给定模型,求给定观测序列条件下,最可能出现的对应的隐藏状态序列。
解码问题公式定义:
已知参数
,观测序列
,找到隐状态序列
,使得
最大。
根据 2.2.1 B 节的定义,在给定模型和观测的情况下,可以通过HMM的前向后向算法计算位置
隐状态为
的概率
。则有
然而这样计算并不能保证隐状态序列整体是最优的,这就像多智能体合作的平均和博弈一样,不能只在一个智能体上求最优而致使其余智能体效果很差。反映在HMM中,就是相邻隐状态可能存在转移概率为0的情况。
在博弈问题中,我们需要找到一个纳什均衡点。在多目标优化问题中,就叫做帕累托最优点。而HMM的解法就要依靠维特比算法。B. 维特比算法概述
TODOC. 维特比算法流程
输入:HMM模型
,观测序列
;
输出:最有可能的隐状态序列
初始化局部状态:
动态规划递推位置
时刻的局部状态:
位置
最大的
就是最优隐状态序列出现的概率。最大的
就是
位置最可能的隐状态。
利用局部状态
开始回溯。对于
:
最终得到最有可能的隐状态序列
2.1.6 HMM 解码 Python 实现
承接 2.1.2
seen = np.array([[0,1,0]]).T
logprob, box = model.decode(seen, algorithm="viterbi")
print("The ball picked:", ", ".join(map(lambda x: observations[x], seen)))
print("The hidden box", ", ".join(map(lambda x: states[x], box)))
2.2 线性动态系统 LDS隐变量和观测变量都是连续的⾼斯变量
引例:假设我们希望使⽤⼀个有噪声的传感器测量⼀个未知量z的值,传感器返回⼀个观测值x, 表⽰z的值加上⼀个零均值的⾼斯噪声。给定⼀个单次的测量,我们关于z的最好的猜测是假 设z = x。一个简单的思路是,通过取多次测量然后求平均的⽅法提⾼我们对z的估计效果,因为随机噪声项倾向于彼此抵消。
那么我们将情况变得更复杂一些。假设我们希望测量⼀个随着时间变化的量z。简单思路:如果依然简单地对测量求平均,由随机噪声产⽣的误差确实会被消去,然而z的时间变化也被平均掉了,从⽽引⼊了⼀种新的误差。
好一点的思路:为了估计
的值,我们只取最近的⼏次测量
求平均。
z变化很慢,且随机噪声的⽔平很⾼,选择⼀个相对长的窗求平均;
z变化很快,且噪声⽔平相对较⼩,直接使⽤
来估计
会更合适。
如果我们求加权平均,即最近的测量⽐之前的测量的贡献更⼤,那么或许效果会更好。
那么该如何定义这个加权平均?总不能handcraft吧
定义⼀个概率模型,它描述了时间的演化和测量过程。
由于模型由树结构的有向图表⽰,因此推断问题可以使⽤加和-乘积算法⾼效地求解。前向递归方程,类似于 HMM 的
信息,被称为Kalman滤波 (Kalman filter) 方程(Kalman, 1960; Zarchan and Musoff, 2005),
后向递归⽅程,类似于
信息,被称为Kalman平滑 (Kalman smoother) 方程,或者Rauch-Tung-Striebel (RTS) 方程(Rauch et al., 1965)。
单独地概率最⼤的潜在变量值组成的序列与概率 最⼤的潜在变量序列相同
转移分布:
发射分布:
初始隐变量也服从高斯分布:
以上三个式子写作矩阵形式:
其中噪声项为
由此,模型参数记作
2.2.1 LDS推断
LDS的推断要解决以观测序列为条件的隐变量的边缘概率分布。我们也希望以观测数据
为条件,对于下⼀个潜在状态
以及下 ⼀个观测
做出预测。
线性动态系统与隐马尔可夫模型具有相同的分解⽅式。
2.2.2 LDS学习
TODO
3 马尔可夫随机场 MRF什么叫随机场?
随机场是由若干个位置组成的整体,当给每一个位置中按照某种分布随机赋予一个值之后,其全体就叫做随机场。
例:假如我们有一个十个词形成的句子需要做词性标注。这十个词每个词的词性可以在我们已知的词性集合(名词,动词...)中去选择。当我们为每个词选择完词性后,这就形成了一个随机场。
马尔可夫随机场是随机场的一个具有马尔可夫性得特例,它假设随机场中某一个位置的赋值仅仅与和它相邻的位置的赋值有关,和与其不相邻的位置的赋值无关。
例:如果我们假设所有词的词性只和它相邻的词的词性有关时,这个随机场就特化成一个马尔科夫随机场。比如第三个词的词性除了与自己本身的位置有关外,只与第二个词和第四个词的词性有关。
4 条件随机场 CRF
条件随机场 Conditional Random Field 是 马尔可夫随机场 + 隐状态的特例。
区别于生成式的隐马尔可夫模型,CRF是判别式的。CRF 试图对多个随机变量(代表状态序列)在给定观测序列的值之后的条件概率进行建模:
给定观测序列
,以及隐状态序列
的情况下,构建条件概率模型
。若随机变量Y构成的是一个马尔科夫随机场,则
为CRF。
与HMM类似,CRF也关心如下三种问题:概率计算问题。
已知条件随机场
,给定观测序列
、标记序列
,求条件概率:
。
条件概率:
。
用 前向-后向算法 求解。
参数学习。
CRF 实际上是定义在时序数据上的对数线性模型,其学习方法包括:极大似然估计、正则化的极大似然估计。
用改进的迭代尺度法Improved Iterative Scaling:IIS、 梯度下降法、拟牛顿法 求解。
预测、解码问题。
给定条件随机场
,给定观测序列
,求条件概率最大的输出序列(标记序列)
,其中
。
用维特比算法求解。
4.1 线性链式条件随机场 linear-CRF / chain-structured CRFX和Y有相同的结构的CRF
四、条件随机场 CRF - 图17
给定观测变量序列
, 隐状态序列
,链式条件随机场主要包含两种关于标记变量的团:单个标记变量与
构成的团:
。
相邻标记变量与
构成的团:
。
对于单个变量的团是满足马尔可夫性的:
那么 CRF 的参数学习是在学什么?
特征函数和其权重系数。
注意:特征函数听着玄学,实际上就是个bool值,只能是0或者1。
与马尔可夫随机场定义联合概率的方式类似,条件随机场使用势函数和团来定义条件概率
:
其中: :在已知观测序列情况下,两个相邻标记位置上的转移特征函数transition feature function。它刻画了相邻标记变量之间的相关关系,以及观察序列
对它们的影响。
位置变量
也对势函数有影响。比如:已知观测序列情况下,相邻标记取值(代词,动词)出现在序列头部可能性较高,而(动词,代词)出现在序列头部的可能性较低。
:在已知观察序列情况下,标记位置
上的状态特征函数 status feature function。它刻画了观测序列
对于标记变量的影响。
位置变量
也对势函数有影响。比如:已知观测序列情况下,标记取值 名词出现在序列头部可能性较高,而 动词 出现在序列头部的可能性较低。
为参数,
为规范化因子(它用于确保上式满足概率的定义)。
为转移特征函数的个数,
为状态特征函数的个数。特征函数和权重系数的实际意义是什么?
每个特征函数定义了一个linear-CRF的规则,则其系数定义了这个规则的可信度。所有的规则和其可信度一起构成了我们的linear-CRF的最终的条件概率分布。
4.2 linear-CRF 的矩阵形式
简化特征函数
假设总共有
个特征函数。我们用一个特征函数
来表示:
对
在各个序列位置求和得到:
简化权重系数
得到参数化后的linear-CRF
其中,归一化因子为
参数表示为向量
linear-CRF的内积形式
linear-CRF的矩阵形式
定义一个
的矩阵
,
为
所有可能的状态的取值个数
4.3 概率计算问题
4.3.1 定义前向概率
表示在位置
的标记是
,并且到位置
的前半部分标记序列的非规范化概率(即暂不考虑
)。
根据
可得
在起点处,我们定义:
写成前向向量形式:
同时
,故这样的递推公式用矩阵乘法表示为:
4.3.2 定义后向概率
同理,后向递推的矩阵乘法表示为
在终点处
4.3.3 linear-CRF的前向后向概率计算
由此可得到 序列位置
的标记是
时的条件概率
:
也容易计算序列位置i的标记是
,位置i−1的标记是
时的条件概率
:
其中
4.3.4 linear-CRF的前向后向期望计算
有了上一节计算的条件概率,我们也可以很方便的计算联合分布
与条件分布
的期望。
特征函数
关于条件分布
的期望表达式是:
同时,联合分布的期望为:
4.3.5 Python 实现
借助 sklearn-crfsuite 库实现,和 sklearn 格式一样,文档链接
import sklearn_crfsuite
# 这里的 crf 在 4.4.2 节定义
# observed_xseq: new observations
observed_xseq = ... # type -> list of dicts
# y_probs: predicted probabilities for each label at each position
y_probs = crf.predict_marginals_single(observed_xseq) # type -> list of dicts
4.4 CRF参数学习算法
4.4.1 改进的迭代尺度法、拟牛顿法
详见 链接
4.4.2 Python 实现
借助 sklearn_crfsuite 库实现,和 sklearn 格式一样,文档链接
import sklearn_crfsuite
X_train = ...
y_train = ...
crf = sklearn_crfsuite.CRF(
algorithm='lbfgs',
c1=0.1,
c2=0.1,
max_iterations=100,
all_possible_transitions=True
)
crf.fit(X_train, y_train)
# CPU times: user 32 s, sys: 108 ms, total: 32.1 s
# Wall time: 32.3 s
y_pred = crf.predict(X_test)
metrics.flat_f1_score(y_test, y_pred,
average='weighted', labels=labels)
# 0.76980231377134023
此外,还可以尝试一下 PyStruct 库,文档链接
4.5 预测问题
4.5.1 linear-CRF 维特比算法解码
给定条件随机场
,给定观测序列
,求条件概率最大的输出序列(标记序列)
。
维特比算法本身是一个动态规划算法,利用了两个局部状态和对应的递推公式,从局部递推到整体,进而得解。对于具体不同的问题,仅仅是这两个局部状态的定义和对应的递推公式不同而已。由于在之前已详述维特比算法,这里就是做一个简略的流程描述。
对于我们linear-CRF中的维特比算法,我们的第一个局部状态定义为
,表示在位置
标记
各个可能取值
对应的非规范化概率的最大值。
根据
的定义,我们递推在位置
标记
的表达式为:
和HMM的维特比算法类似,我们需要用另一个局部状态
来记录使
达到最大的位置
的标记取值,这个值用来最终回溯最优解,
的递推表达式为:
4.5.2 linear-CRF 维特比算法流程
输入:模型的KK个特征函数,和对应的K个权重。观测序列x=(x1,x2,...xn)x=(x1,x2,...xn),可能的标记个数mm
输出:最优标记序列y∗=(y∗1,y∗2,...y∗n)初始化:
对于
,进行递推:
终止:
回溯:
最后得到最优标记序列
4.5.3 Python 实现
借助 sklearn-crfsuite 库实现,和 sklearn 格式一样,文档链接
import sklearn_crfsuite
# observed_xseq: new observations
observed_xseq = ... # type -> list of dicts
# y: predicted labels
y = crf.predict_single(observed_xseq) # type -> list of strings
5 Reference