说明
这个是以前写的代码,回顾一下
内容
1 基础理论概要
- 1 HMM 从信号处理的角度出发
- 2 本质上HMM本身要处理的问题类型是有更大拓展意义的(毕竟大多数信息处理都可以视为一个通信系统)
- 3 不过处理人类决策相关的系统HMM不能直接胜任(更适合处理自然类的问题)
- 4 Deterministic Model(确定性模型) 处理一些具体的特征
- 5 Statistical Model(统计性模型) 只考虑信号的统计特征
- 6 潜在的假设: 信号可以用一些参数化的随机过程概括
- 7 三类问题
- 1 给定一个HMM,一个观察序列的概率评估(或者说似然)
- 2 判定模型具备的最佳(隐含)状态序列
- 3 调整模型参数来最佳拟合观察序列
- 模型的几个参数:
- 1 Pi,
- 2 A(转移矩阵)
- 3 B(发射矩阵)
- 4 N(隐含状态)
- 5 M(观察状态)
本质上应该就是A和B. (Pi在到达稳态的时候是不变的,反过来说,只有模型随时可能切换的情况下讨论Pi在有意义)
N和M已经蕴含在A和B之中了。
A是隐藏状态变化,而B则是隐藏状态和可观察状态的联系
2 代码
import numpy as np
class aHMM():
def __init__(self):
self.pi = None
self.A = None
self.B = None
self.N = None
self.M = None
self.obs_series = None
self.hs = None
self.result_series = None
def init(self, _pi=None, _A=None, _B=None):
if self.pi is None:
self.pi = _pi
else:
print('Pi Already has a value :' + str(self.pi))
# input 有问题
# if input("Overwrite Y/N ").upper == 'Y':
self.pi = _pi
print('New Pi is:' + str(self.pi))
self.A = _A
self.B = _B
def input_obs(self, _obs_series):
self.obs_series = np.array(_obs_series)
def forward(self):
# 事实上应该做mapping,使得矩阵中状态的选取为整形
# 取观察对应的发射向量
self.result_series = []
_obs_prob_emission = self.B[:, self.obs_series[0]]
# 隐含状态乘以对应的发射向量,为对应的概率结果
_result = self.pi * _obs_prob_emission
self.result_series.append(_result)
for x in self.obs_series[1:]:
_obs_prob_emission = self.B[:, x]
_hidden_state_vector = np.dot(self.result_series[-1], self.A)
_result = _hidden_state_vector * _obs_prob_emission
self.result_series.append(_result)
这里主要是前向函数的那部分:
- 1 一开始通过最初的观察,反推第一个时刻的隐藏向量
- 2 迭代的推断隐藏状态
- 3 得到最终的结果(这个模式的概率)
从Obs->B->pi ->pi(更新),反复进行。得到的结果是pi的序列(隐藏状态向量)。
按经典的故事,应该是看到一系列色子的投掷结果,猜是哪类色子。
3 例子
按定义,这是一个N=3,M=4的情况
# 1 初始化
test = aHMM()
# 2 参数定义
pi = np.array([0.63, 0.17, 0.2])
a = np.array([[0.5, 0.375, 0.125],
[0.25, 0.125, 0.625],
[0.25, 0.375, 0.375]])
b = np.array([[0.6, 0.2, 0.15, 0.05],
[0.25, 0.25, 0.25, 0.25],
[0.05, 0.1, 0.35, 0.5]])
# 3 观察数据
obs = [0, 2, 3]
# 4 准备开始
test.init(_pi=pi, _A=a, _B=b)
test.input_obs(obs)
# 5 运行
test.forward()
print(np.sum(test.result_series[-1]))
---
0.026901406250000003
这只是初步的模型,用原始概率值计算没几步就下溢了。
看看完整的序列
test.result_series
---
[array([0.378 , 0.0425, 0.01 ]),
array([0.03031875, 0.03770312, 0.02714688]),
array([0.00156859, 0.00656563, 0.01876719])]
验算第一步
test.B
array([[0.6 , 0.2 , 0.15, 0.05],
[0.25, 0.25, 0.25, 0.25],
[0.05, 0.1 , 0.35, 0.5 ]])
_obs_prob_emission = test.B[:,0]
---
array([0.6 , 0.25, 0.05])
test.pi *_obs_prob_emission
---
array([0.378 , 0.0425, 0.01 ])