通过案例+python代码,理解--维特比算法(viterbi algorithm)--HMM

在HMM等场景只中中会使用到维特比算法,那么维特比算法具体是怎么实现的呢?

例子:老师布置的作业和老师当天的心情有关。

老师今天的心情是good,那么第二天的心情可能是good、neutral、bad中的一种。如果老师心情很好,很有可能会布置一个简单的作业,也可能会布置很难的作业,但是简单作业的概率更高;同样的,当老师的心情是bad的时候,更有可能布置一个很难的作业。作业的难度有A、B、C三种情况。

这里,把心情叫做状态序列,把作业叫做观测序列。

比如从周一到周五:

状态序列goodneutralgoodbadbad
观测序列AABCC

周一老师的心情是good,布置的作业是难度A,第二天,老师的心情变成了neutral,同样布置的作业是难度A,周三老师的心情变成了good,布置的作业难度是B……

介绍一下隐马尔可夫模型中的两个假设:

(1)当前的状态只和前一个状态有关,即周二的状态只和周一的状态有关。

(2)观测到的数据之和当前的状态有关,即周三布置的作业难度只和周三的心情有关。

初始状态矩阵

周二的状态可以从周一的状态通过乘上概率得到,但是周一的状态要怎么得到呢?

这时候就需要事前给出初始状态。

[0.33,0.33,0.33]

意思是第一天(初始时),心情是good的概率是0.33,心情是neutral的概率是0.33。

状态转移矩阵

状态转移函数是good,neutral,bad三种心情之间的转变概率。纵坐标是当前心情,横坐标是转变到的心情。

(bad,good)=0说明如果今天的心情是bad,那么第二天是不会变成good的,有0.2的概率变成neutral,有0.58的概率还是bad。

goodneutralbad
good0.20.30.5
neutral0.20.20.6
bad0.00.20.8

观测矩阵

观测矩阵是当前状态下布置各种作业的概率

ABC
good0.70.20.1
neutral0.30.40.3
bad0.00.10.9

对于neutral这一行,如果老师的心情是neutral,他布置难度为A的作业的概率是0.3,难度为B是0.4,难度为C是0.9。

计算方式

接下来就说维特比算法要怎么用来计算。

现在已经知道了初始状态矩阵+状态转移矩阵+观测矩阵。

也知道了老师一周五天布置的作业是A C B A C,求解出老师一周最有可能的心情是什么样的?

第一天:当心情是good的时候,布置作业A的概率:0.33*0.7=0.23.(0.33是心情为good的概率,0.7是心情为good的时候布置作业A的概率)。

当心情是neutral的时候,布置作业A的概率:0.33*0.3=0.1

当心情是bad的时候,布置作业A的概率:0.33*0=0.0

关键是如何求解周二的:

求解周二是在周一的基础上进行的。

以(good,C)为例子,意思是周二心情是good的时候,布置作业C的最大概率(注意,这里以及之后求的都是最大概率)。

从周一来到周二并且布置作业C有三条路,从(good,A)到(good,C),从(neutral,A)到(good,C),从(bad,A)到(good,C)​​​​​​​。

概率是:
0.23*0.2*0.1=0.0046;(0.23是(good,A)的概率,0.2是心情从good变成good的概率,0.1是心情为good时布置作业C的概率)

0.1*0.2*0.1=0.002;(0.23是(neutral,A)的概率,0.2是心情从neutral变成good的概率,0.1是心情为good时布置作业C的概率)

0=0;

在这里求出的三个数值,最大的是0.0046,所以(good,C)就是0.0046,这个是从(good,A)这条路来的,花上一个箭头,从(good,C)​​​​​​​指向(good,A)。

同理,求出(neutral,C)和(bad,C),他们取得最大值的时候,都是从(good,A)这条路过来的。这样就完成了周二的表格。

接着完成周三、四、五的表格,求解周四时,是在周三的基础上进行的,周四要填的3个数据,每一个数据都有三条路可以达到,选择概率最大值。

最后得到的表格如下,数值可能不对,但是形式是这样的:

回溯

最后进行回溯:
最后一列中概率最大值是0.0005216,然后它是从0.0011592这条路得到的,0.0011592是从0.00828得到的,按照红色箭头的顺序进行回溯,便可以得到:
(bad,C)-->(good,A)-->(neutral,B)-->(bad,C)-->(good,A).

对应的时间是周五到周一:
返回来,从周一到周五:
(good,A)-->(bad,C)-->(neutral,B)-->(good,A)-->(bad,C).

即作业是ACBAC时,最有可能的情绪是:good,bad,neutral,good,bad。

代码
# viterbi algorithm---Teacher emotions and homework

import numpy as np

# Initial probability
pai = np.array([0.333333, 0.333333, 0.333333])
# transition probability
A = np.array([[0.2, 0.3, 0.5], [0.2, 0.2, 0.6], [0.0, 0.2, 0.8]])
# Observation probability
B = np.array([[0.7, 0.2, 0.1], [0.3, 0.4, 0.3], [0.0, 0.1, 0.9]])
# condition number
statesN = 3
# Status dictionary
stateDict = {0: "good", 1: "neutral", 2: "bad"}
# Observed number
observedN = 3
# Observation dictionary
observedDict = {0: 'A', 1: 'B', 2: 'C'}
# observation sequence
observedSequence = np.array([0, 2, 1, 0, 2])
# time span
T = 5

# Initializes the dynamic programming table
V = np.zeros((T, statesN))
# A backtracking table that stores the optimal path
backpointer = np.zeros((T, statesN), dtype=int)

# Initialize the first column
V[0, :] = pai * B[:, observedSequence[0]]

# Recursive computation
for t in range(1, T):
    for s in range(statesN):
        trans_prob = V[t - 1, :] * A[:, s]
        max_trans_prob = np.max(trans_prob)
        V[t, s] = max_trans_prob * B[s, observedSequence[t]]
        backpointer[t, s] = np.argmax(trans_prob)

# Backtrack to find the most likely sequence of states
best_path = np.zeros(T, dtype=int)
best_path[T - 1] = np.argmax(V[T - 1, :])

for t in range(T - 2, -1, -1):
    best_path[t] = backpointer[t + 1, best_path[t + 1]]

# Print result
print("\nprobability matrix:")
for t in range(T):
    print(f" {V[t, :]}")

print("observation sequence:", ''.join([observedDict[i] for i in observedSequence]))
print("The most likely sequence of states:", ' -> '.join([stateDict[i] for i in best_path]))



运行结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值