隱馬爾可夫模型(三)——隱馬爾可夫模型的評估問題(前向算法)


      隱馬模型的評估問題即,在已知一個觀察序列O=O1O2...OT,和模型μ=(A,B,π}的條件下,觀察序列O的概率,即P(O|μ}

                  

      如果窮盡所有的狀態組合,即S1S1...S1, S1S1...S2, S1S1...S3, ..., S3S3...S3。這樣的話t1時刻有N個狀態,t2時刻有N個狀態...tT時刻有N個狀態,這樣的話一共有N*N*...*N= NT種組合,時間復雜度為O(NT),計算時,就會出現“指數爆炸”,當T很大時,簡直無法計算這個值。為解決這一問題,Baum提出了前向算法。

      歸納過程

      首先引入前向變量αt(i):在時間t時刻,HMM輸出序列為O1O2...OT,在第t時刻位於狀態si的概率。

      當T=1時,輸出序列為O1,此時計算概率為P(O1|μ):假設有三個狀態(如下圖)1、2、3,輸出序列為O1,有三種可能一是狀態1發出,二是從狀態2發出,三是從狀態3發出。另外從狀態1發出觀察值O1得概率為b1(O1),從狀態2發出觀察值O1得概率為b2(O1),從狀態3發出觀察值O1得概率為b3(O1)。因此可以算出

     P(O1|μ)= π1*b1(O1)+π2*b2(O1) +  π3*b3(O1)= α1(1) + α1(2) + α1(3)

                                    

      當T=2時,輸出序列為O1O2,此時計算概率為P(O1O2|μ):假設有三個狀態(如下圖)1、2、3,輸出序列為O1,有三種可能一是狀態1發出,二是從狀態2發出,三是從狀態3發出。另外從狀態1發出觀察值O2得概率為b1(O2),從狀態2發出觀察值O2得概率為b2(O2),從狀態3發出觀察值O2得概率為b3(O2)。

      要是從狀態1發出觀察值O2,可能從第一時刻的1、2或3狀態裝換過來,要是從狀態1轉換過來,概率為α1(1)*a11*b1(O2),要是從狀態2轉換過來,概率為α1(2)*a21*b1(O2),要是從狀態3轉換過來,概率為α1(3)*a31*b1(O2),因此

     P(O1O2,q2=s1|μ)= α1(1)*a11*b1(O2)  + α1(2)*a21*b1(O2) + α1(3)*a31*b1(O2)=α2(1)

                                    

      同理:P(O1O2,q2=s1|μ)= α1(1)*a12*b2(O2)  + α1(2)*a22*b2(O2) + α1(3)*a32*b2(O2)=α2(2)

               P(O1O2,q2=s1|μ)= α1(1)*a13*b1(O2)  + α1(2)*a23*b3(O2) + α1(3)*a33*b3(O2)=α2(3)

     所以:P(O1O2|μ)=P(O1O2,q2=s1|μ)+ P(O1O2,q2=s1|μ)+ P(O1O2,q2=s1|μ)

                             =α2(1) + α2(2) + α2(3)

      以此類推。。。

      前向算法

       step1 初始化:α1(i) = πi*bi(O1), 1≤i≤N

       step2 歸納計算:

                          

       step3 終結:

                      P(O|μ)=

      時間復雜度

      計算某時刻的某個狀態的前向變量需要看前一時刻的N個狀態,此時時間復雜度為O(N),每個時刻有N個狀態,此時時間復雜度為N*O(N)=O(N2),又有T個時刻,所以時間復雜度為T*O(N2)=O(N2T)。

      程序例證

      

        前向算法計算P(O|M):

        step1:α1(1) =π1*b1(red)=0.2*0.5=0.1          α1(2)=π2*b2(red)==0.4*0.4= 0.16          α1(3)=π3*b3(red)==0.4*0.7=0.21

        step2:α2(1)=α1(1)*a11*b1(white) + α1(2)*a21*b1(white) + α1(3)*a31*b1(white)

                     ...

        step3:P(O|M) = α3(1)+α3(2)+α3(3)

        程序代碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
        float a[3][3] = {{0.5,0.2,0.3},{0.3,0.5,0.2},{0.2,0.3,0.5}};
        float b[3][2] = {{0.5,0.5},{0.4,0.6},{0.7,0.3}};
        float alpha[4][3];
        int i,j,k, count = 1;
        //output list
        int list[4] = {0,1,0,1};
        //step1:Initialization
        alpha[0][0] = 0.2 * 0.5;
        alpha[0][1] = 0.4 * 0.4;
        alpha[0][2] = 0.4 * 0.7;
        //step2:iteration
        for (i=1; i<=3; i++)
        {
            for(j=0; j<=2; j++)
            {
                alpha[i][j] = 0;
                for(k=0; k<=2; k++)
                {
                   alpha[i][j] += alpha[i-1][k] * a[k][j] * b[j][list[count]];
                }
            }
            count += 1;
        }
       for (i=0; i<=3; i++)
        {
            for(j=0; j<=2; j++)
            {
                printf("a[%d][%d]=%f\n",i+1,j+1,alpha[i][j]);
            }
        }
       //step3:end
       printf("Forward:%f\n", alpha[3][0]+alpha[3][1]+alpha[3][2]);
       return 0;
}

     運行結果

                

 

       

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM