隐马尔可夫(HMM)好讲,简单易懂不好讲。

用最经典的例子,掷骰子。假设我手里有三个不同的骰子。第一个骰子是我们平常见的骰子(称这个骰子为D6),6个面,每个面(1,2,3,4,5,6)出现的概率是1/6。第二个骰子是个四面体(称这个骰子为D4),每个面(1,2,3,4)出现的概率是1/4。第三个骰子有八个面(称这个骰子为D8),每个面(1,2,3,4,5,6,7,8)出现的概率是1/8。

<img src="https://pic4.zhimg.com/435fb8d2d675dc0be95aedf27feb6b67_b.jpg" data-rawwidth="1351" data-rawheight="825" class="origin_image zh-lightbox-thumb" width="1351" data-original="https://pic4.zhimg.com/435fb8d2d675dc0be95aedf27feb6b67_r.jpg">
假设我们开始掷骰子,我们先从三个骰子里挑一个,挑到每一个骰子的概率都是1/3。然后我们掷骰子,得到一个数字,1,2,3,4,5,6,7,8中的一个。不停的重复上述过程,我们会得到一串数字,每个数字都是1,2,3,4,5,6,7,8中的一个。例如我们可能得到这么一串数字(掷骰子10次):1 6 3 5 2 7 3 5 2 4

这串数字叫做可见状态链。但是在隐马尔可夫模型中,我们不仅仅有这么一串可见状态链,还有一串隐含状态链。在这个例子里,这串隐含状态链就是你用的骰子的序列。比如,隐含状态链有可能是:D6 D8 D8 D6 D4 D8 D6 D6 D4 D8

一般来说,HMM中说到的马尔可夫链其实是指隐含状态链,因为隐含状态(骰子)之间存在转换概率(transition probability)。在我们这个例子里,D6的下一个状态是D4,D6,D8的概率都是1/3。D4,D8的下一个状态是D4,D6,D8的转换概率也都一样是1/3。这样设定是为了最开始容易说清楚,但是我们其实是可以随意设定转换概率的。比如,我们可以这样定义,D6后面不能接D4,D6后面是D6的概率是0.9,是D8的概率是0.1。这样就是一个新的HMM。

同样的,尽管可见状态之间没有转换概率,但是隐含状态和可见状态之间有一个概率叫做输出概率(emission probability)。就我们的例子来说,六面骰(D6)产生1的输出概率是1/6。产生2,3,4,5,6的概率也都是1/6。我们同样可以对输出概率进行其他定义。比如,我有一个被赌场动过手脚的六面骰子,掷出来是1的概率更大,是1/2,掷出来是2,3,4,5,6的概率是1/10。

<img src="https://pic1.zhimg.com/95b60935725125a126e02e370c595000_b.jpg" data-rawwidth="1508" data-rawheight="781" class="origin_image zh-lightbox-thumb" width="1508" data-original="https://pic1.zhimg.com/95b60935725125a126e02e370c595000_r.jpg">
<img src="https://pic2.zhimg.com/53193f484ae89279da5a717a9d756089_b.jpg" data-rawwidth="1384" data-rawheight="731" class="origin_image zh-lightbox-thumb" width="1384" data-original="https://pic2.zhimg.com/53193f484ae89279da5a717a9d756089_r.jpg">
其实对于HMM来说,如果提前知道所有隐含状态之间的转换概率和所有隐含状态到所有可见状态之间的输出概率,做模拟是相当容易的。但是应用HMM模型时候呢,往往是缺失了一部分信息的,有时候你知道骰子有几种,每种骰子是什么,但是不知道掷出来的骰子序列;有时候你只是看到了很多次掷骰子的结果,剩下的什么都不知道。如果应用算法去估计这些缺失的信息,就成了一个很重要的问题。这些算法我会在下面详细讲。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
如果你只想看一个简单易懂的例子,就不需要往下看了。
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
说两句废话,答主认为呢,要了解一个算法,要做到以下两点:会其意,知其形。答主回答的,其实主要是第一点。但是这一点呢,恰恰是最重要,而且很多书上不会讲的。正如你在追一个姑娘,姑娘对你说“你什么都没做错!”你要是只看姑娘的表达形式呢,认为自己什么都没做错,显然就理解错了。你要理会姑娘的意思,“你赶紧给我道歉!”这样当你看到对应的表达形式呢,赶紧认错,跪地求饶就对了。数学也是一样,你要是不理解意思,光看公式,往往一头雾水。不过呢,数学的表达顶多也就是晦涩了点,姑娘的表达呢,有的时候就完全和本意相反。所以答主一直认为理解姑娘比理解数学难多了。

回到正题,和HMM模型相关的算法主要分为三类,分别解决三种问题:

1)知道骰子有几种(隐含状态数量),每种骰子是什么(转换概率),根据掷骰子掷出的结果(可见状态链),我想知道每次掷出来的都是哪种骰子(隐含状态链)。
这个问题呢,在语音识别领域呢,叫做解码问题。这个问题其实有两种解法,会给出两个不同的答案。每个答案都对,只不过这些答案的意义不一样。第一种解法求最大似然状态路径,说通俗点呢,就是我求一串骰子序列,这串骰子序列产生观测结果的概率最大。第二种解法呢,就不是求一组骰子序列了,而是求每次掷出的骰子分别是某种骰子的概率。比如说我看到结果后,我可以求得第一次掷骰子是D4的概率是0.5,D6的概率是0.3,D8的概率是0.2.第一种解法我会在下面说到,但是第二种解法我就不写在这里了,如果大家有兴趣,我们另开一个问题继续写吧。

2)还是知道骰子有几种(隐含状态数量),每种骰子是什么(转换概率),根据掷骰子掷出的结果(可见状态链),我想知道掷出这个结果的概率。
看似这个问题意义不大,因为你掷出来的结果很多时候都对应了一个比较大的概率。问这个问题的目的呢,其实是检测观察到的结果和已知的模型是否吻合。如果很多次结果都对应了比较小的概率,那么就说明我们已知的模型很有可能是错的,有人偷偷把我们的骰子給换了。

3)知道骰子有几种(隐含状态数量),不知道每种骰子是什么(转换概率),观测到很多次掷骰子的结果(可见状态链),我想反推出每种骰子是什么(转换概率)。
这个问题很重要,因为这是最常见的情况。很多时候我们只有可见结果,不知道HMM模型里的参数,我们需要从可见结果估计出这些参数,这是建模的一个必要步骤。

问题阐述完了,下面就开始说解法。(0号问题在上面没有提,只是作为解决上述问题的一个辅助)

0.一个简单问题
其实这个问题实用价值不高。由于对下面较难的问题有帮助,所以先在这里提一下。

知道骰子有几种,每种骰子是什么,每次掷的都是什么骰子,根据掷骰子掷出的结果,求产生这个结果的概率。
<img src="https://pic1.zhimg.com/2ca5e20b49d2ad17963b477a5691a9e0_b.jpg" data-rawwidth="364" data-rawheight="237" class="content_image" width="364">解法无非就是概率相乘:解法无非就是概率相乘:

