通俗理解隐马尔可夫模型(HMM)及其案例代码实现

参考:

一站式解决:隐马尔可夫模型(HMM)全过程推导及python代码实现》知乎

Speech Recognition using Hidden Markov Model - DiVA》(硕士论文,推导细节可以参阅此文献

A Revealing Introduction to Hidden Markov Models》2021.4.12【重要文献,案例说明】

A Hidden Markov Models》—隐马尔可夫模型-斯坦福大学

Hidden Markov Models ——A lecture given by Tapas_Kanungo

Hidden Markov Model

A tutorial on hidden Markov models and selected applications in speech recognition

Mar隐马尔可夫模型(第3部分) 深入了解Hidden Markov Model 的训练理论》Medium文

统计学习方法——(第十章)隐马尔科夫模型详解》(公式推导细节参考)

HMM隐马尔可夫模型的例子、原理、计算和应用

Speech Recognition — GMM, HMM

 

 

https://www.cnblogs.com/sddai/p/8475424.html

https://blog.csdn.net/yywan1314520/article/details/50454063

https://www.cnblogs.com/pinking/p/8531405.html

零、HMM发展大事记

1913

Russian mathematician A. A. Markov recognizes that in a sequence of random variables, one variable may not be independent of the previous variable. For example, two successive coin tosses are independent but today's weather might depend on yesterday's weather. He models this as a chain of linked events with probability assigned to each link. This technique later is named Markov Chain.

1966

Baum and Petrie at the Institute of Defense Analyses, Princeton, introduce the Hidden Markov Model (HMM), though this name is not used. They state the problem of estimating transition and emission probabilities from observations. They use maximum likelihood estimate.

1967

Andrew Viterbi publishes an algorithm to decode information at the receiver in a communication system. Later named Viterbi algorithm, it's directly applicable to the decoding problem in HMM. Vintsyuk first applies this algorithm to speech and language processing in 1968.

1970

The Baum-Welch algorithm is proposed to solve the learning problem in HMM. This algorithm is a special case of the Expectation-Maximization (EM) algorithm. However, the name HMM is not used in the paper and mathematicians refer to HMM as "probabilistic functions of Markov chains".

1975

James Baker at CMU applies HMM to speech recognition in the DRAGON speech understanding system. This is one of the earliest engineering applications of HMM. HMM is further applied to speech recognition through the 1970s and 1980s by Jelinek, Bahl and Mercer at IBM.

1989

Lawrence Rabiner publishes a tutorial on HMM covering theory, practice and applications. He notes that HMM originated in mathematics and was not widely read by engineers. Even when it was applied to speech processing in the 1970s, there were no tutorials to help translate theory into practice.

2003

HMM is typically used when the number of states is small but one research team applies it to large scale web traffic analysis. This involves hundreds of states and tens of millions of observations.

 

一、必要的数学知识

1.联合概率与边缘概率

联合概率是指多维随机变量中同时满足多个变量时候的概率,也就是共同发生的概率。A,B的联合概率通常写成 P(A∩B)或 P(AB)或  P(AB)。对于离散的变量,联合概率可以用表格形式表示或者求和表示,连续的变量可以使用积分表示(若是二维就一个二重积分)

边缘概率是指多维随机变量中只满足部分变量时的概率。图片帮助理解:

 联合概率与边缘概率的关系:

技术图片

 边缘概率分布公式

技术图片

 联合概率的条件概率链式法则

技术图片

举例:P(a,b,c)=P(a|b,c)*P(b,c)=P(a|b,c)*P(b|c)*P(c)

条件概率

技术图片

独立性(XY相互独立)

P(X,Y)=P(X) *P(Y)

条件独立性

P(X,Y|Z)=P(X|Z)*P(Y|Z)

2.EM算法

 

         技术图片

 

关于EM算法利用jensen不等式近似实现极大似然估计的推导过程:https://zhuanlan.zhihu.com/p/36331115

 

二、隐马尔可夫模型(HMM)

1. 基本模型样式

 

 

 上图中,白圈代表状态变量,蓝圈代表观测变量。所以白圈那一行是状态序列(隐状态),而白圈这一行是观测序列。

 

2. 模型的数学表达

HMM由隐含状态S可观测状态O初始状态概率矩阵π隐含状态概率转移矩阵A可观测值转移矩阵B(混淆矩阵)组成,可以使用一个三元组进行表述:技术图片

 

3. Markov两个假设

(1)齐次假设:表示 t 时刻的状态只与 t-1 时刻的状态有关

技术图片

(2) 观测独立性假设:表示 t 时刻的观测变量只与 t 时刻的状态有关

技术图片

4. 解决三个问题

(1)概率计算问题(Scoring / Evalution ):前向后向算法,已知模型 λ = (A, B, π)和观测序列O={o1, o2, o3 ...},计算模型λ下观测O出现的概率P(O | λ)【解决算法包括穷举搜索向前算法(Forward Algorithm)、向后算法(Backward Algorithm)】

(2)学习问题learning):EM算法,已知观测序列O={o1, o2, o3 ...},计算估计模型λ = (A, B, π)的参数即推断状态的转移情况,使得在该参数下该模型的观测序列P(O | λ)最大;【使用鲍姆-韦尔奇算法(Baum-Welch Algorithm) (约等于EM算法)】

(3)预测问题Decoding):Viterbi算法,已知模型λ = (A, B, π)和观测序列O={o1, o2, o3 ...},求给定观测序列条件概率P(I | O,λ)最大的状态序列 I【使用维特比算法(Viterbi Algorithm)】

 

4.1 HMM模型的实质

HMM实际上就是建立建模 P(O,Q),【这里Q表示隐藏状态】对于给定的λ 进行建模:

   技术图片

 技术图片

   技术图片

