1 前言

隐马尔科夫模型(Hidden Markov Model,以下简称 HMM)是比较经典的机器学习模型了,它在语音识别,自然语言处理,模式识别等领域得到广泛的应用。隐马尔科夫模型继承了马尔科夫链的性质,即马尔科夫性。关于马尔科夫性的介绍,可以参考:

随风:自然语言处理(2)主题模型 LDA (1 数学基础篇)​zhuanlan.zhihu.com

第 5 节的 5.2 马尔科夫链(Markov Chain)。

2 什么是隐马尔科夫模型?

如下图所示,假设我们有 3 个筛子,一个六面体(D6:1~6),一个四面体(D4:1~4),一个八面体(D8:1~8)。

现在我们随机选取一个筛子,假设选取了 D6,并且将 D6 抛掷一次,假设得到数字 1。下一步我们再选取一个骰子,假设选取了 D8,并且将 D8 抛掷一次,假设得到数字 6。按照上面的方法重复多次,将得到两个序列:一个是筛子的序列,另一个是数字的序列,如下图所示:

假设 A 每次掷骰子得到一个数字,B 作为观测者,只能看到每次得到的数字,而不知道是哪个骰子。我们将筛子的状态序列称为隐含序列,将数字序列称为观测序列。隐含序列具有马尔科夫性,即下一个骰子是 D4、D6 还是 D8,仅由上一个骰子决定,骰子之间的转移概率可以表示为:

而观测值由它所对应的隐含状态决定,即假设当前数字为 8,那么可以肯定它对应的隐含状态为骰子 D8,而与它前后的骰子没有关系。

上面这个例子涉及到两个序列,一个是具有马尔科夫性的骰子序列,另一个是观测序列,这就是 HMM,下面给出 HMM 的定义。

假设

是所有可能的隐含状态的集合,
是所有可能的观测状态的集合,其中 N 是所有可能的隐含状态数,M 是所有可能的观测状态数。

对于一个长度为 T 的序列,隐含状态序列

,观测序列
。其中,任意一个隐含状态
,任意一个观测状态

HMM 做了两个假设如下:

(1)马尔科夫性,即任意时刻的隐含状态只依赖于它前一个隐含状态(其实当前状态可能依赖于前面的几个状态,这样假设是为了使模型极大的简化)。如果在时刻 t 的隐含状态

,在t+1 时刻的隐含状态是
,则从 t 到 t+1 时刻的状态转移概率
可以表示为:

这样

可以组成马尔科夫链的状态转移概率矩阵:

(2)观测独立性,即任意时刻的观测状态只依赖于当前时刻的隐含状态。如果在时刻 t 的隐含状态

,而对应的观测结果为
,则该时刻观测结果
在隐含状态
下的生成概率为:

这样

可以组成观测结果生成的概率矩阵:

此外,我们还需要一组在时刻 t = 1 的隐含状态概率分布,即初始概率分布:

一个 HMM,由初始隐含概率分布

,隐含状态转移概率矩阵
,观测结果生成概率矩阵
构成,即 HMM 可以表示为:

3 关于 HMM 的三个问题

如下图所示,描述了一天的天气与人的行为的概率转移图。其中,隐含状态集合

,观测集合

现在我们连续观测三天,得到观测序列为

。初始分布为:

隐含状态转移概率矩阵为:

观测结果生成概率矩阵为:

这样我们就得到了 HMM,

针对一个 HMM,有三大问题:

  1. 评估观测序列的概率:已知

    ,求
    即给定模型
    的条件下,产生序列
    的概率。
  2. 计算隐含状态序列:已知
    ,求隐含状态序列
    。即求出最可能出现的隐含状态序列
  3. 模型参数学习:已知
    ,求
    。即给定观测序列
    求模型
    ,使得
    最大。

这三个问题的难度依次递增,下面分别求解问题 1、2。由于问题 3 的求解过于复杂(Baum-Welch算法),且在数学上只能得到局部最优解,这里不再讨论。

4 前向后向算法评估观测序列的概率

先来解决第一个问题:已知

,求
即给定模型
的条件下,产生序列
的概率。