1.看见不可见的,破解骰子序列
这里我说的是第一种解法,解最大似然路径问题。
举例来说,我知道我有三个骰子,六面骰,四面骰,八面骰。我也知道我掷了十次的结果(1 6 3 5 2 7 3 5 2 4),我不知道每次用了那种骰子,我想知道最有可能的骰子序列。

其实最简单而暴力的方法就是穷举所有可能的骰子序列,然后依照第零个问题的解法把每个序列对应的概率算出来。然后我们从里面把对应最大概率的序列挑出来就行了。如果马尔可夫链不长,当然可行。如果长的话,穷举的数量太大,就很难完成了。

另外一种很有名的算法叫做Viterbi algorithm. 要理解这个算法,我们先看几个简单的列子。

首先,如果我们只掷一次骰子:
<img src="https://pic4.zhimg.com/cd4ede10233a8b9c33cd3921ac64bfeb_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic4.zhimg.com/cd4ede10233a8b9c33cd3921ac64bfeb_r.jpg">
看到结果为1.对应的最大概率骰子序列就是D4,因为D4产生1的概率是1/4,高于1/6和1/8.

把这个情况拓展,我们掷两次骰子:
<img src="https://pic1.zhimg.com/6790ea73a601549e1f2a8dae1abcde44_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic1.zhimg.com/6790ea73a601549e1f2a8dae1abcde44_r.jpg">
结果为1,6.这时问题变得复杂起来,我们要计算三个值,分别是第二个骰子是D6,D4,D8的最大概率。显然,要取到最大概率,第一个骰子必须为D4。这时,第二个骰子取到D6的最大概率是


同样的,我们可以计算第二个骰子是D4或D8时的最大概率。我们发现,第二个骰子取到D6的概率最大。而使这个概率最大时,第一个骰子为D4。所以最大概率骰子序列就是D4 D6。

继续拓展,我们掷三次骰子:
<img src="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_r.jpg">
同样,我们计算第三个骰子分别是D6,D4,D8的最大概率。我们再次发现,要取到最大概率,第二个骰子必须为D6。这时,第三个骰子取到D4的最大概率是

同上,我们可以计算第三个骰子是D6或D8时的最大概率。我们发现,第三个骰子取到D4的概率最大。而使这个概率最大时,第二个骰子为D6,第一个骰子为D4。所以最大概率骰子序列就是D4 D6 D4。

写到这里,大家应该看出点规律了。既然掷骰子一二三次可以算,掷多少次都可以以此类推。我们发现,我们要求最大概率骰子序列时要做这么几件事情。首先,不管序列多长,要从序列长度为1算起,算序列长度为1时取到每个骰子的最大概率。然后,逐渐增加长度,每增加一次长度,重新算一遍在这个长度下最后一个位置取到每个骰子的最大概率。因为上一个长度下的取到每个骰子的最大概率都算过了,重新计算的话其实不难。当我们算到最后一位时,就知道最后一位是哪个骰子的概率最大了。然后,我们要把对应这个最大概率的序列从后往前推出来。

2.谁动了我的骰子?
比如说你怀疑自己的六面骰被赌场动过手脚了,有可能被换成另一种六面骰,这种六面骰掷出来是1的概率更大,是1/2,掷出来是2,3,4,5,6的概率是1/10。你怎么办么?答案很简单,算一算正常的三个骰子掷出一段序列的概率,再算一算不正常的六面骰和另外两个正常骰子掷出这段序列的概率。如果前者比后者小,你就要小心了。

比如说掷骰子的结果是:
<img src="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_r.jpg">
要算用正常的三个骰子掷出这个结果的概率,其实就是将所有可能情况的概率进行加和计算。同样,简单而暴力的方法就是把穷举所有的骰子序列,还是计算每个骰子序列对应的概率,但是这回,我们不挑最大值了,而是把所有算出来的概率相加,得到的总概率就是我们要求的结果。这个方法依然不能应用于太长的骰子序列(马尔可夫链)。

我们会应用一个和前一个问题类似的解法,只不过前一个问题关心的是概率最大值,这个问题关心的是概率之和。解决这个问题的算法叫做前向算法(forward algorithm)。

首先,如果我们只掷一次骰子:
<img src="https://pic4.zhimg.com/cd4ede10233a8b9c33cd3921ac64bfeb_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic4.zhimg.com/cd4ede10233a8b9c33cd3921ac64bfeb_r.jpg">
看到结果为1.产生这个结果的总概率可以按照如下计算,总概率为0.18:
<img src="https://pic1.zhimg.com/9b76649fefc177911313c03169502614_b.jpg" data-rawwidth="1496" data-rawheight="440" class="origin_image zh-lightbox-thumb" width="1496" data-original="https://pic1.zhimg.com/9b76649fefc177911313c03169502614_r.jpg">
把这个情况拓展,我们掷两次骰子:
<img src="https://pic1.zhimg.com/6790ea73a601549e1f2a8dae1abcde44_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic1.zhimg.com/6790ea73a601549e1f2a8dae1abcde44_r.jpg">
看到结果为1,6.产生这个结果的总概率可以按照如下计算,总概率为0.05:
<img src="https://pic2.zhimg.com/a2024b20c5036e932a53753acdf67085_b.jpg" data-rawwidth="1496" data-rawheight="440" class="origin_image zh-lightbox-thumb" width="1496" data-original="https://pic2.zhimg.com/a2024b20c5036e932a53753acdf67085_r.jpg">

继续拓展,我们掷三次骰子:
<img src="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_b.jpg" data-rawwidth="1477" data-rawheight="275" class="origin_image zh-lightbox-thumb" width="1477" data-original="https://pic4.zhimg.com/82093763ebb5f0b84784206bca544063_r.jpg">
看到结果为1,6,3.产生这个结果的总概率可以按照如下计算,总概率为0.03:
<img src="https://pic3.zhimg.com/e724596267109a059701d51653d42a8a_b.jpg" data-rawwidth="1496" data-rawheight="440" class="origin_image zh-lightbox-thumb" width="1496" data-original="https://pic3.zhimg.com/e724596267109a059701d51653d42a8a_r.jpg">

同样的,我们一步一步的算,有多长算多长,再长的马尔可夫链总能算出来的。用同样的方法,也可以算出不正常的六面骰和另外两个正常骰子掷出这段序列的概率,然后我们比较一下这两个概率大小,就能知道你的骰子是不是被人换了。

3.掷一串骰子出来,让我猜猜你是谁
(答主很懒,还没写,会写一下EM这个号称算法的方法)

上述算法呢,其实用到了递归,逆向推导,循环这些方法,我只不过用很直白的语言写出来了。如果你们去看专业书籍呢,会发现更加严谨和专业的描述。毕竟,我只做了会其意,要知其形,还是要看书的。

1. 赌场风云(背景介绍)