技术图片

 

4.2 关于转移矩阵A、B及π的定义

(1)状态转移矩阵A

根据Markov齐次假设去定义状态转移矩阵是一个NxN的矩阵,表示一个状态有N种可能性,前一个状态也有N种可能性。aij表示状态从前一个的 i 状态转变为现在的 j 状态的概率。

技术图片

 

 上述式中 q 表示状态,所以 qt 表示 t 时刻的转态。

(2)观测概率矩阵B(混淆矩阵)

根据Markov 观测独立性假设定义观测概率矩阵B是一个NxM的矩阵,表示对于N种状态,在这N种状态下对应的M个可观测变量的概率(比如说在晴天状态下,观测到的湿度、温度、风速等观测量的概率)。bj(k)表示 j 状态下的第 k 个观测量的 概率。 

技术图片技术图片

 

 上式中P(ot=vk|it=qj)表示t 时刻状态为 qj 的情况下,t 时刻观察量为 vk的概率。

 5.3 隐藏状态概率分布 π(t=1时刻的状态)

技术图片

 举例总结

针对上述将的几个转移矩阵概念和初始状态π,举出一个盒子中摸球的例子帮助理解。

技术图片

摸球规则:

  开始的时候,从第一个盒子抽球的概率是0.2,从第二个盒子抽球的概率是0.4,从第三个盒子抽球的概率是0.4。以这个概率抽一次球后,将球放回。然后从当前盒子转移到下一个盒子进行抽球。规则是:如果当前抽球的盒子是第一个盒子,则以0.5的概率仍然留在第一个盒子继续抽球,以0.2的概率去第二个盒子抽球,以0.3的概率去第三个盒子抽球。如果当前抽球的盒子是第二个盒子,则以0.5的概率仍然留在第二个盒子继续抽球,以0.3的概率去第一个盒子抽球,以0.2的概率去第三个盒子抽球。如果当前抽球的盒子是第三个盒子,则以0.5的概率仍然留在第三个盒子继续抽球,以0.2的概率去第一个盒子抽球,以0.3的概率去第二个盒子抽球。

   从紫色背景的摸球规则中,可以推断出初始矩阵:技术图片

从绿色背景的摸球规则中,可以推断出状态转移矩阵为技术图片(矩阵的行列表示盒子123,数据表示转移概率)

从数据表格中可以推断出观测概率矩阵为:技术图片(矩阵的2列标识对应的观测结果,3行表示该观测结果下来自于不同盒子的概率)

 【注】集合与序列的问题,集合不重复,所以这个案例中,观测集合为 {红,白},状态集合为{盒子1,盒子2,盒子3}。所以M=2,N=3.但是观测序列可以是[红,白,红]等非2个元素的组成

4.3 概率计算问题及前后向算法

(1)概率计算问题定义:在给定模型 λ和观测序列O的情况下计算 P(O|λ)。【这里 I 表示隐藏状态】

(2)方法一:穷举法

思路:

  1. 列举所有可能的长度为T的状态序列I = {i1, i2, ..., iT};每个i都有N个可能的取值。
  2. 求各个状态序列I与观测序列O的联合概率P(O,I|λ);
  3. 所有可能的状态序列求和∑_I P(O,I|λ)得到P(O|λ)。

用到的公式:边缘概率公式 技术图片和条件概率的链式法则

     P(O|λ)=ΣI P(O,I|λ)    ←边缘概率公式

  P(O,I|λ)= P(O|I, λ)P(I|λ)   ←链式法则

第一步:

  P(I|λ)= P(i1,i2, ..., iT |λ)  

    = P(i1 |λ)P(i2 | i1, λ)P(i3 | i2, λ)...P(iT | iT-1, λ)  ←链式法则

  上面的P(i1 |λ) 是初始为状态i1的概率,P(i2 | i1, λ) 是从状态 i1转移到 i2的概率,其他同理,于是分别使用初始概率分布π 和状态转移矩阵A,就得到结果:

  ∴技术图片

第二步:

  P(O|I, λ) 在序列 I的条件下观测,所以技术图片

   于是带入求和可得:

    技术图片

复杂度为:aij 的复杂度为NT,b的复杂度为 T,所以总的复杂度 O(TnT)。

对于此种算法,需要列举所以状态,这几乎是不可能的,而且有些问题中我们是无法知道所以状态的。即使可以,但是,计算量很大,是O(TNT)阶的,这种算法不可行。因此,有前向后向算法。

英文描述为:

(3)方法2:前向 / 后向算法(forward / backward algorithm)

解决概率计算(Scoring / Evalution )问题的另外两种快捷方法为:

  • a. 前向算法

P(\mathcal{O} \mid \lambda)=\sum_{i=0}^{N-1} \alpha_{T-1}(i)

  • b. 后向算法

P(\mathbf{O} \mid \lambda)=\sum_{i=0}^{N-1} \pi_{i} \beta_{0}(i)=\sum_{i=0}^{N-1} \pi_{i} b_{i}\left(o_{1}\right) \beta_{1}(i)

I、 定义

前后向算法的区别之处:

 在概念的定义上:

前向算法:当第t个时刻的状态为i时,前面的时刻分别观测到y1,y2, ..., yt的概率,即:技术图片

后向算法:当第t个时刻的状态为i时,后面的时刻分别观测到yt+1,yt+2, ..., yT的概率,即:技术图片

II、推导过程

前向算法推导过程:在给定模型 λ和观测序列O的情况下计算 P(O|λ)

   在上面的粗暴概率计算中,复杂度大,所以我们可以使用递推公式来降低复杂度,于是在这里就是构造一个递推。

