HMM模型 forward backward viterbi算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

评估问题

隐马尔可夫模型中包含一个评估问题:已知模型参数,计算某一特定输出序列的概率。通常使用forward算法解决。

比如计算活动序列{读书,做清洁,散步,做清洁,散步}出现的概率,就属于评估问题。
如果穷举的话,观察序列会有2(晴or雨)^5种,需要分别计算它们出现的概率,然后找出概率最大的。

穷举法中有很多重复计算,向前算法就是利用已有的结果,减少重复计算。

向前算法借助于一个矩阵Q[LEN][M],其中M是所有隐藏状态的种数,Q[i][j]表示从第0天到第i天,满足观察序列,且第i天隐藏状态为Sj时的所有可能的隐藏序列的概率之和。最终所求结果为Q[LEN-1][0]+…+Q[LEN-1][M-1],即最后一天,所有隐藏状态下,分别满足观察序列的概率值之和。
在这里插入图片描述

向前算法

在这里插入图片描述

向前变量图示

在这里插入图片描述

向后算法

在这里插入图片描述

向后算法变量图示

在这里插入图片描述

前向-后向算法

在这里插入图片描述

解码问题 Viterbi算法

解码问题是:已知模型参数,寻找最可能的能产生某一特定输出序列O(LEN)的隐含状态的序列。通常使用Viterbi算法解决。

观察序列长度为LEN,隐藏状态序列长度是M,如果采用穷举法,就有M^LEN种可能的隐藏状态序列,我们要计算每一种隐藏状态到指定观察序列的概率,最终选择概率最大的。

穷举法中有很多重复计算,Viterbi算法就是利用已有的结果,减少重复计算。跟评估问题非常相似,不同点在于评估算的是和,解码算的是最大值。

Viterbi算法主要就是在计算一个矩阵Q[LEN][M],其中Q[i][j]表示从第0天到第i天,满足观察序列,且第i天隐藏状态为Sj的所有可能的隐藏序列的概率的最大值。另外还要建立一个矩阵Path[LEN][M],用来记录状态序列中某一状态之前最可能的状态。

举个例子,假如指定观察序列是{读书,做卫生,散步,做卫生,散步},求出现此观察序列最可能的状态序列是什么。

Q[0][0]=p(第一天读书 , 第一天晴)=p(天晴)*p(读书|天晴) Path[0][0]=-1;
Q[0][1]=p(第一天读书 , 第一天下雨)=p(下雨)*p(读书|下雨) Path[0][1]=-1;

关键是从第二天开始,Q[1][0]表示:满足“第一天读书 且 第二做清洁 且 第二天晴”的所有可能的隐藏序列的概率的最大值。那么满足“第一天读书 且 第二做清洁 且 第二天晴”的所有可能的隐藏序列有哪些呢?

第二天是必须满足晴天的,第二天之前的状态可以任意变。则所有可能的隐藏序列就是“晴 晴”和“雨 晴”。实际上考虑第三天(及第三天以后)时,并不需要考虑“所有”可能的隐藏序列,而只需要考虑第二天的不同状态取值,这是因为马氏过程有无后效性–t时刻所处状态的概率只和t-1时刻的状态有关,而与t-1时刻之前的状态无关。

Q[1][0]=

max{ p(第一天晴, 第一天读书 , 第二天晴, 第二天做卫生) ,p(第一天下雨 且 第一天读书 且 第二天晴, 第二天做卫生) }

=max{ p(第一天读书, 第一天晴)*p(天晴转天晴),p(第一天读书, 第一天下雨)*p(下雨转天晴) } * p(做卫生|天晴)

=max{ Q[0][0]*A[0][0],Q[0][1]*A[1][0] } * B[0][2]

假如Q[0][0]*A[0][0] < Q[0][1]*A[1][0],则Path[1][0]=1;假如Q[0][0]*A[0][0] > Q[0][1]*A[1][0],则Path[1][0]=0。