<img src="https://pic2.zhimg.com/240ab89afad8bff33e442a8d95433831_b.jpg" data-rawwidth="500" data-rawheight="261" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic2.zhimg.com/240ab89afad8bff33e442a8d95433831_r.jpg">

最近一个赌场的老板发现生意不畅,于是派出手下去赌场张望。经探子回报,有位大叔在赌场中总能赢到钱,玩得一手好骰子,几乎是战无不胜。而且每次玩骰子的时候周围都有几个保镖站在身边,让人不明就里,只能看到每次开局,骰子飞出,沉稳落地。老板根据多年的经验,推测这位不善之客使用的正是江湖失传多年的"偷换骰子大法”(编者注:偷换骰子大法,用兜里自带的骰子偷偷换掉均匀的骰子)。老板是个冷静的人,看这位大叔也不是善者,不想轻易得罪他,又不想让他坏了规矩。正愁上心头,这时候进来一位名叫HMM帅哥,告诉老板他有一个很好的解决方案。

不用近其身,只要在远处装个摄像头,把每局的骰子的点数都记录下来。

然后HMM帅哥将会运用其强大的数学内力,用这些数据推导出

1. 该大叔是不是在出千?

2. 如果是在出千,那么他用了几个作弊的骰子? 还有当前是不是在用作弊的骰子。

3. 这几个作弊骰子出现各点的概率是多少?

天呐,老板一听,这位叫HMM的甚至都不用近身,就能算出是不是在作弊,甚至都能算出别人作弊的骰子是什么样的。那么,只要再当他作弊时,派人围捕他,当场验证骰子就能让他哑口无言。

2. HMM是何许人也?

在让HMM开展调查活动之前,该赌场老板也对HMM作了一番调查。

HMM(Hidden Markov Model), 也称隐性马尔可夫模型,是一个概率模型,用来描述一个系统隐性状态的转移和隐性状态的表现概率。

系统的隐性状态指的就是一些外界不便观察(或观察不到)的状态, 比如在当前的例子里面, 系统的状态指的是大叔使用骰子的状态,即

{正常骰子, 作弊骰子1, 作弊骰子2,...}

隐性状态的表现也就是, 可以观察到的,由隐性状态产生的外在表现特点。这里就是说, 骰子掷出的点数.

{1,2,3,4,5,6}

HMM模型将会描述,系统隐性状态的转移概率。也就是大叔切换骰子的概率,下图是一个例子,这时候大叔切换骰子的可能性被描述得淋漓尽致。

<img src="https://pic3.zhimg.com/de1e09aa9c09b1a0928f5b91ba45d352_b.jpg" data-rawwidth="500" data-rawheight="300" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic3.zhimg.com/de1e09aa9c09b1a0928f5b91ba45d352_r.jpg">

很幸运的,这么复杂的概率转移图,竟然能用简单的矩阵表达, 其中a_{ij}代表的是从i状态到j状态发生的概率

<img src="https://pic1.zhimg.com/0a28bf2d267ba6aa16dde74771796bbc_b.jpg" data-rawwidth="183" data-rawheight="67" class="content_image" width="183">