英文描述为:

 

 附录:第2步的推导过程细节为:

\begin{aligned} \alpha_{t+1}(i) &=\sum_{j=1}^{N} P\left(o_{1}, \ldots, o_{t+1}, x_{t}=q_{j}, x_{t+1}=q_{i} \mid \lambda\right) \\ &=\sum_{j=1}^{N} P\left(o_{1}, \ldots, o_{t}, x_{t}=q_{j} \mid \lambda\right) P\left(x_{t+1}=q_{i} \mid o_{1}, \ldots, o_{t}, x_{t}=q_{j}, \lambda\right) P\left(o_{t+1} \mid o_{1}, \ldots, o_{t}, x_{t}=q_{j}, x_{t+1}=q_{i}, \lambda\right) \\ &=\sum_{j=1}^{N} P\left(o_{1}, \ldots, o_{t}, x_{t}=q_{j} \mid \lambda\right) P\left(x_{t+1}=q_{i} \mid x_{t}=q_{j}, \lambda\right) P\left(o_{t+1} \mid x_{t+1}=q_{i}, \lambda\right)\\ &=\sum_{j=1}^{N} \alpha_{t}(j) a_{j i} b_{i}\left(o_{t+1}\right) \end{aligned}

后向算法类似于前向算法。

后向算法的英文描述为:

              3. P(\mathbf{O} \mid \lambda)=\sum_{i=0}^{N-1} \pi_{i} \beta_{0}(i)=\sum_{i=0}^{N-1} \pi_{i} b_{i}\left(o_{1}\right) \beta_{1}(i)

附录: 第2步的推导过程细节为:

\beta_{t}(i)=P\left(o_{t+1}, \ldots, o_{T} \mid x_{t}=q_{i}, \lambda\right)=\sum_{j=1}^{N} P\left(o_{t+1}, \ldots, o_{T},x_{t+1}=q_{j} \mid x_{t}=q_{i}, \lambda\right)

                                                          \begin{array}{l} =\sum_{j=1}^{N} P\left(o_{t+1} \mid o_{t+2}, \ldots, o_{T}, x_{t+1}=q_{j}, q_{t}={i}, \lambda\right) P\left(x_{t+1}=q_{j} \mid x_{t}=q_{i}, \lambda\right) P\left(o_{t+2}, \ldots, o_{T} \mid x_{t+1}=q_{j}, x_{t}=q_{i}, \lambda\right) \\ =\sum_{j=1}^{N} P\left(o_{t+1} \mid x_{t+1}=q_{j}, \lambda\right) P\left(x_{t+1}=q_{j} \mid x_{t}=q_{i}, \lambda\right) P\left(o_{t+2}, \ldots, o_{T} \mid x_{t+1}=q_{j}, \lambda\right) \\ =\sum_{j=1}^{N} b_{j}\left(o_{t+1}\right) a_{i j} \beta_{t+1}(j) \end{array}

 

III、总结

 

4.4 学习问题及Baum Welch-EM算法

 (1)学习问题定义

已知观测序列O={o1, o2, o3 ...},计算估计模型λ = (A, B, π)的参数即推断状态的转移情况,使得在该参数下该模型的观测序列P(O | λ)最大。

即:

       

 (2)算法思路

 

(3)Baum-Welch算法 (又称为forward-backward 算法)

    首先回顾前向变量和后向变量两个概念:

   

前向变量给定模型下,观察序列为O_{1},O_{2},...,O_{t}\large t 时刻隐藏状态为q_{i}的联合概率:  \alpha_{t}(i)=P\left(o_{1}, o_{2}, \ldots, o_{t}, q_{t}=i \mid \lambda\right)
后向变量给定模型下,\large t时刻隐藏状态为q_{i}并且后续观察序列为O_{t+1},O_{t+2},...O_{T-1}的概率: \beta_{t}(i)=P\left(O_{t+1}, O_{t+2}, \ldots ,O_{T-1}\mid q_{t}={i}, \lambda\right)

   再定义以下概念:

        概念1:在给定观察序列下,t 时刻从隐藏状态 i 转移到 j 的概率:

ξt(i, j)计算示意图

 根据 \alpha_{t}(i)=P\left(\mathbf{o}_{1}, \mathbf{o}_{2},\ldots \mathbf{o}_{t}, q_{t}=i \mid \lambda\right)\beta_{t}(i)=P\left(\mathbf{o}_{t+1}, \mathbf{o}_{t+2}, \ldots ,\mathbf{o}_{T} \mid q_{t}=i, \lambda\right)可以计算得到联合概率分布

\begin{aligned} P\left(O, i_{t}=q_{i} \mid \lambda\right) &=P\left(o_{1}, o_{2}, \ldots, o_{T}, i_{t}=q_{i} \mid \lambda\right) \\ &=P\left(o_{1}, o_{2}, \ldots, o_{t}, i_{t}=q_{i} \mid \lambda\right) P\left(o_{t+1}, \ldots, o_{T} \mid o_{1}, o_{2}, \ldots, o_{t}, i_{t}=q_{i}, \lambda\right) \\ &=P\left(o_{1}, o_{2}, \ldots, o_{t}, i_{t}=q_{i} \mid \lambda\right) P\left(o_{t+1}, \ldots, o_{T} \mid i_{t}=q_{i}, \lambda\right) \\ &=\alpha_{t}(i) \beta_{t}(i) \end{aligned}

进而可得到以下公式:

 

附录: 

红色部分,即P(O \mid \lambda)=\sum_{i=1}^{N} \sum_{j=1}^{N} \alpha_{t}(i) a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j)的证明如下:

因为:

\begin{aligned} P(O \mid \lambda) &=\sum_{i=1}^{N} \sum_{j=1}^{N} \alpha_{t}(i) a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j) \\ &=\sum_{i=1}^{N} \alpha_{t}(i) \sum_{j=1}^{N} a_{i j} b_{j}\left(o_{t+1}\right) \beta_{t+1}(j) \\ &=\sum_{i=1}^{N} \alpha_{t}(i) \beta_{t}(i) \end{aligned}

又因为:

\begin{aligned} \alpha_{t}(i) \beta_{t}(i) &=P\left(o_{1}, o_{2}, \ldots, o_{t}, q_{t}={i} \mid \lambda\right) P\left(o_{t+1}, \ldots, o_{T} \mid q_{t}={i}, \lambda\right) \\ &=P\left(o_{1}, o_{2}, \ldots, o_{t}, q_{t}={i} \mid \lambda\right) P\left(o_{t+1}, \ldots, o_{T} \mid o_{1}, o_{2}, \ldots, o_{t}, q_{t}={i}, \lambda\right) \\ &=P\left(o_{1}, o_{2}, \ldots, o_{T}, q_{t}={i} \mid \lambda\right) \\ &=P\left(O, q_{t}={i} \mid \lambda\right) \end{aligned}

所以结合下式,得证.

P(O \mid \lambda)=\sum_{i=1}^{N} P\left(O, q_{t}={i} \mid \lambda\right)=\sum_{i=1}^{N} \alpha_{t}(i) \beta_{t}(i)

       概念2:在给定观察序列下,t 时刻隐藏状态为 i 的概率:

         \gamma_{t}(i)=P\left(q_{t}={i} \mid O, \lambda\right) =\sum_{j=1}^{N} P\left(q_{t}={i}, q_{t+1}={j} \mid O, \theta\right)=\sum_{j=1}^{N} \xi_{t}(i, j)

 

继续,

隐藏状态为 i 的数学期望,其实就是算平均值:

\mathbb{E}[i]=\frac{\sum_{t=1}^{T-1} \gamma_{t}(i)}{T-1}

隐藏状态从 i 转移到 j 的数学期望(是 t 时刻为 i , t+1 时刻为 j 的联合概率):

\mathbb{E}[i,j]=\frac{\sum_{t=1}^{T} \xi_{t}(i, j)}{T-1}

 

所以自然可以计算模型参数:

估算初始概率:\gamma_{1}

估算转移概率:\LARGE \begin{array}{l} \bar{a}_{i j}=\frac{\text { expected number of transitions from state } i \text { to state } j}{\text { expected number of transitions from state } i}=\frac{\sum_{t=1}^{T-1} \xi_{t}(i, j)}{\sum_{t=1}^{T-1} \gamma_{t}(i)} \end{array}

估算发射概率:\LARGE \bar{b}_{j}(k)=\frac{\text { expected number of times in state } j \text { and observing k th symbol }}{\text { expected number times in state } j}\LARGE =\frac{\sum_{t=1 \atop o_{t}={k}}^{T} \gamma_{t}(j) }{\sum_{t=1}^{T} \gamma_{t}(j) }\LARGE =\frac{\sum_{t=1 \atop o_{t}={k}}^{T} \alpha_{t}(j) \beta_{t}(j) }{\sum_{t=1}^{T} \alpha_{t}(j) \beta_{t}(j)}

然后使用上边计算的估算值,替换初始的参数。反复进行迭代,直到得到局部最优解,即:

算法原理:

隐马尔可夫模型lamda = (pi, A, B)

  • 定义评估方法,最大化可见状态链的前向概率alpha和后向概率beta
  • 初始化模型参数:随机定义一套初始概率pi,转换概率矩阵A、输出概率矩阵B
  • 不断的重复迭代
  1. E步:用当前的pi,A,B计算初alpha,beta(即前向算法-后向算法)
  2. M步: 用alpha和beta更新pi,A,B(贝叶斯理论公式基础)
  • 重复上述步骤,当pi,A,B的更新区域静止时认为已经找到了模型的最佳参数,停止迭代

而我们知道,观测O由对应的状态决定,所以这里还隐含了状态这个未知变量,所以这个求解问题实际是一个隐变量求解问题,于是需要使用EM算法解决

 

4.5 预测问题及Viterbi(维特比)算法

(1) 预测问题定义: 

(2)思路分析

 (3)常规Viterbi 算法

  

 (4)改进的Viterbi 算法

 

三、案例及代码实现

本节主要参考:

A Revealing Introduction to Hidden Markov Models》2021.4.12【重要文献,案例说明】

Hidden Markov Model

一个HMM模型所包含的要素如下:

  • 隐藏状态
  • 观测状态
  • π向量:模型初始隐藏状态的概率
  • 转移矩阵(A矩阵):隐藏状态间转移的概率矩阵
  • 混淆矩阵(也称发射概率矩阵, B矩阵):隐藏状态与观察状态的对应概率矩阵

相关英语术语见下:

3.1 案例1及Code