Q[1][1]= ……
…… ……
可以看到计算Q矩阵的每i行时都用到了第i-1行的结果。

Viterbi算法词性标注

问题:已知已标记好词性的语料库,现给定一个句子S,求这个句子的词性Z。

根据朴素贝叶斯:P(词性|单词) = P(单词|词性)P(词性) 得到公式:
在这里插入图片描述
我们称给定句子为观测序列,需要求的词性为状态序列,A为观测概率矩阵,B为初始状态,C为状态转移概率矩阵,根据如上公式知道参数 = (A,B,pi),即可求得状态序列。


在这里插入图片描述

向前算法代码

#-*-coding:utf-8-*-
__author__ = 'ZhangHe'
def forward(N,M,A,B,P,observed):
    p = 0.0
    #观测变量数目
    LEN = len(observed)
    #中间概率LEN*M
    Q = [([0]*N) for i in range(LEN)]
    #第一个观测变量的概率,隐藏状态的初始概率乘上隐藏状态到观测变量的条件概率。
    for j in range(N):
        Q[0][j] = P[j]*B[j][observation.index(observed[0])]
    #第一个之后的观测变量,首先从前一天的每个隐藏状态,转移到当前隐藏状态的概率求和,然后乘上当前隐藏状态到观测变量的条件概率。
    for i in range(1,LEN):
        for j in range(N):
            sum = 0.0
            for k in range(N):
                sum += Q[i-1][k]*A[k][j]
            Q[i][j] = sum * B[j][observation.index(observed[i])]
    for i in range(N):
        p += Q[LEN-1][i]
    return p
# 3 种隐藏层状态:sun cloud rain
hidden = []
hidden.append('sun')
hidden.append('cloud')
hidden.append('rain')
N = len(hidden)
# 4 种观察层状态:dry dryish damp soggy
observation = []
observation.append('dry')
observation.append('damp')
observation.append('soggy')
M = len(observation)
# 初始状态矩阵(1*N 第一天是sun,cloud,rain的概率)
P = (0.3,0.3,0.4)
# 状态转移矩阵A(N*N 隐藏层状态之间互相转变的概率)
A=((0.2,0.3,0.5),(0.1,0.5,0.4),(0.6,0.1,0.3))
# 混淆矩阵B(N*M 隐藏层状态对应的观测层状态的概率)
B=((0.1,0.5,0.4),(0.2,0.4,0.4),(0.3,0.6,0.1))
#假设观察到一组序列为observed,输出HMM模型(N,M,A,B,P)产生观察序列observed的概率
observed = ['dry']
print forward(N,M,A,B,P,observed)
observed = ['damp']
print forward(N,M,A,B,P,observed)
observed = ['dry','damp']
print forward(N,M,A,B,P,observed)
observed = ['dry','damp','soggy']
print forward(N,M,A,B,P,observed)

在这里插入图片描述

向后算法代码

#-*-coding:utf-8-*-
__author__ = 'ZhangHe'
def forward(N,M,A,B,P,observed):
    p = 0.0
    #观察到的状态数目
    LEN = len(observed)
    #中间概率LEN*M
    Q = [([0]*N) for i in range(LEN)]
    #令最后时刻所有状态的后向变量为1
    for j in range(N):
        Q[LEN-1][j] = 1
    # 最后时刻之前的状态,Q[i][j]=sum(第i天的当前状态Sj转移到第i+1天的状态Sk的转移概率,
    # 乘上第i+1天的状态Sk生成观测变量Oi+1观测概率,再乘上第i+1天Sk状态的概率   for  k  in   N)
    for i in range(LEN-2,-1,-1):
        for j in range(N):
            sum = 0.0
            for k in range(N):
                sum += A[j][k]*B[k][observation.index(observed[i+1])]*Q[i+1][k]
            Q[i][j] = sum 
    for i in range(N):
        p += Q[0][i]
    return p
