作者:孙相国
转载请注明出处
参考文献
- 《机器学习郑捷》第11章
- 机器学习周志华 14章
- 《统计学系方法》第10章
- 《概率图模型》第3章贝叶斯网表示和马尔科夫
《驾驭文本》
隐马尔科夫模型
两个基本假设:
齐次马尔科夫性假设:隐藏的马尔科夫链在任意时刻\(t\)的状态只依赖于前一时刻的状态,与其他时刻的状态及观测无关,也与时刻\(t\)无关。
观测独立性假设:任意时刻的观测只依赖于该时刻的马尔科夫链的状态,与其他观测及状态无关。
说人话,就下面这个图,其中箭头和连边表示概率依赖。
从这个图中,我们可以很轻松的对后面的一些公式做推导。比如:
\[ \left( o_{t+1}|o_{1:t},I_{t+1}=q_i\right)=\left( o_{t+1}|I_{t+1}=q_i\right)\tag{1.1} \]
上面的公式为了书写简便,我们省略掉了概率符号\(P\)(下同),并且用\(o_{1:t}\)表示\(\left(o_1,\cdots,o_t \right)\)(下同)。
\[ \left( I_{t+1}=q_i|o_{1:t},I_t=q_j\right)=\left( I_{t+1}=q_i|I_t=q_j\right)\tag{1.2} \]
\[ \left( o_{t+1:T}|I_{t+1}=q_i,I_t=q_i\right)=\left( o_{t+1:T}|I_{t+1}=q_i\right)\tag{1.3} \]
\[ \left( o_{t+2:T}|I_{t+1}=q_j,o_{t+1}\right)=\left( o_{t+2:T}|I_{t+1}=q_j\right)\tag{1.4} \]
\[ \left( I_{t+1}|o_{1:t},I_t\right)=\left( I_{t+1}|I_t\right)\tag{1.5} \]
\[ \left(o_{t+1}|I_{t+1},o_{1:t},I_t \right)=\left(o_{t+1}|I_{t+1}\right)\tag{1.6} \]
基本定义:
转移概率\(a_{ij}=\left( I_{t+1}=q_j|I_t=q_i\right)\)
观测概率\(b_j\left(o_t\right)=\left(o_t|I_t=q_j\right)\)
初始状态概率\(\pi_i=P\left(I_1=q_i\right)\)
隐马尔科夫模型的3个基本问题
- 概率计算
- 学习问题
预测问题/解码问题
概率计算问题
前向算法
前向概率\(\alpha_t\left(i\right)=\left(o_{1:t},I_t=q_i\right)\)
转移概率\(a_{ij}=\left( I_{t+1}=q_j|I_t=q_i\right)\)
观测概率\(b_j\left(o_t\right)=\left(o_t|I_t=q_j\right)\)
初始状态概率\(\pi_i=P\left(I_1=q_i\right)\)
初始前向概率:
\[\begin{equation}\begin{split}\alpha_1\left(i\right)&=\left(o_{1},I_1=q_i\right) \\&=\left(I_1=q_i\right)\left(o_1|I_1=q_i\right)\\&=\pi_ib_i\left(o_1\right)\end{split}\tag{1.8}\end{equation}\]
前向概率的迭代推导:
\[\begin{equation} \begin{split} \alpha_{t+1}\left(i\right)&=\left(o_{1:t+1},I_{t+1}=q_i\right) \\ &= \left(o_{1:t},I_{t+1}=q_i\right)\left( o_{t+1}|o_{1:t},I_{t+1}=q_i\right)\\ &= \left(o_{1:t},I_{t+1}=q_i\right)\left( o_{t+1}|I_{t+1}=q_i\right)\text{(由公式(1.1)得来)}\\ &=\left(o_{1:t},I_{t+1}=q_i\right)b_i\left(o_{t+1}\right)\\ &=\left(\sum_j\left(o_{1:t},I_t=q_j,I_{t+1}=q_i\right)\right)b_i\left(o_{t+1}\right)\\ &=\left(\sum_j\left(o_{1:t},I_t=q_j\right)\left(I_{t+1}=q_i|o_{1:t},I_t=q_j\right)\right)b_i\left(o_{t+1}\right)\\ &=\left(\sum_j\left(o_{1:t},I_t=q_j\right)\left(I_{t+1}=q_i|I_t=q_j\right)\right)b_i\left(o_{t+1}\right)\text{(由公式(1.2)得来)}\\ &=\left(\sum_j\alpha_t\left(j\right)a_{ji}\right)b_i\left(o_{t+1}\right) \end{split}\tag{1.9} \end{equation} \]
终止状态推导:
\[ \begin{equation} \begin{split} P\left(O |\lambda \right)&=\left(o_{1:T}|\lambda\right) \\ &=\sum_i^N \left(o_{1:t},I_{T}=q_i\right)\\ &=\sum_i^N\alpha_T\left(i\right) \end{split}\tag{1.10} \end{equation} \]
算法1.1(观测序列概率的前向算法)
输入:隐马尔科夫模型\(\lambda\),观测序列\(O\);
输出:观测序列概率\(P\left( O|\lambda\right)\)。
根据公式\((1.8)\),设定初值。
根据公式\((1.9)\)递推。其中\(t=1,2,\cdots,T-1\)。
终止。根据公式\((1.10)\)得到输出。
python实现(李航《统计学习方法》177页例题10.2):
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@author: XiangguoSun
@contact: sunxiangguodut@qq.com
@file: forward_prob.py
@time: 2017/3/13 8:53
@software: PyCharm
"""
import numpy as np
def forward_prob(model, Observe, States):
'''
马尔科夫前向算法
'''
A, B, pi = model
N = States.size
T = Observe.size
alpha = pi*B[:, Observe[0]]
print "(1)计算初值alpha_1(i): ",alpha
print "(2) 递推..."
for t in xrange(0, T-1):
print "t=", t+1," alpha_",t+1,"(i):",alpha
alpha = alpha.dot(A)*B[:, Observe[t+1]]
print "(3)终止。alpha_",T,"(i): ", alpha
print "输出Prob: ",alpha.sum()
return alpha.sum()
if __name__ == '__main__':
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 = np.array([0.2, 0.4, 0.4])
model = (A, B, pi)
Observe = np.array([0, 1, 0])
States = np.array([1, 2, 3])
forward_prob(model,Observe,States)
后向算法
后向概率:\(\beta_t\left( i\right)=\left( o_{t+1:T}|I_t=q_i\right)\)
初始后向概率:\(\beta_T\left(i\right)=1,i=1,2,\cdots,N\)
后向概率迭代推导:
\[ \begin{equation} \begin{split} \beta_t\left(i\right)&=\left(o_{t+1:T}|I_t=q_i\right) \\ &=\sum_j^N \left(o_{t+1:T},I_{t+1}=q_j|I_{t}=q_i\right)\\ &=\sum_j^N\left(I_{t+1}=q_j|I_{t}=q_i\right) \left(o_{t+1:T}|I_{t+1}=q_j,I_{t}=q_i\right)\\ &=\sum_j^N\left(I_{t+1}=q_j|I_{t}=q_i\right) \left(o_{t+1:T}|I_{t+1}=q_j\right)\text{(由公式(1.3)得到)}\\ &=\sum_j^N\left(I_{t+1}=q_j|I_{t}=q_i\right) \left(o_{t+1}|I_{t+1}=q_j\right)\left(o_{t+2:T}|I_{t+1}=q_j,o_{t+1}\right)\\ &=\sum_j^N a_{ij} b_j\left(o_{t+1}\right) \beta_{t+1}\left(j\right) \end{split}\tag{1.11} \end{equation} \]
终止状态推导:
\[ \begin{equation} \begin{split} P\left(O|\lambda\right)&=\left(o_{1:T}|\lambda\right) \\ &=\sum_{i=1}^N \left(o_{1:T},I_{1}=q_i\right)\\ &=\sum_{i=1}^N \left(I_1=q_i\right)\left(o_{1:T}|I_{1}=q_i\right)\\ &=\sum_{i=1}^N \left(I_1=q_i\right)\left(o_1|I_1=q_i\right)\left(o_{2:T}|o_1,I_{1}=q_i\right)\\ &=\sum_{i=1}^N\pi_i b_i\left(o_i\right)\left(o_{2:T}|I_{1}=q_i\right)\\ &=\sum_{i=1}^N\pi_i b_i\left(o_i\right)\beta_1\left(i\right) \end{split}\tag{1.12} \end{equation} \]
算法1.2(观测序列概率的后向算法)
输入:隐马尔科夫模型\(\lambda\),观测序列\(O\);
输出:观测序列概率\(P\left( O|\lambda\right)\)。
- 设定后向概率初值为1。
- 根据公式\((1.11)\)递推。其中\(t=T-1,T-2,\cdots,1\)。
- 终止。根据公式\((1.12)\)得到输出。
python实现(李航《统计学习方法》177页例题10.2):
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@author: XiangguoSun
@contact: sunxiangguodut@qq.com
@file: markov.py
@time: 2017/3/13 8:53
@software: PyCharm
"""
import numpy as np
def forward_prob(model, Observe, States):
'''
马尔科夫前向算法
'''
A, B, pi = model
N = States.size
T = Observe.size
alpha = pi*B[:, Observe[0]]
print "(1)计算初值alpha_1(i): ",alpha
print "(2) 递推..."
for t in xrange(0, T-1):
alpha = alpha.dot(A)*B[:, Observe[t+1]]
print "t=", t + 1, " alpha_", t + 1, "(i):", alpha
print "(3)终止。alpha_",T,"(i): ", alpha
print "输出Prob: ",alpha.sum()
return alpha.sum()
def backward_prob(model,Observe,States):
'''
马尔科夫后向算法
'''
A, B, pi = model
N = States.size
T = Observe.size
beta = np.ones((N,)) # beta_T
print "(1)计算初值beta_",T,"(i): ", beta
print "(2) 递推..."
for t in xrange(T - 2, -1, -1): # t=T-2,...,0
beta = A.dot(B[:, Observe[t + 1]] * beta)
print "t=", t + 1, " beta_", t + 1, "(i):", beta
print "(3)终止。alpha_", 1, "(i): ", beta
prob = pi.dot(beta * B[:, Observe[0]])
print "输出Prob: ", prob
return prob
if __name__ == '__main__':
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 = np.array([0.2, 0.4, 0.4])
model = (A, B, pi)
Observe = np.array([0, 1, 0])
States = np.array([1, 2, 3])
forward_prob(model,Observe,States)
backward_prob(model, Observe, States)
实验结果: