隱馬爾可夫模型(五)——隱馬爾可夫模型的解碼問題(維特比算法)


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 回溯:從最后一個狀態往回返

程序代碼

 

#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 result[4][3];
        int list[4] = {0,1,0,1};
        int max[4][3];
        float tmp;
        //step1:Initialization
        result[0][0] = 0.2*0.5;
        result[0][1] = 0.4*0.4;
        result[0][2] = 0.4*0.7;
        
        int i,j,k, count = 1, max_node;
        float max_v;
        //step2:歸納運算
        for (i=1; i<=3; i++)
        {
            for(j=0; j<=2; j++)
            {
                tmp = result[i-1][0] * a[0][j] * b[j][list[count]];
                max[i][j] = 0;
                for(k=1; k<=2; k++)
                {
                    if(result[i-1][k] * a[k][j] * b[j][list[count]] > tmp)
                    {
                        tmp = result[i-1][k] * a[k][j]* b[j][list[count]];
                        max[i][j] = k;
                    }
                   result[i][j] = tmp;
                }
                max_v = result[3][0];
                max_node = 0;
                for (k=1; k<=2; k++)
                {
                    if(result[3][k] > max_v)
                    {
                        max_v = result[3][k];
                        max_node = k;
                    }
                }
            }
            count += 1;
        }
        //step3:終結
       for (i=0; i<=3; i++)
        {
            for(j=0; j<=2; j++)
            {
                printf("%d %d     %f\n",i+1,j+1,result[i][j]);

            }
        }
        printf("Pmax=%f\n", max_v);
        printf("step4:%d   \n", max_node+1);
        //step4:回溯
        for(k=3; k>=1; k--)
        {
            printf("step%d:%d  \n",k, max[k][max_node]+1);
            max_node = max[k][max_node];
        }
        return 0;
    }

 

運行結果

        

最終的序列是3 2 2 2


免責聲明!

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



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