# 3 种隐藏层状态:sun cloud rain
hidden = []
hidden.append('sun')
hidden.append('cloud')
hidden.append('rain')
N = len(hidden)
# 4 种观察层状态:dry dryish damp soggy
observation = []
observation.append('dry')
observation.append('damp')
observation.append('soggy')
M = len(observation)
# 初始状态矩阵(1*N第一天是sun,cloud,rain的概率)
P = (0.3,0.3,0.4)
# 状态转移矩阵A(N*N 隐藏层状态之间互相转变的概率)
A=((0.2,0.3,0.5),(0.1,0.5,0.4),(0.6,0.1,0.3))
# 混淆矩阵B(N*M 隐藏层状态对应的观察层状态的概率)
B=((0.1,0.5,0.4),(0.2,0.4,0.4),(0.3,0.6,0.1))
#假设观察到一组序列为observed,输出HMM模型(N,M,A,B,P)产生观察序列observed的概率
observed = ['dry']
print(forward(N,M,A,B,P,observed))
observed = ['damp']
print(forward(N,M,A,B,P,observed))
observed = ['dry','damp']
print(forward(N,M,A,B,P,observed))
observed = ['dry','damp','soggy']
print(forward(N,M,A,B,P,observed))

在这里插入图片描述

viterbi算法代码
def viterbi(N,M,A,B,P,hidden,observed):
    sta = []
    LEN = len(observed)
    Q = [([0]*N) for i in range(LEN)]
    path = [([0]*N) for i in range(LEN)]
    #第一天计算,状态的初始概率*隐藏状态到观察状态的条件概率
    for j in range(N):
        Q[0][j]=P[j]*B[j][observation.index(observed[0])]
        path[0][j] = -1
    # 第一天以后的计算
    # 前一天的每个状态转移到当前状态的概率最大值
    # *
    # 隐藏状态到观察状态的条件概率
    for i in range(1,LEN):
        for j in range(N):
            max = 0.0
            index = 0
            for k in range(N):
                if(Q[i-1][k]*A[k][j] > max):
                    max = Q[i-1][k]*A[k][j]
                    index = k
            Q[i][j] = max * B[j][observation.index(observed[i])]
            path[i][j] = index
    #找到最后一天天气呈现哪种观察状态的概率最大
    max = 0.0
    idx = 0
    for i in range(N):
        if(Q[LEN-1][i]>max):
            max = Q[LEN-1][i]
            idx = i
    print "最可能隐藏序列的概率:"+str(max)
    sta.append(hidden[idx])
    #逆推回去找到每天出现哪个隐藏状态的概率最大
    for i in range(LEN-1,0,-1):
        idx = path[i][idx]
        sta.append(hidden[idx])
    sta.reverse()
    return sta;
# 3 种隐藏层状态:sun cloud rain
hidden = []
hidden.append('sun')
hidden.append('cloud')
hidden.append('rain')
N = len(hidden)
# 4 种观察层状态:dry dryish damp soggy
observation = []
observation.append('dry')
observation.append('damp')
observation.append('soggy')
M = len(observation)
# 初始状态矩阵(1*N第一天是sun,cloud,rain的概率)
P = (0.3,0.3,0.4)
# 状态转移矩阵A(N*N 隐藏层状态之间互相转变的概率)
A=((0.2,0.3,0.5),(0.1,0.5,0.4),(0.6,0.1,0.3))
# 混淆矩阵B(N*M 隐藏层状态对应的观察层状态的概率)
B=((0.1,0.5,0.4),(0.2,0.4,0.4),(0.3,0.6,0.1))
#假设观察到一组序列为observed,输出HMM模型(N,M,A,B,P)产生观察序列observed的概率
observed = ['dry','damp','soggy']
print viterbi(N,M,A,B,P,hidden,observed)

参考:
http://www.cnblogs.com/CheeseZH/ 作者:ZH奶酪——张贺
博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:张朝阳

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值