当然同时也会有,隐性状态表现转移概率。也就是骰子出现各点的概率分布, (e.g. 作弊骰子1能有90%的机会掷到六,作弊骰子2有85%的机会掷到'小’). 给个图如下,

<img src="https://pic2.zhimg.com/2f6e49ac23b9f99cc21cf9016435ae39_b.jpg" data-rawwidth="500" data-rawheight="245" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic2.zhimg.com/2f6e49ac23b9f99cc21cf9016435ae39_r.jpg">

隐性状态的表现分布概率也可以用矩阵表示出来,

<img src="https://pic3.zhimg.com/9974153a9ac8963c329c4195878c5312_b.jpg" data-rawwidth="325" data-rawheight="66" class="content_image" width="325">

把这两个东西总结起来,就是整个HMM模型。

这个模型描述了隐性状态的转换的概率,同时也描述了每个状态外在表现的概率的分布。总之,HMM模型就能够描述扔骰子大叔作弊的频率(骰子更换的概率),和大叔用的骰子的概率分布。有了大叔的HMM模型,就能把大叔看透,让他完全在阳光下现形。

3. HMM能干什么!

总结起来HMM能处理三个问题,

3.1 解码(Decoding)

解码就是需要从一连串的骰子中,看出来哪一些骰子是用了作弊的骰子,哪些是用的正常的骰子。

<img src="https://pic2.zhimg.com/4a40f1a93aa25adce92f5441e6e2cfb9_b.jpg" data-rawwidth="500" data-rawheight="200" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic2.zhimg.com/4a40f1a93aa25adce92f5441e6e2cfb9_r.jpg">

比如上图中,给出一串骰子序列(3,6,1,2..)和大叔的HMM模型, 我们想要计算哪一些骰子的结果(隐性状态表现)可能对是哪种骰子的结果(隐性状态).

3.2学习(Learning)

学习就是,从一连串的骰子中,学习到大叔切换骰子的概率,当然也有这些骰子的点数的分布概率。这是HMM最为恐怖也最为复杂的招数!!

3.3 估计(Evaluation)

估计说的是,在我们已经知道了该大叔的HMM模型的情况下,估测某串骰子出现的可能性概率。比如说,在我们已经知道大叔的HMM模型的情况下,我们就能直接估测到大叔扔到10个6或者8个1的概率。

4. HMM是怎么做到的?
4.1 估计

估计是最容易的一招,在完全知道了大叔的HMM模型的情况下,我们很容易就能对其做出估计。

现在我们有了大叔的状态转移概率矩阵A,B就能够进行估计。比如我们想知道这位大叔下一局连续掷出10个6的概率是多少? 如下

<img src="https://pic3.zhimg.com/f893ed100b894616bffef0bae9f461da_b.jpg" data-rawwidth="421" data-rawheight="21" class="origin_image zh-lightbox-thumb" width="421" data-original="https://pic3.zhimg.com/f893ed100b894616bffef0bae9f461da_r.jpg">

这表示的是,在一开始隐性状态(s0)为1,也就是一开始拿着的是正常的骰子的情况下,这位大叔连续掷出10个6的概率。

现在问题难就难在,我们虽然知道了HMM的转换概率,和观察到的状态V{1:T}, 但是我们却不知道实际的隐性的状态变化。

好吧,我们不知道隐性状态的变化,那好吧,我们就先假设一个隐性状态序列, 假设大叔前5个用的是正常骰子, 后5个用的是作弊骰子1.

<img src="https://pic3.zhimg.com/468da543a29861571622d107d845bc42_b.jpg" data-rawwidth="316" data-rawheight="21" class="content_image" width="316">

好了,那么我们可以计算,在这种隐性序列假设下掷出10个6的概率.

<img src="https://pic1.zhimg.com/4f15b94f31eb9fbe8370a1ad6b90e730_b.jpg" data-rawwidth="236" data-rawheight="54" class="content_image" width="236">
这个概率其实就是,隐性状态表现概率B的乘积.
<img src="https://pic4.zhimg.com/c1616bab1b90e3daa3b01c93a27f5c07_b.jpg" data-rawwidth="339" data-rawheight="54" class="content_image" width="339">

但是问题又出现了,刚才那个隐性状态序列是我假设的,而实际的序列我不知道,这该怎么办。好办,把所有可能出现的隐状态序列组合全都试一遍就可以了。于是,

<img src="https://pic3.zhimg.com/b007c2e9628c6db1de871bc5c52e24b6_b.jpg" data-rawwidth="317" data-rawheight="260" class="content_image" width="317">
R就是所有可能的隐性状态序列的集合。的嗯,现在问题好像解决了,我们已经能够通过尝试所有组合来获得出现的概率值,并且可以通过A,B矩阵来计算出现的总概率。

但是问题又出现了,可能的集合太大了, 比如有三种骰子,有10次选择机会, 那么总共的组合会有3^10次...这个量级O(c^T)太大了,当问题再大一点时候,组合的数目就会大得超出了计算的可能。所以我们需要一种更有效的计算P(V(1:T)概率的方法。
比如说如下图的算法可以将计算P(V1:T)的计算复杂度降低至O(cT).
<img src="https://pic4.zhimg.com/7a7efeb3e50a827cd8305f1c1dde360f_b.jpg" data-rawwidth="544" data-rawheight="675" class="origin_image zh-lightbox-thumb" width="544" data-original="https://pic4.zhimg.com/7a7efeb3e50a827cd8305f1c1dde360f_r.jpg">

有了这个方程,我们就能从t=0的情况往前推导,一直推导出P(V1:T)的概率。下面让我们算一算,大叔掷出3,2,1这个骰子序列的可能性有多大(假设初始状态为1, 也就是大叔前一次拿着的是正常的骰子)?

4.2 解码(Decoding)

解码的过程就是在给出一串序列的情况下和已知HMM模型的情况下,找到最可能的隐性状态序列。

<img src="https://pic2.zhimg.com/4a40f1a93aa25adce92f5441e6e2cfb9_b.jpg" data-rawwidth="500" data-rawheight="200" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic2.zhimg.com/4a40f1a93aa25adce92f5441e6e2cfb9_r.jpg">

用数学公式表示就是, (V是Visible可见序列, w是隐性状态序列, A,B是HMM状态转移概率矩阵)

然后又可以使用估计(4.1)中的前向推导法,计算出最大的P(w(1:T), V(1:T)).

在完成前向推导法之后,再使用后向追踪法(Back Tracking),对求解出能令这个P(w(1:T), V(1:T))最大的隐性序列.这个算法被称为维特比算法(Viterbi Algorithm).

4.3 学习(Learning)

学习是在给出HMM的结构的情况下(比如说假设已经知道该大叔有3只骰子,每只骰子有6面),计算出最有可能的模型参数.

5. HMM 的应用

以上举的例子是用HMM对掷骰子进行建模与分析。当然还有很多HMM经典的应用,能根据不同的应用需求,对问题进行建模。

但是使用HMM进行建模的问题,必须满足以下条件,

1.隐性状态的转移必须满足马尔可夫性。(状态转移的马尔可夫性:一个状态只与前一个状态有关)

2. 隐性状态必须能够大概被估计。

在满足条件的情况下,确定问题中的隐性状态是什么,隐性状态的表现可能又有哪些.

HMM适用于的问题在于,真正的状态(隐态)难以被估计,而状态与状态之间又存在联系。

5.1 语音识别

语音识别问题就是将一段语音信号转换为文字序列的过程. 在个问题里面

隐性状态就是: 语音信号对应的文字序列

而显性的状态就是: 语音信号.

<img src="https://pic1.zhimg.com/8ea5a05ed423c75e283dac52bc378604_b.jpg" data-rawwidth="500" data-rawheight="300" class="origin_image zh-lightbox-thumb" width="500" data-original="https://pic1.zhimg.com/8ea5a05ed423c75e283dac52bc378604_r.jpg">

HMM模型的学习(Learning): 语音识别的模型学习和上文中通过观察骰子序列建立起一个最有可能的模型不同. 语音识别的HMM模型学习有两个步骤:

1. 统计文字的发音概率,建立隐性表现概率矩阵B

2. 统计字词之间的转换概率(这个步骤并不需要考虑到语音,可以直接统计字词之间的转移概率即可)

语音模型的估计(Evaluation): 计算"是十四”,"四十四"等等的概率,比较得出最有可能出现的文字序列.

5.2 手写识别

这是一个和语音差不多,只不过手写识别的过程是将字的图像当成了显性序列.

5.3 中文分词

“总所周知,在汉语中,词与词之间不存在分隔符(英文中,词与词之间用空格分隔,这是天然的分词标记),词本身也缺乏明显的形态标记,因此,中文信息处理的特有问题就是如何将汉语的字串分割为合理的词语序。例如,英文句子:you should go to kindergarten now 天然的空格已然将词分好,只需要去除其中的介词“to”即可;而“你现在应该去幼儿园了”这句表达同样意思的话没有明显的分隔符,中文分词的目的是,得到“你/现在/应该/去/幼儿园/了”。那么如何进行分词呢?主流的方法有三种:第1类是基于语言学知识的规则方法,如:各种形态的最大匹配、最少切分方法;第2类是基于大规模语料库的机器学习方法,这是目前应用比较广泛、效果较好的解决方案.用到的统计模型有N元语言模型、信道—噪声模型、最大期望、HMM等。第3类也是实际的分词系统中用到的,即规则与统计等多类方法的综合。”[1]使用HMM进行中文分词.

5.4 HMM实现拼音输入法

拼音输入法,是一个估测拼音字母对应想要输入的文字(隐性状态)的过程(比如, ‘pingyin’ -> 拼音)

使用HMM实现简单拼音输入法

隐马尔可夫模型 (Hidden Markov Model,HMM) 最初由 L. E. Baum 和其它一些学者发表在一系列的统计学论文中,随后在语言识别,自然语言处理以及生物信息等领域体现了很大的价值。平时,经常能接触到涉及 HMM 的相关文章,一直没有仔细研究过,都是蜻蜓点水,因此,想花一点时间梳理下,加深理解,在此特别感谢
52nlp 对 HMM 的详细介绍。

  考虑下面交通灯的例子,一个序列可能是红-红/橙-绿-橙-红。这个序列可以画成一个状态机,不同的状态按照这个状态机互相交替,每一个状态都只依赖于前一个状态,如果当前的是绿灯,那么接下来就是橙灯,这是一个确定性系统,因此更容易理解和分析,只要这些状态转移都是已知的。但是在实际当中还存在许多不确定性系统。

  在日常生活当中,我们总是希望根据当前天气的情况来预测未来天气情况,和上面的交通灯的例子不同,我们不能依靠现有知识确定天气情况的转移,但是我们还是希望能得到一个天气的模式。一种办法就是假设这个模型的每个状态都只依赖于前一个的状态,这个假设被称为马尔科夫假设,这个假设可以极大简化这个问题。显然,这个假设也是一个非常糟糕的假设,导致很多重要的信息都丢失了。

  当涉及到天气的时候,马尔科夫假设描述为,假设如果我们知道之前一些天的天气信息,那么我们就能预测今天的天气。当然,这个例子也是有些不合实际的。但是,这样一个简化的系统可以有利于我们的分析,所以我们通常接受这样的假设,因为我们知道这样的系统能让我们获得一些有用的信息,尽管不是十分准确的。

  谈到 HMM,首先简单介绍一下马尔可夫过程 (Markov Process),它因俄罗斯数学家安德烈·马尔可夫而得名,代表数学中具有马尔可夫性质的离散随机过程。该过程中,每个状态的转移只依赖于之前的 n 个状态,这个过程被称为1个 n 阶的模型,其中 n 是影响转移状态的数目。最简单的马尔科夫过程就是一阶过程,每一个状态的转移只依赖于其之前的那一个状态。注意这和确定性系统不一样,因为这种转移是有概率的,而不是确定性的。

  马尔可夫链是随机变量 X1, … , Xn 的一个数列。这些变量的范围,即他们所有可能取值的集合,被称为“状态空间”,而 Xn  的值则是在时间 的状态。如果 Xn+1 对于过去状态的条件概率分布仅是 X的一个函数,则

  这里 为过程中的某个状态。上面这个恒等式可以被看作是马尔可夫性质

  马尔可夫链的在很多应用中发挥了重要作用,例如,谷歌所使用的网页排序算法(PageRank)就是由马尔可夫链定义的。

  下图展示了天气这个例子中所有可能的一阶转移:

  注意一个含有 N 个状态的一阶过程有 N个状态转移。每一个转移的概率叫做状态转移概率 (state transition probability),就是从一个状态转移到另一个状态的概率。这所有的 N个概率可以用一个状态转移矩阵来表示,其表示形式如下:

  对该矩阵有如下约束条件:

  下面就是海藻例子的状态转移矩阵

  这个矩阵表示,如果昨天是晴天,那么今天有50%的可能是晴天,37.5%的概率是阴天,12.5%的概率会下雨,很明显,矩阵中每一行的和都是1。

  为了初始化这样一个系统,我们需要一个初始的概率向量:

  这个向量表示第一天是晴天。

  到这里,我们就为上面的一阶马尔科夫过程定义了以下三个部分:

  状态:晴天、阴天和下雨

  初始向量:定义系统在时间为0的时候的状态的概率

  状态转移矩阵:每种天气转换的概率

  所有的能被这样描述的系统都是一个马尔科夫过程

  然而,当马尔科夫过程不够强大的时候,我们又该怎么办呢?在某些情况下,马尔科夫过程不足以描述我们希望发现的模式。

  例如,一个隐居的人可能不能直观的观察到天气的情况,但是民间传说告诉我们海藻的状态在某种概率上是和天气的情况相关的。在这种情况下我们有两个状态集合,一个可以观察到的状态集合(海藻的状态)和一个隐藏的状态(天气状况)。我们希望能找到一个算法可以根据海藻的状况和马尔科夫假设来预测天气的状况。

  一个更现实的例子是语音识别,我们听到的声音是声带、喉咙和一起其他的发音器官共同作用的结果。这些因素相互作用,共同决定了每一个单词的声音,而一个语音识别系统检测的声音(可以观察的状态)是人体内部各种物理变化(隐藏的状态、引申一个人真正想表达的意思)产生的。

  某些语音识别设备把内部的发音机制作为一个隐藏的状态序列,把最后的声音看成是一个和隐藏的状态序列十分相似的可以观察到的状态的序列。在这两个例子中,一个非常重要的地方是隐藏状态的数目和可以观察到的状态的数目可能是不一样的。在一个有3种状态的天气系统(sunny、cloudy、rainy)中,也许可以观察到4种潮湿程度的海藻(dry、dryish、damp、soggy)。在语音识别中,一个简单的发言也许只需要80个语素来描述,但是一个内部的发音机制可以产生不到80或者超过80种不同的声音。

  在上面的这些情况下,可以观察到的状态序列和隐藏的状态序列是概率相关的。于是我们可以将这种类型的过程建模为有一个隐藏的马尔科夫过程和一个与这个隐藏马尔科夫过程概率相关的并且可以观察到的状态集合。这就是本文重点介绍的隐马尔可夫模型。

  隐马尔可夫模型 (Hidden Markov Model) 是一种统计模型,用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数,然后利用这些参数来作进一步的分析。下图是一个三个状态的隐马尔可夫模型状态转移图,其中x 表示隐含状态,y 表示可观察的输出,a 表示状态转换概率,b 表示输出概率。

  下图显示了天气的例子中隐藏的状态和可以观察到的状态之间的关系。我们假设隐藏的状态是一个简单的一阶马尔科夫过程,并且他们两两之间都可以相互转换。

  对 HMM 来说,有如下三个重要假设,尽管这些假设是不现实的。

  

  假设1:马尔可夫假设(状态构成一阶马尔可夫链)

  假设2:不动性假设(状态与具体时间无关)

  假设3:输出独立性假设(输出仅与当前状态有关)

  隐藏的状态和可观察到的状态之间有一种概率上的关系,也就是说某种隐藏状态 H 被认为是某个可以观察的状态 O1 是有概率的,假设为 P(O1 | H)。如果可以观察的状态有3种,那么很显然 P(O1 | H)+P(O2 | H)+ P(O3 | H) = 1

  这样,我们也可以得到一个另一个矩阵,称为混淆矩阵 (confusion matrix)。这个矩阵的内容是某个隐藏的状态被分别观察成几种不同的可以观察的状态的概率,在天气的例子中,这个矩阵如下图:

  上边的图示都强调了 HMM 的状态变迁。而下图则明确的表示出模型的演化,其中绿色的圆圈表示隐藏状态,紫色圆圈表示可观察到状态,箭头表示状态之间的依存概率,一个 HMM 可用一个5元组 { N, M, π,A,B } 表示,其中 N 表示隐藏状态的数量,我们要么知道确切的值,要么猜测该值,M 表示可观测状态的数量,可以通过训练集获得, π={πi}
为初始状态概率,A={aij} 为隐藏状态的转移矩阵 Pr(xt(i) | xt-1(j)),B={bik} 表示某个时刻因隐藏状态而可观察的状态的概率,即混淆矩阵,Pr(ot(i) | xt(j))。在状态转移矩阵和混淆矩阵中的每个概率都是时间无关的,即当系统演化时,这些矩阵并不随时间改变。对于一个 N 和
M 固定的 HMM 来说,用 λ={ π, A, B } 表示 HMM 参数。

  在正常的马尔可夫模型中,状态对于观察者来说是直接可见的。这样状态的转换概率便是全部的参数。而在隐马尔可夫模型中,状态并不是直接可见的,但受状态影响的某些变量则是可见的。每一个状态在可能输出的符号上都有一概率分布。因此输出符号的序列能够透露出状态序列的一些信息。

  在 HMM 中有三个典型问题:

  (一) 已知模型参数,计算某一给定可观察状态序列的概率

  

假设我们已经有一个特定的隐马尔科夫模型 λ 和一个可观察状态序列集。我们也许想知道在所有可能的隐藏状态序列下,给定的可观察状态序列的概率。当给定如下一个隐藏状态序列:

  那么在 HMM 和这个隐藏状态序列的条件下,可观察状态序列的概率为:

  而隐藏状态序列在 HMM 条件下的概率为:

  因此,隐藏状态序列和可观察状态序列的联合概率为:

  那么所有可能的隐藏状态序列上,可观察状态序列的概率为:

  例如,我们也许有一个海藻的“Summer”模型和一个“Winter”模型,因为海藻在夏天和冬天的状态应该是不同的,我们希望根据一个可观察状态(海藻的潮湿与否)序列来判断现在是夏天还是冬天。

  我们可以使用前向算法来计算在某个特定的 HMM 下一个可观察状态序列的概率,然后据此找到最可能的模型。

  这种类型的应用通常出现在语音设别中,通常我们会使用很多 HMM,每一个针对一个特别的单词。一个可观察状态的序列是从一个可以听到的单词向前得到的,然后这个单词就可以通过找到满足这个可观察状态序列的最大概率的 HMM 来识别。

  下面介绍一下前向算法 (Forward Algorithm)

  如何计算一个可观察序列的概率?

  1. 穷举搜索

  给定一个 HMM,我们想计算出某个可观察序列的概率。考虑天气的例子,我们知道一个描述天气和海藻状态的 HMM,而且我们还有一个海藻状态的序列。假设这个状态中的某三天是(dry,damp,soggy),在这三天中的每一天,天气都可能是晴朗,多云或者下雨,我们可以用下图来描述观察序列和隐藏序列:

  在这个图中的每一列表示天气的状态可能,并且每个状态都指向相邻的列的每个状态,每个状态转换在状态转移矩阵中都有一个概率。每一列的下面是当天的可观察的海藻的状态,在每种状态下出现这种可观察状态的概率是由混淆矩阵给出的。

  一个可能的计算可观察概率的方法是找到每一个可能的隐藏状态的序列,这里有3= 27种,这个时候的可观察序列的概率就是 Pr(dry, damp, soggy | HMM)=Pr(dry, damp, soggy | sunny, sunny, sunny) + . . . . + Pr(dry, damp, soggy | rainy, rainy, rainy)。

  很显然,这种计算的效率非常低,尤其是当模型中的状态非常多或者序列很长的时候。事实上,我们可以利用概率不随时间变化这个假设来降低时间的开销。

  2. 使用递归来降低复杂度

  我们可以考虑给定 HMM 的情况下,递归的计算一个可观察序列的概率。我们可以首先定义一个部分概率,表示达到某个中间状态的概率。接下来我们将看到这些部分概率是如何 在time=1 和 time = n (n > 1) 的时候计算的。

  假设一个T时间段的可观察序列是:

  1) 部分概率

  下面这张图表示了一个观察序列(dry,damp,soggy)的一阶转移

  我们可以通过计算到达某个状态的所有路径的概率和来计算到达某个中间状态的概率。比如说,t=2时刻,cloudy的概率用三条路径的概率之和来表示:

  我们用 αt(j) 来表示在 t 时刻是状态 j 的概率,αt(j)=Pr(观察状态 | 隐藏状态 j ) x Pr(t 时刻到达状态 j 的所有路径)。

  最后一个观察状态的部分概率就表示了整个序列最后达到某个状态的所有可能的路径的概率和,比如说在这个例子中,最后一列的部分状态是通过下列路径计算得到的:

  因为最后一列的部分概率是所有可能的路径的概率和,所以就是这个观察序列在给定 HMM 下的概率了。

  2) 计算 t=1时候的部分概率

  当 t=1 的时候,没有路径到某个状态,所以这里是初始概率,Pr(状态 j | t=0) = π(状态 j ),这样我们就可以计算 t=1 时候的部分概率为:

  因为在初始的时候,状态 j 的概率不仅和这个状态本身相关,还和观察状态有关,所以这里用到了混淆矩阵的值,k1 表示第一个观察状态,bjk1 表示隐藏状态是 j,但是观察成 k1 的概率。

  3) 计算 t>1 时候的部分概率

  还是看计算部分概率的公式是:αt(j) = Pr(观察状态 | 隐藏状态 j) x Pr(t 时刻到达状态 j 的所有路径)。 这个公式的左边是从混淆矩阵中已知的,我只需要计算右边部分,很显然右边是所有路径的和:

  需要计算的路径数是和观察序列的长度的平方相关的,但是 t 时刻的部分概率已经计算过了之前的所有路径,所以在 t+1 时刻只需要根据 t 时刻的概率来计算就可以了:

  这里简单解释下,bjk(t+1) 就是在 t+1 时刻的第 j 个隐藏状态被认为是当前的观察状态的概率,后面一部分是所有t时刻的隐藏状态到 t+1 时候的隐藏状态j的转移的概率的和。这样我们每一步的计算都可以利用上一步的结果,节省了很多时间。

  4) 公式推导

  5) 降低计算复杂度

  我们可以比较穷举和递归算法的复杂度。假设有一个 HMM,其中有 n 个隐藏状态,我们有一个长度为 T 的观察序列。

  穷举算法的需要计算所有可能的隐藏序列:

  需要计算:

  很显然穷举算法的时间开销是和 T 指数相关的,即 NT,而如果采用递归算法,由于我们每一步都可以利用上一步的结果,所以是和 T 线性相关的,即复杂度是 N2T。

  这里我们的目的是在某个给定的 HMM 下,计算出某个可观察序列的概率。我们通过先计算部分概率的方式递归的计算整个序列的所有路径的概率,大大节省了时间。在 t=1 的时候,使用了初始概率和混淆矩阵的概率,而在t时刻的概率则可以利用 t-1 时刻的结果。

  这样我们就可以用递归的方式来计算所有可能的路径的概率和,最后,所有的部分概率的计算公式为

  使用天气的例子,计算 t=2 时刻的 cloudy 状态的概率方法如图:

  我们使用前向算法在给定的一个 HMM 下计算某个可观察序列的概率。前向算法主要采用的是递归的思想,利用之前的计算结果。有了这个算法,我们就可以在一堆 HMM 中,找到一个最满足当前的可观察序列的模型(前向算法计算出来的概率最大)。

  (二) 根据可观察状态的序列找到一个最可能的隐藏状态序列

  和上面一个问题相似的并且更有趣的是根据可观察序列找到隐藏序列。在很多情况下,我们对隐藏状态更有兴趣,因为其包含了一些不能被直接观察到的有价值的信息。比如说在海藻和天气的例子中,一个隐居的人只能看到海藻的状态,但是他想知道天气的状态。这时候我们就可以使用 Viterbi 算法来根据可观察序列得到最优可能的隐藏状态的序列,当然前提是已经有一个 HMM

  另一个广泛使用 Viterbi 算法的领域是自然语言处理中的词性标注。句子中的单词是可以观察到的,词性是隐藏的状态。通过根据语句的上下文找到一句话中的单词序列的最有可能的隐藏状态序列,我们就可以得到一个单词的词性(可能性最大)。这样我们就可以用这种信息来完成其他一些工作。

  下面介绍一下维特比算法 (Viterbi Algorithm)

  一.如何找到可能性最大的隐藏状态序列?

  通常我们都有一个特定的 HMM,然后根据一个可观察状态序列去找到最可能生成这个可观察状态序列的隐藏状态序列。

  1. 穷举搜索

  我们可以在下图中看到每个隐藏状态和可观察状态的关系。

  通过计算所有可能的隐藏序列的概率,我们可以找到一个可能性最大的隐藏序列,这个可能性最大的隐藏序列最大化了 Pr(观察序列 | 隐藏状态集)。比如说,对于上图中的可观察序列 (dry damp soggy),最可能的隐藏序列就是下面这些概率中最大的:

  Pr(dry, damp, soggy | sunny, sunny, sunny), ……,Pr(dry, damp, soggy | rainy, rainy, rainy)

  这个方法是可行的,但是计算代价很高。和前向算法一样,我们可以利用转移概率在时间上的不变性来降低计算的复杂度。

  2. 使用递归降低复杂度

  在给定了一个可观察序列和HMM的情况下,我们可以考虑递归的来寻找最可能的隐藏序列。我们可以先定义一个部分概率 δ,即到达某个中间状态的概率。接下来我们将讨论如何计算 t=1 和 t=n (n>1) 的部分概率。

  注意这里的部分概率和前向算法中的部分概率是不一样的,这里的部分概率表示的是在t时刻最可能到达某个状态的一条路径的概率,而不是所有概率之和

  1) 部分概率和部分最优路径

  考虑下面这个图以及可观察序列 (dry, damp, soggy) 的一阶转移

  对于每一个中间状态和终止状态 (t=3) 都有一个最可能的路径。比如说,在 t=3 时刻的三个状态都有一个如下的最可能的路径:

  我们可以称这些路径为部分最优路径。这些部分最优路径都有一个概率,也就是部分概率 δ。和前向算法中的部分概率不一样,这里的概率只是一个最可能路径的概率,而不是所有路径的概率和。

  我们可以用 δ(i, t) 来表示在t时刻,到状态i的所有可能的序列(路径)中概率最大的序列的概率,部分最优路径就是达到这个最大概率的路径,对于每一个时刻的每一个状态都有这样一个概率和部分最优路径。

  最后,我们通过计算 t=T 时刻的每一个状态的最大概率和部分最优路径,选择其中概率最大的状态和它的部分最优路径来得到全局的最优路径。

  2) 计算 t=1 时刻的部分概率

  当 t=1 时刻的时候,到达某个状态最大可能的路径还不存在,但是我们可以直接使用在 t=1 时刻某个状态的概率和这个状态到可观察序列 k的转移概率:

  3) 计算 t>1 时刻的部分概率

  接下来我们可以根据 t-1 时刻的部分概率来求 t 时刻的部分概率

  我们可以计算所有到状态 X 的路径的概率,找到其中最可能的路径,也就是局部最优路径。注意到这里,到达X的路径必然会经过 t-1 时刻的 A、B 和 C,所以我们可以利用之前的结果。达到X的最可能的路径就是下面三个之一:

  (状态序列),. . .,A,X (状态序列),. . .,B,X (状态序列),. . .,C,X

  我们需要做的就是找到以 AX、BX 和 CX 结尾的路径中概率最大的那个。

  根据一阶马尔科夫的假设,一个状态的发生之和之前的一个状态有关系,所以X在某个序列的最后发生的概率只依赖于其之前的一个状态:

Pr (到达A的最优路径) . Pr (X | A) . Pr (观察状态 | X)

  有个了这个公式,我们就可以利用t-1时刻的结果和状态转移矩阵和混淆矩阵的数据:

  将上面这个表达式推广一下,就可以得到 t 时刻可观察状态为 k的第 i 个状态的最大部分概率的计算公式:

  其中 aji 表示从状态 j 转移到状态 i 的概率,bikt 表示状态i被观察成 kt 的概率。

  4) 后向指针

  考虑下图

  在每一个中间状态和结束状态都有一个部分最优概率 δ(i, t)。但是我们的目的是找到最可能的隐藏状态序列,所以我们需要一个方法去记住部分最优路径的每一个节点。

  考虑到要计算 t 时刻的部分概率,我们只需要知道 t-1 时刻的部分概率,所以我们只需要记录那个导致了 t 时刻最大部分概率的的状态,也就是说,在任意时刻,系统都必须处在一个能在下一时刻产生最大部分概率的状态。如下图所示:

  我们可以利用一个后向指针 φ 来记录导致某个状态最大局部概率的前一个状态,即

  这里 argmax 表示能最大化后面公式的j值,同样可以发现这个公式和 t-1 时刻的部分概率和转移概率有关,因为后向指针只是为了找到“我从哪里来”,这个问题和可观察状态没有关系,所以这里不需要再乘上混淆矩阵因子。全局的行为如下图所示:

  5) 优点

  使用 viterbi 算法对一个可观察状态进行解码有两个重要的优点:

  a) 通过使用递归来减少复杂度,这点和之前的前向算法是一样的

  b) 可以根据可观察序列找到最优的隐藏序列,这个的计算公式是:

