关于Vertebi算法的理解以及程序实现
来源:互联网 发布:淘宝二级页面 编辑:程序博客网 时间:2024/06/16 13:53
HMM解码问题
给定一个观察序列O=O1O2...OT,和模型μ=(A,B,π),如何快速有效地选择在一定意义下“最优”的状态序列Q=q1q2...qT,使该状态最好地解释观察序列。
一种想法是求出每个状态的概率rt(i)最大(rt(i)=P(qt=si,O|μ)),记q't(i)=argQmax(rt(i)),但是这样做,忽略了状态之间的关系,很可能两个状态之间的概率为0,即aq't(i)q't+1(i)=0,这样求得的“最优”状态序列是不合法的。
为防止状态之间转移概率为0(断续问题),换一种思路,不是求单个状态求得最大值,而是求得整个状态序列最大值,即求
Q'= argQmaxP(Q|O,μ)
此时用维特比算法,先定义下维特比变量δt(i):在时间t,HMM沿着一条路径到达状态si,并输出观察序列O=O1O2...Ot的最大概率:
δt(i)=max P(q1q2...qt=si,O1O2...Ot|μ)
t t+1
上图中,对于从t时刻三个到 t+1时刻的状态1,到底取状态1,2还是3,不是看单独状态1,2还是3的概率,而是看在状态1,2,3各自的维特比变量值乘以相应的状态转换概率,从中选出最大值,假设2时最大,那么记下t+1时刻状态1之前的路径是t时刻的状态2,以此类推。
δt(i)的递归关系式: δt+1(i)=maxj δt(j)*aji*bi(Ot+1),为了记忆路径,定义路径变量ψt(i),记录该路径上的状态si的前一个状态。
维特比算法:
step1 初始化:
δt(i) = πi*bi(O1), 1≤i≤N
ψt(i) = 0
step2 归纳计算:
δt(i)=max1≤j≤N δt-1(j)*aji*bi(Ot),2≤t≤T;1≤i≤N
记忆路径 ψt(i) = arg [max1≤j≤Nδt-1(j)*aji*bi(Ot)]
step3 终结:
QT' = arg max1≤i≤N [δT(i)]
P'(QT') = max1≤i≤N [δT(i)]
step4 路径回溯:
qt'=ψt+1(qt+1') , t=T-1,T-2...1
时间复杂度
计算某时刻的某个状态的前向变量需要比较前一时刻的N个状态,此时时间复杂度为O(N),每个时刻有N个状态,此时时间复杂度为N*O(N)=O(N2),又有T个时刻,所以时间复杂度为T*O(N2)=O(N2T)。
程序例证
step1 初始化:δ1(1) = 0.2*0.5=0.1 ,δ1(2) = 0.4*0.4=0.16, δ1(3) = 0.4*0.7=0.21
step2 归纳计算:δ2(1) =max[0.1*0.5,0.16*0.3,0.21*0.2]*0.6
...
step3 终结:最佳路径是δ4(1)δ4(2)δ4(3)最大的一个对应的状态
step4 回溯:从最后一个状态往回返
程序代码
package Vertebi;
public class vertebi {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
vertebi vb=new vertebi();
}
public vertebi(){
double[][] a=new double[][]{{0.5,0.2,0.3},{0.3,0.5,0.2},{0.2,0.3,0.5}};
double[][] b=new double[][]{{0.5,0.5},{0.4,0.6},{0.7,0.3}};
double[] Pi=new double[]{0.2,0.4,0.4};
double[][]deta=new double[4][4];
int[] list=new int[]{0,1,0,1};
int count=1;
int[] record=new int[4];
//初始化
deta[0][0]=0.2*0.5;
deta[0][1]=0.4*0.4;
deta[0][2]=0.4*0.7;
deta[0][3]=0;
//初始化得出最大概率
deta[0][3]=0.28;
record[0]=2;
//迭代
for(int i=1;i<=3;i++){
for(int j=0;j<=2;j++){
deta[i][j]=0;
deta[i][j]+=deta[i-1][record[i-1]]*a[record[i-1]][j]*b[j][list[count]];
}
for(int m=2;m>0;m--){
if(deta[i][m]<deta[i][m-1])
{deta[i][3]=deta[i][m-1];
record[i]=m-1;}
else {
deta[i][3]=deta[i][m];
record[i]=m;
}
}
count+=1;
}
//比较大小
for(int k=0;k<=3;k++){
System.out.println(deta[k][3]+" "+record[k]);
}
}
}
0.28 2
0.05039999999999999 1
0.010079999999999999 1
0.0030239999999999993 1
- 关于Vertebi算法的理解以及程序实现
- 关于傅里叶变换的理解、快速傅里叶算法的推导以及蝶形运算的c语言实现
- 关于RSA算法的资料阅读以及程序编写
- 对KMP的理解,以及kmp算法java版本实现
- 字符串匹配:KMP算法的实现以及理解
- RSA算法的理解以及实现(C++)
- 关于Sunday算法以及实现
- 关于CAVLC相关码表在JM程序实现的理解
- Svm算法理解以及MLlib实现
- 关于程序方面的理解
- 关于希尔算法的理解以及两种不同的移动方式
- 关于KMP算法的理解
- 关于KMP算法的理解
- SIFT实现步骤,以及算法程序
- 进程,线程,程序的理解以及区别
- 基于用户(user-based)的协同过滤推荐算法的初步理解以及代码实现
- 深度学习中IU、IoU(Intersection over Union)的概念理解以及python程序实现
- 关于近期CPI的调控以及理解
- POJ 1986 Distance Queries(离线LCA)
- 修改文件夹下,文件名编码
- pku1163
- 跳台阶问题
- Hadoop2-YARN 伪分布模式筹建
- 关于Vertebi算法的理解以及程序实现
- 简单的备份用bash脚本
- LogicalConnection异常的解决
- js跨域问题浅析及解决方法优缺点对比
- 使用CSS过滤效果来改变图片样式
- VS2010 编译 boost thread库
- 优秀js赏析-乐蜂网
- java.lang.IllegalArgumentException: Illegal character in query at index
- 正确使用 Docker 技术的四项基本原则