隐马尔可夫模型(Hidden Markov Model,HMM)是统计模型,它用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数。
隐马尔可夫模型注意包含以下参数:可见状态链,即观测序列,用
表示。
隐含状态链,隐含状态之间存在转换概率(transition probability),一般用状态转移矩阵A表示。
隐含状态和可见状态之间有一个概率叫做输出概率(emission probability),一般用输出观测矩阵B表示。
初始状态,描述初始各隐含状态的概率,用
表示
隐马尔可夫模型各参数基本含义和关系
用一个例子来表述隐马尔可夫模型各参数的关系:假设三个盒子
按照如下方式进行取球:(1)开始,从三个盒子取球概率分别为0.2,0.4,0.4
(2)从第二次取球开始,设定,若上次从盒子1取球,则下次从三个盒子取球概率为0.5,0.2,0.3;若从盒子2取球,下次从三个盒子取球概率为0.3,0.5,0.2;若从盒子3,下次概率依次为0.2,0.3, 0.5,
重复三次后,得到球观测序列为{红,白,红}。
根据HMM定义,得到,观察集合:{红,白}
状态集合:{盒子1,盒子2,盒子3}
初始状态 [0.2,0.4,0.4]
状态转移概率矩阵
观测概率矩阵
需要注意观测序列和观测集合是两码事。
HMM求解概率—前向算法
首先说明HMM求观测序列概率的前向后向算法。以前向算法为例。
(1) 计算时刻1的观测为
,隐含序号为i的各个隐藏状态前向概率:

例如,第一个球为红球,隐藏状态为一号盒子的概率:

隐藏状态为二号盒子的概率:

隐藏状态为三号盒子的概率:

2) 递推时刻2,3,…T时刻观测为,隐含序号为i的各个隐藏状态前向概率的前向概率:
例如时刻2是白色球,隐藏状态是盒子1的概率为:

(3)计算t时刻观测序列的概率

HMM解码—维特比算法,
维特比算法针对的形式,如下图,作用是求第一列到第三列的最短路径。

在HMM模型的解码问题中,一般给定模型状态转移矩阵A,输出观测概率矩阵B,初始状态概率。以及观测序列,求给定观测序列条件下,最可能出现的对应的隐藏状态序列I,即P(I|O)要最大化。例如本例,求三次摸球分别是哪些盒子。相当于已知结果(观测序列,逆推隐藏序列)
维特比算法为动态规划算法,基本思路是先正向计算最大概率,再根据最后一个结点回溯得到前面的结点。定义两个状态转移公式:
(1)时刻t隐藏状态为i所有可能的状态转移路径中的概率最大值。记为


(2)定义在时刻t隐藏状态为i概率最大的转移路径中第t−1个节点(前一个结点)的隐藏状态为
,用于回溯计算结点:

输入:HMM模型
观测序列O
输出:最有可能的隐藏状态序列I
1)初始化局部状态:


例如本例,时刻1,第一个观测值为红球
=0.2×0.5=0.1
=0.4×0.4=0.16
=0.4×0.7=0.28
2) 进行动态规划递推时刻t=2,3,…T时刻的局部状态:
递推三个隐藏状态在时刻2时的动态规划局部状态
递推三个隐藏状态在时刻3时的动态规划局部状态
(3)根据最大概率局部状态进行回溯,其中

T=3时其中
最大,回溯自
。
到T=2时得到
,回溯到

从而得到最终的最可能的隐藏状态序列为:(3,3,3)
代码:
class HMM(object):
def __init__(self):
self.A=array([(0.5,0.2,0.3),(0.3,0.5,0.2),(0.2,0.3,0.5)])
self.B=array([(0.5,0.5),(0.4,0.6),(0.7,0.3)])
self.pi=array([(0.2),(0.4),(0.4)])
self.o=[0,1,0]
self.t=len(self.o)#观测序列长度
self.m=len(self.A)#状态集合大小
self.n=len(self.B[0])#观测集合大小
def forward(self):
#t时刻部分观测序列为o1,o2,ot,状态为qi的概率用矩阵x表示,
#则矩阵大小行数为观测序列数,列数为状态个数
self.x=array(zeros((self.t,self.m))) #先计算出时刻1时,观测为o[0]的概率
for i in range(self.m): # 对隐藏集合遍历
self.x[0][i]=self.pi[i]*self.B[i][self.o[0]] # 初始某状态的概率*观测状态概率(输出状态为o1)
for j in range(1,self.t):
for i in range(self.m):
#前一时刻所有状态的概率乘以转移概率得到i状态概率
#i状态的概率*i状态到j观测的概率
temp=0
for k in range(self.m):
temp=temp+self.x[j-1][k]*self.A[k][i]
self.x[j][i]=temp*self.B[i][self.o[j]]
result=0
for i in range(self.m):
result=result+self.x[self.t-1][i]
print (u”前向概率矩阵及当前观测序列概率如下:”)
print (self.x)
print (result)
def viterbi(self):
# 维特比方法的对象是两个矩阵
#利用模型和观测序列找出最优的状态序列
#每个路径都有自己的概率,最大的概率用矩阵z记录,前一个状态用d矩阵记录
# self.t=len(self.o)#观测序列长度
# self.m=len(self.A)#状态集合大小
self.z=array(zeros((self.t,self.m))) # 3*3的矩阵
self.d=array(zeros((self.t,self.m)))
for i in range(self.m): # 初始状态
self.z[0][i]=self.pi[i]*self.B[i][self.o[0]]
self.d[0][i]=0
for j in range(1,self.t):
for i in range(self.m):
maxnum=self.z[j-1][0]*self.A[0][i]
node=1
for k in range(1,self.m): # 求最大转移概率
temp=self.z[j-1][k]*self.A[k][i]
if(maxnum
maxnum=temp
node=k
self.z[j][i]=maxnum*self.B[i][self.o[j]] # 转移序列状态
self.d[j][i]=node # 上个状态的结点
#找到T时刻概率的结点
print (“概率顺序”,self.d)
print (“路径概率”,self.z)
max_probability=self.z[self.t-1][0]
node_path = []
temp=0
for i in range(1,self.m):
if(max_probability < self.z[self.t-1][i]):
max_probability=self.z[self.t-1][i]
temp=i
i=self.t-1
temp = int(temp)
node_path.append(temp+1)
#self.d[t][p],t时刻状态为p的时候,t-1时刻的状态
#回溯,找到路径
while(i>=1):
#last_node.append(self.d[i][temp])
node_path.append(int (self.d[i][temp]+1))
temp = int (self.d[i][temp])
i=i-1
node_path.reverse()
print (u’路径节点分别为’)
print (“node_path”, node_path)
print (u’该路径概率为’+str(max_probability))
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/217590.html原文链接:https://javaforall.net