如上图所示,当模型给定的情况下,显然,我们可以通过暴力求解的方式得到结果。比如我们的观测序列为

。假设我们从 start 开始找一条路径得到观测结果:start-Rainy(Walk)-Rainy(Shop)-Summy(Clean),这样一条路径的概率为:

这是其中一条可以形成观测序列

的路径,在图中找出所有可能的路径,分别计算概率后相加,就可以得到结果。

显然,这样计算的时间复杂度太高。那应该如何求解呢?可以通过前向后向算法求解。

4.1 前向算法求解

前向算法本质上属于动态规划的算法,也就是我们要通过找到局部状态递推的公式,这样一步步的从子问题的最优解拓展到整个问题的最优解。

定义“前向概率”:

表示 t 时刻,隐含状态为

,观测序列为
的概率。

现在假设 t 时刻的隐含状态为

,t+1 时刻的隐含状态为
,可以得到递推关系:

我们从 t=1 开始,到 T 时刻结束,由于

表示在 T 时刻观测序列为
,并且隐含状态为
的概率,因此
就表示 T 时刻观测序列为
的概率。

总结一下前向算法的过程:

输入:HMM

,观测序列

输出:观测序列出现的概率

(1)计算 t=1 的前向概率:

(2)递推 t=2,3...,T 的前向概率:

(3)计算最终结果:

下面求解一下观测序列

的概率。设

1) t=1:

2)t=2:

3)t=3:

因此

4.2 后向算法求解

后向算法和前向算法非常类似,都是用的动态规划,唯一的区别是选择的局部状态不同,后向算法用的是“后向概率”。定义“后向概率”:

表示 t 时刻,隐含状态为

,从 t+1 时刻开始到 T 时刻,观测序列为
的概率。

现在假设 t 时刻的隐含状态为

,t+1 时刻的隐含状态为
,可以得到递推关系:

总结一下前向算法的过程:

输入:HMM

,观测序列

输出:观测序列出现的概率

(1)初始化 T 时刻的隐含状态的后向概率:

注意 T 时刻以后已经没有观测序列,

对观测序列
不起作用,但不能影响前面的计算,因此取 1。

(2)递推 t=T-1,T-2,...,1 时刻的后向概率:

(3)计算最终结果:

5 Viterbi 算法计算隐含状态序列

HMM 的解码问题最常用的算法是维特比算法,当然也有其他的算法可以求解这个问题。同时维特比算法是一个通用的求序列最短路径的动态规划算法,也可以用于很多其他问题。

5.1 最短路径问题

先来看一个问题,如下图所示,描述了各个节点之间的距离。比如从 A 走到 E,可以走的路线是 A-B1-C1-D1-E,这条路线的距离为 6+5+7+4=22。现在的问题是,选择哪条路径从 A 到 E 的距离最短呢?

当然可以通过暴力求解的方式遍历从 A 到 E 的所有路径,求出最小的。显然,这种方法的时间复杂度太高。那么有没有更简单的方法呢?

将上图先改造成这样:

如果我们知道 A-D1、A-D2、A-D3 的最短路径(对应图中三个问号),就可以很容易的得到 A-E 的最短路径。

为了确定从哪个 D 到 E 才是最短的,我们就必须确定 A 到每一个 D 的最短路径,这样 A-E 的最短路径问题,就变成了 A-D 的最短路径问题。我们把一个问题变为了求解它的子问题,这不正是动态规划的思想吗?

要求解 A-D 的最短路径,就需要分别求出 A-D1、A-D2、A-D3 的最短路径,然后取最小的一个。假设我们先求解 A-D1 的最短路径,如下图:

又需要求解 A-C 的最短路径,先来看一下 A-C1 的最短路径:

哈哈,小学生都会了!好了,现在我们从前往后来完整的推一遍。

1)A-C 的最短路径:

A-C1 的路径(6+5,7+4,5+4),显然 A-C1 的最短路径为 9,路径为 A-B3-C1

A-C2 的路径(6+6,7+3,5+6),显然 A-C2 的最短路径为 10,路径为 A-B2-C2