案例1:小明现在有三天的假期,他为了打发时间,可以在每一天中选择三件事情来做,这三件事情分别是散步(Walk)购物(Shop)打扫卫生(Clean)(对应着可观测序列),可是在生活中我们所做的决定一般都受到天气的影响,可能晴天的时候想要去购物或者散步,可能下雨天的时候不想出门,留在家里打扫卫生。而天气(晴天(Sunny)下雨天(Rainy)就属于隐藏状态,用一幅概率图来表示这一马尔可夫过程:

 

根据案例可以得到:

T = don’t have any observation yet;

N = 2;

M = 3;

Q = {“Rainy”, “Sunny”};

V = {“Walk”, “Shop”, “Clean”}

状态转移矩阵A为:

混淆矩阵B为:

初始隐藏状态的概率π为

根据图中概率分布可以建立以下HMM模型:

states = ('Rainy', 'Sunny')
 
observations = ('walk', 'shop', 'clean')
 
start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
 
transition_probability = {
   'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3},
   'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6},
   }
 
emission_probability = {
   'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
   'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
   }

from hmmlearn import hmm
import numpy as np

model = MultinomialHMM(n_components=2)
model.startprob_ = np.array([0.6, 0.4])
model.transmat_ = np.array([[0.7, 0.3],
                            [0.4, 0.6]])
model.emissionprob_ = np.array([[0.1, 0.4, 0.5],
                                [0.6, 0.3, 0.1]])

 

现在,使用HMM可以解决哪些关键问题?

  1. 问题1 ,给定已知模型λ,序列O发生的可能性P(O|λ)是多少?【概率计算问题】
  2. 问题2 ,给定已知模型λ和序列O,最佳隐藏状态序列I是什么,即P(I |O,λ)? 如果我们想知道天气是“下雨”还是“晴天”。【预测问题】
  3. 问题3 ,给定序列O和隐藏状态数,最大化O概率的最佳模型λ = (A, B, π)是什么,即计算估计模型λ = (A, B, π)的参数即推断状态的转移情况,使得在该参数下该模型的观测序列P(O | λ)最大?换句话说就是,我们要寻找的训练的目标是找到「 状态转移矩阵 A 」、「 观察转移矩阵 B 」、「 起始值转移矩阵 π 【学习问题】

三种问题的具体计算推导公式见:

(1)《Hidden Markov models》(Centre for Vision Speech & Signal ProcessingUniversity of Surrey, Guildford GU2 7XH.

(2)A tutorial on hidden Markov models and selected applications in speech recognition

(1)案例1的概率计算实例

import math

math.exp(model.score(np.array([[0]])))
# 0.30000000000000004
math.exp(model.score(np.array([[1]])))
# 0.36000000000000004
math.exp(model.score(np.array([[2]])))
# 0.3400000000000001
math.exp(model.score(np.array([[2,2,2]])))
# 0.04590400000000001

比如,第二行代码,需要求出:第一个观测值O是“Walk”(对应为0)的概率,根据计算公式:

该概率等于初始状态分布π发射概率矩阵B的乘积, 

代码中通过调用.score提供计算的。

(2)案例1的预测(Decoding)问题实例

logprob, seq = model.decode(np.array([[1,2,0]]).transpose())
print(math.exp(logprob))
print(seq)

logprob, seq = model.decode(np.array([[2,2,2]]).transpose())
print(math.exp(logprob))
print(seq)

输出结果为:

即:在已知模型λ和观测值={“Shop”,“Clean”,“Walk”}的情况下,最有可能的天气(隐藏状态)={“Rainy”,“Rainy”,“Sunny”},概率约为1.5%。

给定已知的模型λ和观测值={“ Clean”,“ Clean”,“ Clean”},最有可能的天气(隐藏状态)={“ Rainy”,“ Rainy”,“ Rainy”},概率约为3.6%。

直观地讲,当“Walk”发生时,天气很可能不会是“Rainy”。

具体使用的方法(维特比算法(Viterbi))及其步骤见《马尔科夫(Markov)

(3)案例1的学习问题实例

 

3.2 案例2及代码实现

案例2:观察海藻湿度的状态,能否确定是雨天还是晴天。这个例子可能偏颇,需明确一下,海藻的湿度为可见状态,而天气状态为隐藏状态(假设盲人能够感知海藻湿度,却无法观察天气)。我们现定义海藻湿度分为四个等级为”dry”,”dryish”,”damp”,”soggy”.显而易见,不同的天气状况我们能观测到海藻不同湿度的概率是不同的,以表格的形式如下:

(1)案例2的概率计算问题及预测(Decoding)问题实例及代码

结合以上案例解决其概率计算问题穷举搜索递归思想之前向算法后向算法,及解决其预测(Decoding)问题Viterbi(维特比)算法具体推导及python代码(不使用HMM库,直接实现公式)实现见:

隐马尔可夫学习笔记(一)

(2)案例2的学习问题实例及代码

隐马尔可夫模型的学习,根据训练数据是包括观测序列和对应的状态序列还是只有观测序列,可以分别由监督学习与非监督学习实现。以下文章首先介绍监督学习算法,而后介绍非监督学习算法——Baum-Welch算法(也就是EM算法),并用代码(不使用HMM库,直接实现公式)实现:

隐马尔可夫模型之Baum-Welch算法详解

 

3.3 案例3及手撕代码

来源:书籍《Machine Learning:An  Algorithmic Perspective》 CHAPTER16 Graphical Models 及其 code

参考:PPT《Hidden Markov Models and Eukaryotic Gene Finding

案例3:Suppose that you notice a fairground show where the showman demonstrates that a coin is fair, but then makes it turn up heads many times in a row. You notice that he actually has two coins, and swaps between them with sleight-of-hand. Watching, you start to see that he sticks to the fair coin(公平的硬币) with probability 0.4, and to the biased coin(偏币,有偏差的硬币)with probability 0.1, and that the biased coin seems to come up heads about 85% of the time. Make a hidden Markov model for this problem, construct an observation sequence, and use the Viterbi algorithm to estimate the states。

# Code from Chapter 16 of Machine Learning: An Algorithmic Perspective (2nd Edition)
# by Stephen Marsland (http://stephenmonika.net)

# You are free to use, change, or redistribute the code in any way you wish for
# non-commercial purposes, but please maintain the name of the original author.
# This code comes with no warranty of any kind.

# Stephen Marsland, 2008, 2014

# A basic Hidden Markov Model
import numpy as np

scaling = False

def HMMfwd(pi,a,b,obs):

	nStates = np.shape(b)[0]
	T = np.shape(obs)[0]

	alpha = np.zeros((nStates,T))

	alpha[:,0] = pi*b[:,obs[0]]

	for t in range(1,T):
		for s in range(nStates):
			alpha[s,t] = b[s,obs[t]] * np.sum(alpha[:,t-1] * a[:,s])

	c = np.ones((T))
	if scaling:
		for t in range(T):
			c[t] = np.sum(alpha[:,t])
			alpha[:,t] /= c[t]
	return alpha,c

def HMMbwd(a,b,obs,c):

	nStates = np.shape(b)[0]
	T = np.shape(obs)[0]

	beta = np.zeros((nStates,T))

	beta[:,T-1] = 1.0 #aLast

	for t in range(T-2,-1,-1):
		for s in range(nStates):
			beta[s,t] = np.sum(b[:,obs[t+1]] * beta[:,t+1] * a[s,:])

	for t in range(T):
		beta[:,t] /= c[t]
	#beta[:,0] = b[:,obs[0]] * np.sum(beta[:,1] * pi)
	return beta

def Viterbi(pi,a,b,obs):

	nStates = np.shape(b)[0]
	T = np.shape(obs)[0]

	path = np.zeros(T)
	delta = np.zeros((nStates,T))
	phi = np.zeros((nStates,T))

	delta[:,0] = pi * b[:,obs[0]]
	phi[:,0] = 0

	for t in range(1,T):
		for s in range(nStates):
			delta[s,t] = np.max(delta[:,t-1]*a[:,s])*b[s,obs[t]]
			phi[s,t] = np.argmax(delta[:,t-1]*a[:,s])

	path[T-1] = np.argmax(delta[:,T-1])
	for t in range(T-2,-1,-1):
		path[t] = phi[path[t+1],t+1]

	return path,delta, phi

def BaumWelch(obs,nStates):

	T = np.shape(obs)[0]
	xi = np.zeros((nStates,nStates,T))

	# Initialise pi, a, b randomly
	pi = 1./nStates*np.ones((nStates))
	a = np.random.rand(nStates,nStates)
	b = np.random.rand(nStates,np.max(obs)+1)

	tol = 1e-5
	error = tol+1
	maxits = 100
	nits = 0
	while ((error > tol) & (nits < maxits)):
		nits += 1
		oldpi = pi.copy()
		olda = a.copy()
		oldb = b.copy()

		# E step
		alpha,c = HMMfwd(pi,a,b,obs)
		beta = HMMbwd(a,b,obs,c) 

		for t in range(T-1):
			for i in range(nStates):
				for j in range(nStates):
					xi[i,j,t] = alpha[i,t]*a[i,j]*b[j,obs[t+1]]*beta[j,t+1]
			xi[:,:,t] /= np.sum(xi[:,:,t])

		# The last step has no b, beta in
		for i in range(nStates):
			for j in range(nStates):
				xi[i,j,T-1] = alpha[i,T-1]*a[i,j]
		xi[:,:,T-1] /= np.sum(xi[:,:,T-1])

		# M step
		for i in range(nStates):
			pi[i] = np.sum(xi[i,:,0])
			for j in range(nStates):
				a[i,j] = np.sum(xi[i,j,:T-1])/np.sum(xi[i,:,:T-1])
	
			for k in range(max(obs)):
				found = (obs==k).nonzero()
				b[i,k] = np.sum(xi[i,:,found])/np.sum(xi[i,:,:])

		error = (np.abs(a-olda)).max() + (np.abs(b-oldb)).max() 
		print nits, error, 1./np.sum(1./c), np.sum(alpha[:,T-1])

	return pi, a, b	
		
def evenings():
	pi = np.array([0.25, 0.25, 0.25, 0.25])
	a = np.array([[0.05,0.7, 0.05, 0.2],[0.1,0.4,0.3,0.2],[0.1,0.6,0.05,0.25],[0.25,0.3,0.4,0.05]])
	b = np.array([[0.3,0.4,0.2,0.1],[0.2,0.1,0.2,0.5],[0.4,0.2,0.1,0.3],[0.3,0.05,0.3,0.35]])
	
	obs = np.array([3,1,1,3,0,3,3,3,1,1,0,2,2])
	print Viterbi(pi,a,b,obs)[0]
	alpha,c = HMMfwd(pi,a,b,obs)
	print np.sum(alpha[:,-1])

def test():
	np.random.seed(4)
	pi = np.array([0.25,0.25,0.25,0.25])
	aLast = np.array([0.25,0.25,0.25,0.25])
	#a = np.array([[.7,.3],[.4,.6]] )
	a = np.array([[.4,.3,.1,.2],[.6,.05,.1,.25],[.7,.05,.05,.2],[.3,.4,.25,.05]])
	#b = np.array([[.2,.4,.4],[.5,.4,.1]] )
	b = np.array([[.2,.1,.2,.5],[.4,.2,.1,.3],[.3,.4,.2,.1],[.3,.05,.3,.35]])
	obs = np.array([0,0,3,1,1,2,1,3])
	#obs = np.array([2,0,2])
	HMMfwd(pi,a,b,obs)
	Viterbi(pi,a,b,obs)
	print BaumWelch(obs,4)
	
def biased_coins():
	a = np.array([[0.4,0.6],[0.9,0.1]])
	b = np.array([[0.49,0.51],[0.85,0.15]])
	pi = np.array([0.5,0.5])

	obs = np.array([0,1,1,0,1,1,0,0,1,1,0,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,0,0,1,0,1,0,0,1,1,1,0])	
	print Viterbi(pi,a,b,obs)[0]

	print BaumWelch(obs,2)

3.4 案例4

原文:《Mar隐马尔可夫模型(1、2、3部分)

现有三间大型卖场在AIA 附近,分别是Costco爱买大润发,已知顾客今日在各个卖场间流动的固定机率(invariant),亦即图上的数字,值得注意的是,从每间卖场画出去箭头上的数字相加起来为1 (ex: Costco 0.7+0.2+1 = 1)。 接着来看一下范例吧…今天刚来AIA报到的学员圆仔,每天都有一定的机率到某间卖场里购物,同时也会有某个机率在该间卖场买瓶饮料。在起始机率分别为0.5、0.1、0.4下,圆仔三天来逛卖场的顺序为 I (爱买, Costco,大润发) ,每到一间卖场他都会买一瓶饮料,三天来分别买了 O (雪碧,可乐,绿茶) 。该案例中,隐藏状态为 (爱买, Costco,大润发),可观测状态为: O (雪碧,可乐,绿茶) 

(1)引入1:请问发生 I O 的共同机率为多少呢?

 

 

答:请问发生 I O 的共同机率,即求P(O,I)。由于:

 

 

 

(2)引入2:现在换个问题来想想,如果已知连续三天到卖场买的饮料依序为 O (红茶,雪碧,绿茶),请问有几种可能路线呢? 每条路线分别发生的机率又有多少呢?

答案:已知模型 λ = (A, B, π)和观测序列O={o1, o2, o3, ...},求总共几种可能路线,即求观测序列O在各个状态序列 I 下的条件概率P(O|I,λ),可以用穷举法,即列举所有隐藏状态I =(I0,I1, I2)[3x3x3=29种组合] 发生观测状态的概率。

 

(3)HMM 三大问题

第二个例子说明了,当只知观察值,而状态被隐藏的时候,如何找出「最佳的路径」。 但是,既然是model 一定是需要训练的,到底什么东西是需要被训练的呢?
在实际遇到的问题中,我们并不会知道「机率转移矩阵」实际的机率是多少,换句话说,我们不知道上述所指的「转移矩阵A」和「混淆矩阵B」,只会有一堆数据。在此,我们用已知的转移矩阵条件下,举一个实际的分类问题,熊猫团团、圆圆、圆仔,半年来,每周买饮料( 观察值)的依序清单,至于可能的路线,及多少机率会买到对应的饮料,皆是未知,根据个别的买卖习惯分析,训练对应的模型,找出对应的「转移矩阵A」和「混淆矩阵B」,最后我们要预测,当随便给一周的饮料的清单,最有可能是哪只熊猫的喜好。

                                                                                      (上图为HMM,其中一种方法,目的是算出在指定事件的发生状态下,算出此事件发生的最大机率之路径 )

 

HMM 三大问题:

A.  概率计算问题——向前-向后算法 (Forward-backward Algorithm)

B . 解码(预测)问题——维特比算法

C. 学习问题——使用鲍姆-韦尔奇算法(Baum-Welch Algorithm) (约等于EM算法)

D. (补充) Continuous Hidden Markov Chain

在进入主题前,再重申一次问题,如下图:

我们需计算在已知观察序列 O(o₁, o₂, o₃, …, ot) ,但未知转移矩阵A 和B的条件下,找出其对应的的所有可能状态序列 Q(q₁, q₂, q₃, …, qt ) , 以及其中最大概率之状态序列Q(q₁, q₂, q₃, …, qt )

有些人大概觉得简单吧! 暴力法就可以解决了,穷举出所有可能的路径,并计算每条路径的机率,不就结束了吗? 就是每条路径都算过,痾....时间复杂度是O(N^TT)呀! 大大,在文明的21世纪,我们不能这么暴力呀!

以下的演算法要跟大家介绍,如何降低计算的时间复杂度。

(a)概率计算问题——前向-后向算法

forward 顾名思义,就是由前往后找路径,直到第 t 秒,其实也不太难,看到上图蓝色经过的流程图在这边forward要计算的部分只有 αt(j) ,意思就是在第 t 秒、第 j 个状态,发生 ot 的所有可能路径机率之加总值,所以只算第 t 秒和第 t 秒以前发生的可能路径机率!

backward 用膝盖想,就是由后往前算嘛,看看流程图之绿色部分, βt(j) 从第 t 秒开始,考虑由第 j 个状态出发,直至第 T 秒结束的所有路径机率之总和,由于不知道在 t j 状态出发的机率值,所以我们是从已知第 T 秒发生的机率值,往前回推至第 t 秒的路径机率。

用图示法来看,不严谨的说法是forward乘上backward ,就恰巧是在观察序列 O 时,发生第 t 秒,经过第 j 个状态的所有可能路径机率之总和。

疑? forward 往后算到底,不就是backward 往前算到底的值嘛? 恩,是的,所以要估算路径机率,其实只要算一种就可以了。

何以利吾身? 这样算有什么好处呢? 时间复杂度大大的减少了呀! 只剩下O(N²T) 唷! 时间就是金钱,颗颗….不过这个演算法既然有forwardbackward,算这两个一定有原因呀! 等等在底下会提到。

 

(b)预测(解码)问题— 维特比算法

看到这边,应该都是会心一笑,其实和上个演算法差不多嘛! 只是把变成max而已呀! 是的,你没有看错就是这么简单,有别于上个演算法是要找出在第 t 秒,会经过第 j 个状态的所有可能路径机率总和,而这个演算法想表示的是,在第 t 秒,会经过第 j 个状态之最大机率路径。

(c)学习问题——EM算法

学习问题,学习要学什么呢?以上面例子为例,过去一年来,我们以周为一个观察序列单位,纪录圆仔每天买饮料的习惯,因此我们想从圆仔的饮料习惯纪录中,分析出「选择买什么东西」、「去哪间卖场购买的」,可惜的是,我们没有纪录到圆仔去哪间卖场买东西的诱因,亦即是「机率」,再换句话说,我们要寻找的训练的目标是找到「 状态转移矩阵 A 」、「 观察转移矩阵 B 」、「 起始值转移矩阵 π 」,而「圆仔的饮料习惯纪录」是我们的训练资料集。

了解问题之后,先来看一下离散问题的数学式,首先只考虑一周的饮料清单,透过 Forward-Backward Algorithm 我们可以求出αₜ(i)和βₜ(i),也就是把每一个时间点会经过每一个状态及事件的所有可能路径机率都算出来,求出来之后,自然就要开始训练参数啦!

开始训练喽!

在标题中看到 EM Algorithm ,应该很快就联想到了「聚类」、「数据分布」,是的,我们这里处理的手法其实也差不多啦! 利用事件发生的平均机率,当作更新的转移矩阵,接着反复的寻找和更新,直到更新幅度很小这样。

评论:

  1. 没有出现在资料集中的观察值,在更新的过程中,会被更新为0,一旦变成0,此事件路径发生的可能性即为0,因此不论计算Evaluate Problem 或是Decording Problem 此路径机率皆恒为0,意思是不会再更新,所以通常不会让没出现过的观察值机率为0,常理来说,会预设一个比0 大,但很小的数字。 只有离散问题,会遇到此状况,连续则无。
  2. 因为每次的update,都只与当下计算的观察序列有关,因此很容易看到第n 个序列的时候,就忘掉一开始看到的几个序列的样子了,为了避免这样的状况产生,所以我们让每次要更新的值,与将要被更新的值取一个比例平衡,既不忘了过去的观察序列,也不会全然依照新的观察序列更新,常用的方式如底下公式:    

当然有些人会困惑,之前我们讨论的内容中,每个状态都会有固定对应的M个观察值,意思是,原先卖场饮料都是一罐一罐卖的,后来为了环保考量不用铝罐装,用一袋袋饮料装? 由于是一袋袋的,所以每一袋饮料的重量都有些许的误差,长久下来,观察值会由消费者买了架上第k种每瓶为 L ml的饮料,变成是买了架上第k种每袋为 L ml的饮料,因为不是每袋都能很准确的装刚好 L ml的饮料,所以会有一点点偏差— 「连续型隐藏式马可夫模型Continuous Hidden Markov Model」

 

(d) (补充) Continuous Hidden Markov Model

上述的想法,大家思考一下,看到「 bias 偏差」大家会想到啥? 八九不离十,是令人脑昏的「统计」,统计数据会想到啥? 「常态分布Normal Distribution」。 没错,不管什么状态,未看先猜有「常态分布」,先对一半。 那什么东西训练中会与「常态分布」有关,眼睛闭着,也猜得到「 EM Algorithm 」,接着联想到的就是「 Gaussian Distribution 」、「 Gaussian Mixture Model 」。 既然有这些联想,那一切就好办了。 让我们走下去….

于是乎我们训练的目标中多了一个参数—在「状态 st 」产生「观察值 ot 」的机率。 目前我们以 Gaussian Mixture Model 为假设观察值 ot 所属分布,那马上就会想到,多了的训练参数是谁了吧!!!没错,就是「平均数mean μ」「协方差covariance Σ」。

 

有了这张图,大概就清楚明了了吧! 简单叙述整个问题,就是….圆仔每天都会去买饮料,所以我们纪录她每天买的饮料品项和饮料重量,然后每7天为一笔资料,目的是找出圆仔买东西的习惯和路径,以及买到东西多寡的分析,所以影响的因素和对应的名词有三个「卖场状态」「饮料观察」「饮料重量 N( μ, Σ ) ,目标是从这三者中计算出最可能是圆仔的习惯— —买东西的路径机率、选择买哪种饮料的机率、得到此饮料重量的机率。

一定会有人觉得紧张该怎么办,其实也不用怎么办啦!!!跟刚刚计算的方法差不多,只是多了要更新平均值 μ 「协方差 Σ 而已。

 

YA! 我们终于结束Hidden Markov Model 系列啦!!!给自己一个欢呼吧! 其实一切都不难,不要看到数学是就害怕了啦啦啦~~~~

  • 10
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
HMM是一种常见的统计模型,用于描述随机生成的序列。Viterbi算法是一种在HMM中进行解码的动态规划算法,用于寻找最可能的隐藏状态序列。下面是HMM的MATLAB实现,包括Viterbi算法。 首先,我们需要定义一个HMM模型。我们假设这个模型有3个隐藏状态和2个可见状态。我们使用矩阵A表示隐藏状态之间的转移概率,矩阵B表示每个隐藏状态生成每个可见状态的概率,向量pi表示初始隐藏状态的概率分布。 ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; ``` 接下来,我们需要生成一个可见序列。我们使用HMM模型中的随机过程生成一个长度为10的可见序列。 ```matlab % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end ``` 接下来,我们使用Viterbi算法解码这个可见序列,得到最可能的隐藏状态序列。我们定义一个矩阵V表示每个时间步的最大概率,以及一个矩阵path表示每个时间步的最大概率对应的前一个状态。 ```matlab % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end ``` 最后,我们找到最可能的隐藏状态序列。我们首先找到最后一个时间步的最大概率对应的隐藏状态,然后从后往前依次寻找每个时间步的最大概率对应的隐藏状态,最终得到整个隐藏状态序列。 ```matlab % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ``` 完整代码如下: ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值