给定隐马尔可夫模型 λ \lambda λ,定义到时刻 t t t部分观测序列为 o 1 , o 2 , ⋯ , o t o_1,o_2,\cdots,o_t o1,o2,⋯,ot且状态为 s i s_i si的概率为前向概率,记作 α t ( i ) = P ( o 1 , o 2 , ⋯ , o t , i t = s i ∣ λ ) \alpha_t(i)=P(o_1,o_2,\cdots,o_t,i_t=s_i|\lambda) αt(i)=P(o1,o2,⋯,ot,it=si∣λ)。可以递推地求出前向概率 α t ( i ) \alpha_t(i) αt(i)以及观测序列概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)
(1)初值
α 1 ( i ) = π i b i ( o 1 ) , i = 1 , 2 , ⋯ , N \alpha_1(i)=\pi_i b_i (o_1),\;\;\;\;i=1,2,\cdots,N α1(i)=πibi(o1),i=1,2,⋯,N
第一个时刻,i代表不同的状态,pi表示初始概率,b为发射概率,如:从5个盒子中抽球,第一个抽到红球,i对应的就是1,b为红球在第一个盒子中被抽出来的概率(发射概率)
结果是5个数据,第i数据表示第1个时刻从第i球中抽出红球的概率
(2)递推 对 t = 1 , 2 , ⋯ , T − 1 t=1,2,\cdots,T-1 t=1,2,⋯,T−1
α t + 1 ( i ) = [ ∑ j = 1 N α t ( j ) a j i ] b i ( o t + 1 ) , i = 1 , 2 , ⋯ , N 示例 t = 1 , i = 1 α 2 ( 1 ) = [ ∑ j = 1 N α 1 ( j ) a j 1 ] b 1 ( o 2 ) t = 1 , i = 2 α 2 ( 2 ) = [ ∑ j = 1 N α 1 ( j ) a j 2 ] b 2 ( o 2 ) t = 1 , i = 3 α 2 ( 3 ) = [ ∑ j = 1 N α 1 ( j ) a j 3 ] b 3 ( o 2 ) \alpha_{t+1}(i)=\left[\sum_{j=1}^{N}\alpha_t(j)a_{ji}\right]b_i(o_{t+1}),\;\;\;\;i=1,2,\cdots,N \\ \\ 示例\;\;t=1,\;i=1\\ \alpha_2(1)=\left[\sum_{j=1}^{N}\alpha_1(j)a_{j1}\right]b_1(o_2)\\ t=1,\;i=2\\ \alpha_2(2)=\left[\sum_{j=1}^{N}\alpha_1(j)a_{j2}\right]b_2(o_2)\\ t=1,\;i=3\\ \alpha_2(3)=\left[\sum_{j=1}^{N}\alpha_1(j)a_{j3}\right]b_3(o_2)\\ αt+1(i)=[j=1∑Nαt(j)aji]bi(ot+1),i=1,2,⋯,N示例t=1,i=1α2(1)=[j=1∑Nα1(j)aj1]b1(o2)t=1,i=2α2(2)=[j=1∑Nα1(j)aj2]b2(o2)t=1,i=3α2(3)=[j=1∑Nα1(j)aj3]b3(o2)
第二个时刻则是前一个时刻求出的5个数据,每个数据乘转移概率和再乘当前时刻的发射概率
a(t)j表示上个时刻求出的5个值,aji表示从j状态转移到i状态的概率
(3)终止
P ( O ∣ λ ) = ∑ i = 1 N α T ( i ) P(O|\lambda)=\sum_{i=1}^{N}\alpha_T(i) P(O∣λ)=i=1∑NαT(i)
概率求和(算出的5个状态分别对应的值进行求和)
随机从4个盒子中抽出5个球 ,求该序列的概率
前向概率计算函数:forward_probability()
其中是通过矩阵运算,所以公式的求和的符号可能提现的不明显,可以输出运算后结果进而理解运算过程
import numpy as np
class HMM(object):
def __init__(self, N, M, pi=None, A=None, B=None):
self.N = N # 盒子数量
self.M = M # 球颜色数量
self.pi = pi # 初始概率向量
self.A = A # 转移概率矩阵
self.B = B # 观测概率矩阵
def get_data_with_distribute(self, dist):
# 根据给定的概率分布,返回一个索引
return np.random.choice(np.arange(len(dist)), p=dist)
def generate(self, T : int):
# T 要生成的数据的数量
# 根据给定额参数生成观测序列
# 根据初始概率分布,获取从哪个盒子取第一个球
z = self.get_data_with_distribute(self.pi) # 得到的是第一个盒子的编号
# 从上一个盒子中根据观测概率选中一个球(颜色)
x = self.get_data_with_distribute(self.B[z]) #x代表球的颜色,0红色 1白色
result = [x]
for _ in range(T-1):
z = self.get_data_with_distribute(self.A[z]) # 得到下一个盒子
x = self.get_data_with_distribute(self.B[z]) # 从该盒子中随机选中一个颜色
result.append(x)
return result
def forward_probability(self, X):
# 根据给定的观测序列X,计算观测序列出现的概率
alpha = self.pi * self.B[:, X[0]]
# print(type(alpha))
for x in X[1:]:
# print(alpha)
# print(self.A)
# print(np.matmul(alpha, self.A))
alpha = np.matmul(alpha, self.A) * self.B[:, x]
return alpha.sum()
if __name__ == '__main__':
pi = np.array([.25, .25, .25, .25])
A = np.array([
[0, 1, 0, 0],
[.4, 0, .6, 0],
[0, .4, 0, .6],
[0, 0, .5, .5]])
B = np.array([
[.5, .5],
[.3, .7],
[.6, .4],
[.8, .2]])
assert len(A) == len(pi)
assert len(A) == len(B)
hmm = HMM(B.shape[0], B.shape[1], pi, A, B)
seq = hmm.generate(5)
print('抽出球的序列:', seq)
print('概率值:', hmm.forward_probability(seq))
心得:通过理解公式后再去理解运算过程和代码会很简单,关于矩阵运算对应到公式起初理解困难,多思考,多打印结果值,理解每步后方可打通任督二脉