说明

这个是以前写的代码,回顾一下

内容

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  ])