其中 

  这里就是一个从左往右翻译的过程,通过前面的翻译结果得到后面的结果,起始点是初始向量 π。

  3. 补充

  但在序列某个地方有噪声干扰的时候,某些方法可能会和正确答案相差的较远。但是 Viterbi 算法会查看整个序列来决定最可能的终止状态,然后通过后向指针来找到之前的状态,这对忽略孤立的噪声非常有用。

  Viterbi 算法提供了一个根据可观察序列计算隐藏序列的很高效的方法,它利用递归来降低计算复杂度,并且使用之前全部的序列来做判断,可以很好的容忍噪声。

  在计算的过程中,这个算法计算每一个时刻每一个状态的部分概率,并且使用一个后向指针来记录达到当前状态的最大可能的上一个状态。最后,最可能的终止状态就是隐藏序列的最后一个状态,然后通过后向指针来查找整个序列的全部状态。

  (三) 根据观察到的序列集来找到一个最有可能的 HMM。 

  在很多实际的情况下,HMM 不能被直接的判断,这就变成了一个学习问题,因为对于给定的可观察状态序列 O 来说,没有任何一种方法可以精确地找到一组最优的 HMM 参数 λ 使 P(O | λ) 最大,于是人们寻求使其局部最优的解决办法,而前向后向算法(也称为Baum-Welch算法)就成了 HMM学习问题的一个近似的解决方法。

  前向后向算法首先对于 HMM 的参数进行一个初始的估计,但这个很可能是一个错误的猜测,然后通过对于给定的数据评估这些参数的的有效性并减少它们所引起的错误来更新 HMM 参数,使得和给定的训练数据的误差变小,这其实是机器学习中的梯度下降的思想。

  对于网格中的每一个状态,前向后向算法既计算到达此状态的“前向”概率,又计算生成此模型最终状态的“后向”概率,这些概率都可以通过前面的介绍利用递归进行高效计算。可以通过利用近似的 HMM 模型参数来提高这些中间概率从而进行调整,而这些调整又形成了前向后向算法迭代的基础。

  另外,前向后向算法是 EM 算法的一个特例,它避免了 EM 算法的暴力计算,而采用动态规划思想来解决问题,Jelinek 在其书《Statistical Methods for Speech Recognition》中对前向后向算法与 EM 算法的关系进行了详细描述,有兴趣的读者可以参考这本书。

  类似于上面讲到的前向算法,我们也可以定义后向变量 βt(i) 来计算给定当前隐藏状态 i 时,部分观察序列 ot+1,ot+2,…,oT的概率,即:

  与前向算法类似,我们也可以通过迭代算法有效计算 βt(i),计算公式如下:

  其中

  进一步我们可以发现

  因此

  下面开始介绍前向后向算法

  首先我们需要定义两个辅助变量,这两个变量可以用前文介绍过的前向变量和后向变量进行定义。

  第一个变量定义为 t 时状态 i 和 t+1 时状态 j 的概率,即

  该变量在网格中所代表的关系如下图所示:

  

  该等式等价于

  利用前向变量和后向变量,上式可以表示为

  第二个变量定义为后验概率,也就是在给定观察状态序列和 HMM 的情况下,t 时状态 i 的概率,即

  利用前向变量和后向变量,上式可以表示为

  因此,下式为在任意时刻状态 i 的期望,也就是从状态 i 转移到观察状态 o 的期望

  同样,下式也就是从状态 i 转移到状态 j 的期望

  我们可以发现定义的这两个变量之间的关系为

  下面介绍前向后向算法的参数学习过程,在学习的过程中,不断更新 HMM 的参数,从而使得 P(O | λ) 最大。我们假设初始的 HMM 参数为  λ={ π, A, B },首先计算前向变量 α 和后向变量 β,再根据刚刚介绍的公式计算期望 ξ 和 ζ,最后,根据下面的3个重估计公式更新 HMM 参数。

  如果我们定义当前的 HMM 模型为 λ={ π,A,B },那么可以利用该模型计算上面三个式子的右端;我们再定义重新估计的 HMM 模型为,那么上面三个式子的左端就是重估的 HMM 模型参数。Baum