A-C3 的路径(6+9,7+7,5+6),显然 A-C1 的最短路径为 11,路径为 A-B3-C3

因此 A-C 的最短路径为 A-B3-C1,距离为 9

2)A-D 的最短路径:

A-D1 的路径(9+8,10+5,11+5),显然 A-D1 的最短路径为 15,路径为 A-B2-C2-D1

A-D2 的路径(9+7,10+4,11+7),显然 A-D2 的最短路径为 14,路径为 A-B2-C2-D2

A-D3 的路径(9+3,10+3,11+6),显然 A-D3 的最短路径为 12,路径为 A-B3-C1-D3

因此 A-D 的最短路径为 A-B3-C1-D3,距离为12

3)A-E 的最短路径:

显然,A-E 的最短路径为 A-B3-C1-D3-E, 距离为 17。这样我们就用一层层的递推方法解决了最短路径问题,这就是 Viterbi 算法。

5.2 计算隐含状态序列问题

还是以上面这张图为例,来构建一个类似于最短路径问题的网络:

其中 R 表示 Rainy,S 表示 Sunny。下面求解一下观测序列

的情况下,最可能出现的隐含状态序列

注意这里和最短路径问题的区别,这里的距离换成了状态转移概率,概率之间变成了相乘的关系而不是相加,我们要求的问题也变成了求一条路径最大的概率。再来看一下从状态到观测结果的概率:

注意前面的节点表示隐含状态,发射出去的节点表示观测结果,因此状态到结果的概率也称为发射概率。下面按照 Viterbi 算法的过程来求解:

1)Start-2 且产生

观测的最大概率

A-R2 的路径(Start-R1-R2,Start-S1-R2),概率为(0.6*0.1*0.7*0.4,0.4*0.6*0.4*0.4)=(0.0168,0.0384),显然 A-R2 的最大概率为 0.0384,路径为 Start-S1-R2。

A-S2 的路径(Start-R1-S2,Start-S1-S2),概率为(0.6*0.1*0.3*0.3,0.4*0.6*0.6*0.3)=(0.0054,0.0432),显然 A-S2 的最大概率为 0.0432,路径为 Start-S1-S2。

因此 Start-2 的最大路径为 Start-S1-S2,概率为 0.0432

2)Start-3 且产生

观测的最大概率

A-R3 的路径(Start-S1-R2-R3,Start-S1-S2-R3),概率为(0.0384*0.7*0.5,0.0432*0.4*0.5)=(0.01344,0.00864),显然 A-R3 的最大概率为 0.01344,路径为 Start-S1-R2-R3。

A-S3 的路径(Start-S1-R2-RS3,Start-S1-S2-S3),概率为(0.0384*0.3*0.1,0.0432*0.6*0.1)=(0.001152,0.0025924),显然 A-S3 的最大概率为 0.0025924,路径为 Start-S1-S2-S3。

因此 Start-3 的最大路径为 Start-S1-R2-R3,概率为 0.01344。

这样我们就得到了隐含状态序列

。这就是采用 Viterbi 算法求解隐含状态序列的过程。下面整理一下 Viterbi 算法的求解过程。

首先定义两个变量:

1)定义变量

表示在 t 时刻,隐含状态
,找到一组隐含状态序列
,使得组成的隐含状态序列
与生成的观测序列
的联合概率最大:

注意这里不但要考虑每一个时刻隐含状态产生观测结果的概率,还需要考虑从当前隐含状态转移到下一个隐含状态的概率,使其概率乘积尽可能大,所以用联合概率表示。

可以得到递推关系式:

2)定义变量

表示在 t 时刻,隐含状态
,在 t-1 时刻,隐含状态
且对于

任意 t-1 时刻的状态

,都已经找到了一组隐含序列
,使得隐含状态蓄列
与观测序列
的联合概率最大。现在需要确定 t-1 时刻的状态
,使得上述联合分布概率乘以状态转移概率
最大,即从
转移到
的概率:

正如我们在定义变量

里面所谈到的注意事项,变量
不仅要求 t-1 时刻的联合概率最大,而且要求向 t 时刻状态转移的概率最大,综合考虑这两者,即要求两者乘积最大。

