Python实现隐马尔可夫模型前向后向算法详解
本文详细介绍隐马尔可夫模型(HMM)中前向算法与后向算法的Python实现。内容涵盖循环与递归两种编程方式,提供基于《统计学习方法》例子的完整代码示例,并探讨计算过程中的精度问题,帮助开发者深入理解HMM的概率计算逻辑。
本文通过Python代码演示隐马尔可夫模型(HMM)的前向算法与后向算法。针对每种算法,分别提供了基于循环结构和递归结构的两种实现方案,以便读者根据实际需求选择合适的方法。
前向算法Python实现
首先介绍前向算法的循环实现方式。该方法通过迭代计算每个时刻的前向概率,最终求和得到观测序列的概率。
import numpy as np
def hmm_forward(Q, V, A, B, pi, T, O, p):
"""
:param Q: 状态集合
:param V: 观测集合
:param A: 状态转移概率矩阵
:param B: 观测概率矩阵
:param pi: 初始概率分布
:param T: 观测序列和状态序列的长度
:param O: 观测序列
:param p: 存储各个状态的前向概率的列表,初始为空
"""
for t in range(T):
# 计算初值
if t == 0:
for i in range(len(Q)):
p.append(pi[i] * B[i, V[O[0]]])
# 初值计算完毕后,进行下一时刻的递推运算
else:
alpha_t_ = 0
alpha_t_t = []
for i in range(len(Q)):
for j in range(len(Q)):
alpha_t_ += p[j] * A[j, i]
alpha_t_t.append(alpha_t_ * B[i, V[O[t]]])
alpha_t_ = 0
p = alpha_t_t
return sum(p)
# 《统计学习方法》书上例10.2
Q = [1, 2, 3]
V = {'红':0, '白':1}
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
pi = [0.2, 0.4, 0.4]
T = 3
O = ['红', '白', '红']
p = []
print(hmm_forward(Q, V, A, B, pi, T, O, p)) # 0.130218
接着展示前向算法的递归实现方式。递归方法通过定义终止条件,逐层递推计算前向概率,逻辑上更贴近算法定义。
import numpy as np
def hmm_forward_(Q, V, A, B, pi, T, O, p, T_final):
"""
:param T_final:递归的终止条件
"""
if T == 0:
for i in range(len(Q)):
p.append(pi[i] * B[i, V[O[0]]])
else:
alpha_t_ = 0
alpha_t_t = []
for i in range(len(Q)):
for j in range(len(Q)):
alpha_t_ += p[j] * A[j, i]
alpha_t_t.append(alpha_t_ * B[i, V[O[T]]])
alpha_t_ = 0
p = alpha_t_t
if T >= T_final:
return sum(p)
return hmm_forward_(Q, V, A, B, pi, T+1, O, p, T_final)
Q = [1, 2, 3]
V = {'红':0, '白':1}
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
pi = [0.2, 0.4, 0.4]
T = 0
O = ['红', '白', '红']
p = []
T_final = 2 # T的长度是3,T的取值是(0时刻, 1时刻, 2时刻)
print(hmm_forward_(Q, V, A, B, pi, T, O, p, T_final))
后向算法Python实现
随后介绍后向算法的循环实现。后向算法从序列末尾向前递推,计算后向概率,并结合初始概率和观测概率得到最终结果。
import numpy as np
def hmm_backward(Q, V, A, B, pi, T, O, beta_t, T_final):
for t in range(T, -1, -1):
if t == T_final:
beta_t = beta_t
else:
beta_t_ = 0
beta_t_t = []
for i in range(len(Q)):
for j in range(len(Q)):
beta_t_ += A[i, j] * B[j, V[O[t + 1]]] * beta_t[j]
beta_t_t.append(beta_t_)
beta_t_ = 0
beta_t = beta_t_t
if t == 0:
p=[]
for i in range(len(Q)):
p.append(pi[i] * B[i, V[O[0]]] * beta_t[i])
beta_t = p
return sum(beta_t)
# 《统计学习方法》课后题10.1
Q = [1, 2, 3]
V = {'红':0, '白':1}
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
pi = [0.2, 0.4, 0.4]
T = 3
O = ['红', '白', '红', '白']
beta_t = [1, 1, 1]
T_final = 3
print(hmm_backward_(Q, V, A, B, pi, T, O, beta_t, T_final)) # 0.06009
最后展示后向算法的递归实现。递归版本同样通过设定终止条件,反向递推计算后向概率,适用于理解算法的递归结构。
import numpy as np
def hmm_backward(Q, V, A, B, pi, T, O, beta_t, T_final):
if T == T_final:
beta_t = beta_t
else:
beta_t_ = 0
beta_t_t = []
for i in range(len(Q)):
for j in range(len(Q)):
beta_t_ += A[i, j] * B[j, V[O[T+1]]] * beta_t[j]
beta_t_t.append(beta_t_)
beta_t_ = 0
beta_t = beta_t_t
if T == 0:
p=[]
for i in range(len(Q)):
p.append(pi[i] * B[i, V[O[0]]] * beta_t[i])
beta_t = p
return sum(beta_t)
return hmm_backward(Q, V, A, B, pi, T-1, O, beta_t, T_final)
jpgQ = [1, 2, 3]
V = {'红':0, '白':1}
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
pi = [0.2, 0.4, 0.4]
T = 3
O = ['红', '白', '红', '白']
beta_t = [1, 1, 1]
T_final = 3
print(hmm_backward_(Q, V, A, B, pi, T, O, beta_t, T_final)) # 0.06009
在实现过程中,有读者提出疑问:以某道题为例,理论正确答案应为0.061328,但代码计算结果存在微小偏差。经跟踪调试发现,第一次循环结果正确,但从第二次循环开始出现偏差,推测可能由浮点数精度累积误差导致。如有更优解法或发现代码逻辑问题,欢迎指正。
以上内容介绍了Python实现隐马尔可夫模型前向与后向算法的完整过程,旨在帮助读者掌握相关算法的代码实现,供学习参考。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