及他的同事在70年代证明了,因此如果我们迭代地计算上面三个式子,由此不断地重新估计 HMM 的参数,那么在多次迭代后可以得到 HMM 模型的一个最大似然估计。不过需要注意的是,前向后向算法所得的这个最大似然估计是一个局部最优解。

  参考资料:

  1. http://blog.csdn.net/eaglex/article/details/6376826

  2. http://en.wikipedia.org/wiki/Markov_chain

  3. http://en.wikipedia.org/wiki/Hidden_Markov_model

  4. Lawrence R. Rabiner, A Tutorial on Hidden Markov Models and Selected Applications in Speech Recognition. Proceedings of the IEEE, 77 (2), p. 257–286, February 1989.

  5. L. R. Rabiner and B. H. Juang, “An introduction to HMMs,” IEEE ASSP Mag., vol. 3, no. 1, pp. 4-16, 1986.

  6. http://jedlik.phy.bme.hu/~gerjanos/HMM/node2.html

  7. http://www.cs.brown.edu/research/ai/dynamics/tutorial/Documents/HiddenMarkovModels.html

  8. 隐马尔可夫模型简介,刘群

算法系列:HMM的更多相关文章

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

    隐马尔科夫模型HMM(一)HMM模型 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数(TODO) 隐马尔科夫模型HMM(四)维特比算法 ...

  2. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  3. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

  4. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  5. 三白话经典算法系列 Shell排序实现

    山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...

  6. Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx  Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api

    Atitit s2018.6 s6  doc list on com pc.docx Atitit s2018.6 s6  doc list on com pc.docx  Aitit algo fi ...

  7. 【C#实现漫画算法系列】-判断 2 的乘方

    微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...

  8. 玩转算法系列--图论精讲 面试升职必备(Java版)

    第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...

  9. 数据结构与算法系列——排序(4)_Shell希尔排序

    1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...

  10. 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归

    知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...