注意这里

的含义并不是要求出最大概率是多少,arg 表示使得这个概率最大的状态
是哪一个状态,比如是 Rainy 或者 Sunny。

有了这两个变量,我们就可以从 t=1 一直递推到 t=T,利用

记录的前一个最可能的状态节点回溯,直到找到最优的隐藏状态序列。

现在就可以总结下 Viterbi 算法的流程:

输入:HMM

,观测序列

输出:最有可能的隐含状态序列

1)初始化变量

2)递推 t=2,3,...,T 时刻的变量:

3)计算 T 时刻最大的

,即为最可能的隐含序列的出现概率;计算 T 时刻最大的
,即为 T 时刻最可能的隐含状态:

4)因为之前每一步都计算了

,现在通过回溯
,就可以找到最可能的隐含状态序列

6 HMM 实战

来看一个词性标注问题。比如有这样一句话:“I like nlp”,现在要标注每个词的词性。这句话的词性为人称代词(PRON)、动词(VERB)、名词(NOUN)。

下面看这两句话:

  • Please book my flight for Shanghai
  • I am going to read this book in the flight

这两句话中, book 的含义不同,如果我们能标注 book 的词性,就能够消除歧义。另一方面,在做词频统计时,我们应该区分这两个 book,即(book_VB,1),(book_NN,1)。这样做可以强化基于单词的特征。

看下面这张图,一句话中的每个单词,是以一定的概率选择某个词性,再从该词性中以一定概率选择某个词(有点像 LDA)。在 HMM 中,我们把一句话的词性序列看作隐含状态序列,把单词序列看作观测结果序列。

以“I like nlp”这句话为例,因为 HMM 需要开始状态,我们在一句话的开始位置添加 Start,结束位置添加 End。这句话就变成了“Start I like nlp End”。这句话出现的概率为:

公式里面有两个变量需要求解,一个是词性的隐含状态转移概率,即隐含状态转移概率矩阵 A;另一个是词性到词语的喷射概率,即观测结果生成的概率矩阵 B。这就需要一个已经标注过词性的语料库,假设我们有了这样一个语料库,就可以通过统计的方法计算这两个变量:

1)

。其中 i,j 表示两种词性,
表示语料库中先出现 i,再出现 j 的次数,
表示语料库中 i 出现的次数。

2)

。其中 k 表示单词,i 表示词性,
表示单词 k 的词性是 i 的次数,
表示单词 k 出现的次数。

HMM 还有一个参数是初始状态

,由于我们在语料库中每句话的起始位置加入了 Start,这样就可以按照上述方法统计从 Start 转移到任意词性的概率,这就是初始状态。这样我们就得到了 HMM:

词性标注问题属于 HMM 的第二类问题,即已知一句话(观测序列),需要找到出现概率最大的词性序列(隐含序列)。这里的语料库使用 nltk 自带的布朗大学标注的语料库来生成 HMM。

import nltk
from nltk.corpus import brown# 获取状态转移矩阵 A
def get_tags_pro(brown_tags):cfd_tags = nltk.ConditionalFreqDist(nltk.bigrams(brown_tags))cpd_tags = nltk.ConditionalProbDist(cfd_tags, nltk.MLEProbDist)return cpd_tags# 获取喷射矩阵 B
def get_tags_words_pro(brown_tags_words):cfd_tag_words = nltk.ConditionalFreqDist(brown_tags_words)cpd_tag_words = nltk.ConditionalProbDist(cfd_tag_words, nltk.MLEProbDist)return cpd_tag_words# viterbi 算法
def exc_viterbi(distinct_tags, tags_pro, tags_words_pro, sentence):values = []traces = []# 初始化first_value = {}first_layer = {}for tag in distinct_tags:if tag == 'START': continuefirst_value[tag] = tags_pro['START'].prob(tag) * tags_words_pro[tag].prob(sentence[0])first_layer[tag] = 'START'values.append(first_value)traces.append(first_layer)best_current_tag = max(first_value.keys(), key=lambda tag: first_value[tag])print("Word", "'" + sentence[0] + "'", "current best two-tag sequence:", first_layer[best_current_tag], best_current_tag)# 递推关系for word_index in range(1, len(sentence)):this_value = {}this_layer = {}prev_value = values[-1]for tag in distinct_tags:if tag == 'START': continuebest_prev_tag = max(prev_value.keys(), key=lambda prev_tag: prev_value[prev_tag] * tags_pro[prev_tag].prob(tag) * tags_words_pro[tag].prob(sentence[word_index]))this_value[tag] = prev_value[best_prev_tag] * tags_pro[best_prev_tag].prob(tag) * tags_words_pro[tag].prob(sentence[word_index])this_layer[tag] = best_prev_tagbest_current_tag = max(this_value.keys(), key=lambda tag: this_value[tag])print("Word", "'" + sentence[word_index] + "'", "current best two-tag sequence:", this_layer[best_current_tag], best_current_tag)values.append(this_value)traces.append(this_layer)# 语句最后一个单词到结束词 End 的处理prev_value = values[-1]best_prev_tag = max(prev_value.keys(), key=lambda prev_tag: prev_value[prev_tag] * tags_pro[prev_tag].prob('END'))best_pro = prev_value[best_prev_tag] * tags_pro[best_prev_tag].prob('END')best_tag_seq = ['END', best_prev_tag]traces.reverse()current_best_tag = best_prev_tagfor trace in traces:best_tag_seq.append(trace[current_best_tag])current_best_tag = trace[current_best_tag]best_tag_seq.reverse()return best_tag_seq, best_probrown_tags_words = []
for sent in brown.tagged_sents():# 先加开头brown_tags_words.append(('START', 'START'))# 为了省事儿,我们把 tag 都省略成前两个字母brown_tags_words.extend([(tag, word) for (word, tag) in sent])# 加个结尾brown_tags_words.append(('END', 'END'))brown_tags = [tag for (tag, word) in brown_tags_words]
tags_pro = get_tags_pro(brown_tags)tags_words_pro = get_tags_words_pro(brown_tags_words)distinct_tags = set(brown_tags)
sentence = ['I', 'like', 'nature', 'language', 'processing']
best_tag_seq, best_pro = exc_viterbi(distinct_tags, tags_pro, tags_words_pro, sentence)print('the best hidden seq: ', best_tag_seq)
print('the best pro: ', best_pro)结果:
Word 'I' current best two-tag sequence: START PPSS
Word 'like' current best two-tag sequence: PPSS VB
Word 'nature' current best two-tag sequence: VB NN
Word 'language' current best two-tag sequence: NN NN
Word 'processing' current best two-tag sequence: NN NN
the best hidden seq:  ['START', 'PPSS', 'VB', 'NN', 'NN', 'NN', 'END']
the best pro:  3.0637465502036634e-22

可以看到,标注的结果是正确的,但是概率非常低。从原理来看,HMM 在解决词性标注问题的效果,完全依赖于语料库的好坏,个人感觉布朗大学的这个语料库不是很好,如果能找到更丰富的语料库,出现概率应该会有明显提升。

hmm 求隐藏序列_自然语言处理(3)隐马尔科夫模型 HMM相关推荐

  1. python地图匹配_基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法

    1. 摘要 本篇博客简单介绍下用隐马尔科夫模型(Hidden Markov Model, HMM)来解决地图匹配(Map-Matching)问题.转载请注明网址. 2. Map-Matching(MM ...

  2. 隐马尔科夫模型(HMM)算法的理解与超详细推导

    今天看了徐亦达教授的HMM讲解,感觉有所收获,并将隐马尔科夫模型算法的推导整理了一下,帮助大家一起理解这个算法.首先我们通过一个股票的案例来引入这个算法,我们来看看这个股票行情和涨跌观测值的一个状态图 ...

  3. 一、隐马尔科夫模型HMM

    隐马尔科夫模型HMM(一)HMM模型基础 隐马尔科夫模型(Hidden Markov Model,以下简称HMM)是比较经典的机器学习模型了,它在语言识别,自然语言处理,模式识别等领域得到广泛的应用. ...

  4. 隐马尔科夫模型 (HMM) 算法介绍及代码实现

    Table of Contents Hidden Markov Model (隐马尔科夫模型) 定义 基本问题 前向算法 算法流程 实现代码 后向算法 算法流程 实现代码 Viterbi算法 算法流程 ...

  5. 【NLP】用于语音识别、分词的隐马尔科夫模型HMM

    大家好,今天介绍自然语言处理中经典的隐马尔科夫模型(HMM).HMM早期在语音识别.分词等序列标注问题中有着广泛的应用. 了解HMM的基础原理以及应用,对于了解NLP处理问题的基本思想和技术发展脉络有 ...

  6. 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数

    在本篇我们会讨论HMM模型参数求解的问题,这个问题在HMM三个问题里算是最复杂的.在研究这个问题之前,建议先阅读这个系列的前两篇以熟悉HMM模型和HMM的前向后向算法,以及EM算法原理总结,这些在本篇 ...

  7. m基于隐马尔科夫模型(HMM)的手机用户行为预测(MMUB)算法matlab仿真

    目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 隐马尔可夫模型(Hidden Markov Model,HMM)是一种统计模型,广泛应用在语音识别, ...

  8. 隐马尔科夫模型HMM自学 (2)

    HMM 定义 崔晓源 翻译 HMM是一个三元组 (,A,B).  the vector of the initial state probabilities;  the state transitio ...

  9. 第九章 隐马尔科夫模型HMM

    文章目录 1 隐马尔科夫模型定义 2 概率计算算法 2.1 前向概率 2.2 概率计算 3 学习算法 3.1 EM算法 3.2EM在HMM 4 预测算法 1 隐马尔科夫模型定义 隐马尔科夫模型是一个s ...

  10. 隐马尔科夫模型(HMM)择时应用的量化策略

    HMM模型 隐马尔科夫模型(HMM)择时应用的量化策略. 仅为研究学习使用, 不作为任何投资策略建议. 文章内容从各处整理汇总而成, 感谢各位大神分享.  具体策略代码均调试通过. 一.从大奖章讲起 ...

最新文章

  1. jwt 私钥_一分钟带你了解JWT认证
  2. iOS开发 关于启动页和停留时间的设置
  3. 怎样把字符1变成数字1
  4. 1%学者拥有21%引用量,全球学术圈两极分化扩大
  5. Android反编译apk并重新打包签名(Mac环境)
  6. 2019研究生数学建模比赛题目
  7. Symbian编程总结-图形图像篇-打开非Bitmap类型的图像
  8. ASP.NET Web API中展示实体Link相关的方面
  9. 前端学习(1815):前端调试之css flex 练习1
  10. 组合数的和(java)
  11. 「技术大牛」是如何缩短事件平均解决时间的?
  12. python精简总结
  13. python3使用pickle读取文件提示TypeError或者UnicodeDecodeError的解决办法
  14. ElementUI:input表单验证
  15. Could not read JSON: Cannot construct instance of `java.util.ArrayList$SubList`Redis反序列化异常
  16. 人物动画计算机课教学反思,flash课教学反思
  17. 在线搜索全网音乐支持歌曲外链下载等源码[免费开源]
  18. 你真的懂协程 (Coroutine) 吗 ? Kotlin Coroutines — Suspending Functions
  19. 强化学习笔记一 N-armed bandit Problem
  20. 本机号码认证黑科技:极光(JG)开发者服务推出“极光认证”新产品

热门文章

  1. Fedora上配置一个安全FTP
  2. C++编译器默默编写并调用哪些函数
  3. Shell脚本中date的用法小结
  4. Qt-Qt Creator的下载、安装与配置(Windows)
  5. mysql最小费用最大流问题_最小费用最大流问题
  6. 域做文件服务器,linux 做域文件服务器
  7. js parsefloat 精度_javascript中的float运算精度
  8. python中怎么替换字母_python去除拼音声调字母,替换为字母的方法
  9. 自动化比手工测试成本高?使用Selenium评估测试自动化的ROI指标
  10. oracle11g 时间失效,关于oracle11g RAC 的CTSS与ntp时间同步的疑问