白话机器学习算法(十六)HMM 隐马尔科夫链

http://blog.csdn.net/wangxin110000/article/details/22955885

隐马尔科夫链主要是两部分:

第一部分:与传统马尔科夫过程一样,都是一个状态转移矩阵,假设是:当前状态只与前一状态有关;

第二部分:在某一状态下会有一个对应的观测模型,不同状态有不同的观测模型;

这点与GMM都是一种两级跳的思想,只是GMM选定的高斯分布之间没有关联,我这次哪个高斯部件来生成与上次选择没有关系,但是HMM前后有关系,不过只有一阶;

用一个图表示如下:


                     (图片来源于互联网)

         观测序列为o1   o2     o3.......oT   每个观测序列的背后都有一个隐含状态,而且这些隐含状态之间有个跳转概率,每个状态对应一个概率密度函数,该状态依据这个概率密度函数来生成观测值;说他是隐马尔科夫链,正是因为,这个马尔科夫过程隐藏在观测值的背后;

HMM有三个参数:

1)初始状态概率 pi ;

2)状态之间的概率转移矩阵A;

3)每个状态对应的生成观测模型B ;

有了这三个参数,我们就能完整的描述一个隐马尔科夫链。

关于这个模型,必然有其应用,其对应的三个问题如下:

1)概率计算的问题:最简单的,我给定HMM的参数,求出观测序列o1   o2     o3.......oT 的概率;

2)学习问题:我给出观测序列o1   o2     o3.......oT 求出这个隐马尔科夫模型的三个参数,这是个最大似然估计的问题;

3)解码问题:给出观测序列o1   o2     o3.......oT,求这个观测背后的状态序列s1   s2     s3.......sT。


对于第一个问题:(概率计算问题)

1)直接计算法


pi为初始状态概率,中间的S是隐含状态,因为对应的S状态序列可能有多种可能性(假设有N种可能状态,序列长度为K,那么就有N的T次方个可能的状态序列),因而对这个公式求和是一个非常复杂的事情。因而这个方法仅仅作为理论推导使用,并不实用;


2)前向算法

这种算法类似于动态规划,每一步利用前一步的结果,这样就不需要重复计算,说他是前向算法,源于其一步一步向前递推的过程,动态规划的算法最重要的是要考虑好,每一步我要保存什么数据,这个数据对下一次的计算有用

用来存储时间截止时间为t ,且 t 时刻状态为 i,且观测现象为o(t) 的概率,那么根据递推我们能得到


aji代表状态转移矩阵中从状态 j 转到状态 i 的概率  bi(o(t+1))代表状态为 i 的时候观察值为o(t+1)的概率,通过这个简单的递推我们能得到


综上我们根据观测序列求出每一步的alpha

最后我们要求的值

代码如下:

[cpp]  view plain copy
  1. #include<iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. typedef struct namuna  
  6. {  
  7.     double *pi;  //初始向量转移矩阵  
  8.     double **A;  //状态转移矩阵  
  9.     double **B;  //状态->现象转移矩阵  
  10.     int NumofState;  //状态数目   
  11.     int NumofObs;    //观测现象数目   
  12.     namuna(int NumofState_Input,int NumofObs_Input)  
  13.     {  
  14.         if (NumofObs_Input<=0||NumofState_Input<=0)  
  15.         {  
  16.             return;  
  17.         }  
  18.         NumofState=NumofState_Input;  
  19.         NumofObs=NumofObs_Input;  
  20.         pi=new double[NumofState];  
  21.   
  22.         A=(double **)new int[NumofState];  
  23.         for (int i=0;i<NumofState;i++)  
  24.         {  
  25.             A[i]=new double[NumofState];  
  26.         }  
  27.   
  28.         B=(double **)new int[NumofState];         
  29.         for (int i=0;i<NumofState;i++)  
  30.         {  
  31.             B[i]=new double[NumofObs];  
  32.         }  
  33.     }  
  34.     ~namuna()  
  35.     {  
  36.         delete []pi;  
  37.         for (int i=0;i<NumofState;i++)  
  38.         {  
  39.             delete []A[i];  
  40.         }  
  41.         delete []A;  
  42.         for (int i=0;i<NumofState;i++)  
  43.         {  
  44.             delete []B[i];  
  45.         }  
  46.         delete []B;  
  47.     }  
  48.   
  49.   
  50. }Namuna;  
  51. //输出在给定模型参数情况下,当前观测序列出现的概率  
  52. double HMMQX(Namuna &namuna_Input,int *pObs,int nLenofObsSeq);  
  53. int main()  
  54. {  
  55.   
  56.     Namuna nam(3,2);  
  57.   
  58.     nam.pi[0]=0.2;nam.pi[1]=0.4;nam.pi[2]=0.4;  
  59.   
  60.     nam.A[0][0]=0.5;nam.A[0][1]=0.2;nam.A[0][2]=0.3;  
  61.     nam.A[1][0]=0.3;nam.A[1][1]=0.5;nam.A[1][2]=0.2;  
  62.     nam.A[2][0]=0.2;nam.A[2][1]=0.3;nam.A[2][2]=0.5;  
  63.       
  64.     nam.B[0][0]=0.5;nam.B[0][1]=0.5;  
  65.     nam.B[1][0]=0.4;nam.B[1][1]=0.6;  
  66.     nam.B[2][0]=0.7;nam.B[2][1]=0.3;  
  67.       
  68.     int pObs[3]={0,1,0};  
  69.   
  70.     cout<<HMMQX(nam,pObs,3);  
  71.     getchar();  
  72.     return 0;  
  73.   
  74.   
  75.   
  76. }  
  77.   
  78. //pObs存储的是时间为t时候的观测值  
  79. double HMMQX(Namuna &namuna_Input,int *pObs,int nLenofObsSeq)  
  80. {  
  81.   
  82.     int StateNum=namuna_Input.NumofState;  
  83.       
  84.     double **Alpha=(double **)new int[nLenofObsSeq];  
  85.     for (int t=0;t<nLenofObsSeq;t++)  
  86.     {  
  87.         Alpha[t]=new double[StateNum];  
  88.     }  
  89.     for (int i=0;i<StateNum;i++)  
  90.     {  
  91.         Alpha[0][i]=namuna_Input.pi[i]*namuna_Input.B[i][pObs[0]];  
  92.     }  
  93.       
  94.     for (int t=1;t<nLenofObsSeq;t++)  
  95.     {     
  96.         for (int i=0;i<StateNum;i++)  
  97.         {  
  98.   
  99.             double tempSum=0.0;  
  100.             for (int j=0;j<StateNum;j++)  
  101.             {  
  102.                 tempSum+=Alpha[t-1][j]*namuna_Input.A[j][i];  
  103.             }  
  104.   
  105.             Alpha[t][i]=tempSum*namuna_Input.B[i][pObs[t]];  
  106.         }  
  107.     }  
  108.     double dRes=0.0;  
  109.     for (int i=0;i<StateNum;i++)  
  110.     {  
  111.         dRes+=Alpha[nLenofObsSeq-1][i];  
  112.     }  
  113.     return dRes;  
  114. }  

3)后向算法


第二个问题:(学习问题)

1)监督学习算法

2)非监督学习算法  Baum-Welch算法,EM在HMM中的具体实现


第三个问题:(解码问题)

1)近似算法

2)维特比算法(这是很厉害的一个算法)

具体的以后再补充。(未完待续)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值