随机推荐

  1. 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)

    前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...

  2. Cannot load supported formats: Cannot run program "svn": CreateProcess error=2

    svn CreateProcess error=2, 系统找不到指定的文件 IntelliJ IDEA 13.1.2安装后,SVN checkout时候会出现如下错误: Cannot load sup ...

  3. 一个简单的任务执行时间监视器 StopWatch

    有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观, 如果想对执行的时间做进一步 ...

  4. 《转载》化繁为简 如何向老婆解释MapReduce?

    本文转载自http://server.zol.com.cn/329/3295529.html 昨天,我在Xebia印度办公室发表了一个关于MapReduce的演说.演说进行得很顺利,听众们都能够理解M ...

  5. 【leetcode】Spiral Matrix II

    Spiral Matrix II Given an integer n, generate a square matrix filled with elements from 1 to n2 in s ...

  6. unity3d项目文件目录发布后,对应的ios/android应用目录[转]

    Unity3d的Resource.AssetBundle与手游动态更新的报告,在这里分享一下,希望能够对各位用Unity的朋友有些许帮助.目录:1.Unity的资源数据加载2.Resource.Str ...

  7. 欧洲杯 2016 高清直播 - 观看工具 UEFA-EURO-2016-Play.7z

    OnlineTV-MPlayer-nocache.exe 占 CPU 内存 较少 OnlineTV-FFPlay.exe 可截取图像 UEFA-EURO-2016-Play-v5.7z UEFA-EU ...

  8. springMVC配置文件位置及名称

    在web.xml文件内配置springMVC的DispatcherServlet的那个servlet内添加 <servlet> <servlet-name>mvc</se ...

  9. HDU 4945 2048(dp)

    题意:给n(n<=100,000)个数,0<=a[i]<=2048 .一个好的集合要满足,集合内的数可以根据2048的合并规则合并成2048 .输出好的集合的个数%998244353 ...

  10. Bundle savedInstanceState的作用

    写过Android程序的都知道Activity中有一个名称叫onCreate的方法.该方法是在Activity创建时被系统调用,是一个Activity生命周期的开始.可是有一点容易被忽视,就是onCr ...