您的位置:首页 > 其它

HMM 模型

2016-05-21 09:39 309 查看

马尔可夫链

一个系统有N个状态 S1,S2,···,Sn,随着时间推移,系统从某一状态转移到另一状态,设qt为时间t的状态,系统在时间t处于状态Sj 的概率取决于其在时间 1 ,2,···,t-1 的状态,该概率为:



如果系统在t时间的状态只与其在时间 t -1的状态相关,则该系统构成一个离散的一阶马尔可夫链(马尔可夫过程):



马尔可夫模型

如果只考虑独立于时间t的随机过程:



其中状态转移概率 aij 必须满足 aij>=0 , 且


,则该随机过程称为马尔可夫模型。

假定一段时间的气象可由一个三状态的马尔可夫模型M描述,S1:雨,S2:多云,S3:晴,状态转移概率矩阵为:



如果第一天为晴天,根据这一模型,在今后七天中天气为O=“晴晴雨雨晴云晴”的概率为:



隐马尔可夫模型

对于一个随机事件,有一观察值序列: O=O1,O2,…OT

该事件隐含着一个状态序列: Q = q1,q2,…qT。

假设1:马尔可夫性假设(状态构成一阶马尔可夫链)
P(qi|qi-1…q1) = P(qi|qi-1)
假设2:不动性假设(状态与具体时间无关)
P(qi+1|qi) = P(qj+1|qj),对任意i,j成立
假设3:输出独立性假设(输出仅与当前状态有关)
p(O1,...,OT | q1,...,qT) = Πp(Ot | qt)


HMM定义

一个隐马尔可夫模型 (HMM) 是由一个五元组描述的:

λ =( N,M ,A,B, π )

其中:

N = {q1,…qN}:状态的有限集合

M = {v1,…,vM}:观察值的有限集合

A = {aij},aij = P(qt = Sj |qt-1 = Si):状态转移概率矩阵

B = {bjk}, bjk = P(Ot = vk | qt = Sj):观察值概率分布矩阵

π = {πi},πi = P(q1 = Si):初始状态概率分布

观察状态是已知的,隐状态是未知的。

三个基本问题

令 λ = {π,A,B} 为给定HMM的参数,

令 O = O1,…,OT 为观察值序列,则有关于

隐马尔可夫模型(HMM)的三个基本问题:

1.评估问题:对于给定模型,求某个观察值序列的概率P(O|λ) ;

• 计算骰子点数序列的确由“作弊”模型生成的可能性

2.解码问题:对于给定模型和观察值序列,求可能性最大的状态序列maxQ{P(Q|O,λ)};

• 在骰子点数序列中, 判断哪些点数是用骰子B掷出的

3.学习问题:对于给定的一个观察值序列O,调整参数λ,使得观察值出现的概率P(O|λ)最大。

• 如何从大量的点数序列样本中学习得出“作弊模型”的参数

三个基本问题解法

评估问题:前向算法

定义前向变量

采用动态规划算法,复杂度O(N2T)

解码问题:韦特比(Viterbi)算法

采用动态规划算法,复杂度O(N2T)

学习问题:向前向后算法

EM算法的一个特例,带隐变量的最大似然估计

HMM将两个序列相联系起来:

由离散隐状态组成的状态序列(路径),Q = (q1,…,qT), 每个qt∈S均是一个状态,由初始状态概率及状态转移概率(π, A)所决定

由明字符组成的观察序列,O = (o1,…,oT), 每个ot∈V均为一个离散明字符,由状态序列及各状态的明字符生成概率(Q,B)所决定。

package org.digdata.hmm;

/**
* HMM对象类
*/
public class HMM implements Cloneable {

/**
* 隐藏状态数目
*/
public int N;

/**
* 观察状态数目
*/
public int M;

/**
* 状态转移矩阵 一个隐状态到另一个隐状态的概率
*/
public double[][] A;

/**
* 混淆矩阵 一个隐状态到观察状态的概率
*/
public double[][] B;

/**
* 初始向量
*/
public double[] pi;

@Override
public Object clone() {
HMM hmm = null;
try {
hmm = (HMM) super.clone();
hmm.A = A.clone();
for (int i = 0; i < A.length; i++) {
hmm.A[i] = A[i].clone();
}
hmm.B = B.clone();
for (int i = 0; i < B.length; i++) {
hmm.B[i] = B[i].clone();
}
hmm.pi = pi.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}

return hmm;
}

public HMM() {
super();
}

/**
* @param n
*            隐藏状态数目
* @param m
*            观察状态数目
* @param a
*            状态转移矩阵
* @param b
*            混淆矩阵
* @param pi
*            初始向量
*/
public HMM(int n, int m, double[][] a, double[][] b, double[] pi) {
super();
N = n;
M = m;
A = a.clone();
for (int i = 0; i < a.length; i++) {
A[i] = a[i].clone();
}
B = b.clone();
for (int i = 0; i < b.length; i++) {
B[i] = b[i].clone();
}
this.pi = pi.clone();
}

/**
* 用于参数估计
*
* @param n
*            隐藏状态数目
* @param m
*            观察状态数目
*/
public HMM(int n, int m) {
super();
N = n;
M = m;
A = new double

;
B = new double
[M];
pi = new double
;
}

/**
* 用于测试已知模型
*
* @param a
*            状态转移矩阵
* @param b
*            符号输出矩阵
* @param pi
*            初始向量
*/
public HMM(double[][] a, double[][] b, double[] pi) {
super();
N = a.length;
M = b[0].length;
A = a.clone();
for (int i = 0; i < a.length; i++) {
A[i] = a[i].clone();
}
B = b;
for (int i = 0; i < b.length; i++) {
B[i] = b[i].clone();
}
this.pi = pi.clone();
}

}


HMM 实际问题:

数值计算中的防溢出处理

在前向算法、Viterbi算法以及Baum-Welch算法中,概率值的连续乘法运算很容易导致下溢现象。

解决办法:

1.前向算法中:每一个时间步的运算中都乘以一 个比例因子

2.Viterbi算法中:对概率值取对数后计算
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: