HMM學習最佳範例:維特比算法(Viterbi Algorithm)

六、維特比算法(Viterbi Algorithm)

尋找最可能的隱藏狀態序列(Finding most probable sequence of hidden states)


  對於一個特殊的隱馬爾科夫模型(HMM)及一個相應的觀察序列,我們常常希望能找到生成此序列最可能的隱藏狀態序列。

1.窮舉搜索
  我們使用下面這張網格圖片來形象化的說明隱藏狀態和觀察狀態之間的關係:
網格
  我們可以通過列出所有可能的隱藏狀態序列並且計算對於每個組合相應的觀察序列的概率來找到最可能的隱藏狀態序列。最可能的隱藏狀態序列是使下面這個概率最大的組合:
      Pr(觀察序列|隱藏狀態的組合)
  例如,對於網格中所顯示的觀察序列,最可能的隱藏狀態序列是下面這些概率中最大概率所對應的那個隱藏狀態序列:
  Pr(dry,damp,soggy | sunny,sunny,sunny), Pr(dry,damp,soggy | sunny,sunny,cloudy), Pr(dry,damp,soggy | sunny,sunny,rainy), . . . . Pr(dry,damp,soggy | rainy,rainy,rainy)
  這種方法是可行的,但是通過窮舉計算每一個組合的概率找到最可能的序列是極爲昂貴的。與前向算法類似,我們可以利用這些概率的時間不變性來降低計算複雜度。

2.使用遞歸降低複雜度
  給定一個觀察序列和一個隱馬爾科夫模型(HMM),我們將考慮遞歸地尋找最有可能的隱藏狀態序列。我們首先定義局部概率delta,它是到達網格中的某個特殊的中間狀態時的概率。然後,我們將介紹如何在t=1和t=n(>1)時計算這些局部概率。
  這些局部概率與前向算法中所計算的局部概率是不同的,因爲它們表示的是時刻t時到達某個狀態最可能的路徑的概率,而不是所有路徑概率的總和。
 2a.局部概率delta's和局部最佳途徑
  考慮下面這個網格,它顯示的是天氣狀態及對於觀察序列乾燥,溼潤及溼透的一階狀態轉移情況:
   trellis.1
  對於網格中的每一箇中間及終止狀態,都有一個到達該狀態的最可能路徑。舉例來說,在t=3時刻的3個狀態中的每一個都有一個到達此狀態的最可能路徑,或許是這樣的:
  paths.for.t_3
  我們稱這些路徑局部最佳路徑(partial best paths)。其中每個局部最佳路徑都有一個相關聯的概率,即局部概率或delta。與前向算法中的局部概率不同,delta是到達該狀態(最可能)的一條路徑的概率。
  因而delta(i,t)是t時刻到達狀態i的所有序列概率中最大的概率,而局部最佳路徑是得到此最大概率的隱藏狀態序列。對於每一個可能的i和t值來說,這一類概率(及局部路徑)均存在。
  特別地,在t=T時每一個狀態都有一個局部概率和一個局部最佳路徑。這樣我們就可以通過選擇此時刻包含最大局部概率的狀態及其相應的局部最佳路徑來確定全局最佳路徑(最佳隱藏狀態序列)。

2b.計算t=1時刻的局部概率delta's
  我們計算的局部概率delta是作爲最可能到達我們當前位置的路徑的概率(已知的特殊知識如觀察概率及前一個狀態的概率)。當t=1的時候,到達某狀態的最可能路徑明顯是不存在的;但是,我們使用t=1時的所處狀態的初始概率及相應的觀察狀態k1的觀察概率計算局部概率delta;即
          6.1.2.2_a
  ——與前向算法類似,這個結果是通過初始概率和相應的觀察概率相乘得出的。

2c.計算t>1時刻的局部概率delta's
  現在我們來展示如何利用t-1時刻的局部概率delta計算t時刻的局部概率delta
  考慮如下的網格:
    abcxtrellis
  我們考慮計算t時刻到達狀態X的最可能的路徑;這條到達狀態X的路徑將通過t-1時刻的狀態A,B或C中的某一個。
  因此,最可能的到達狀態X的路徑將是下面這些路徑的某一個
       (狀態序列),...,A,X
       (狀態序列),...,B,X
或      (狀態序列),...,C,X
  我們想找到路徑末端是AX,BX或CX並且擁有最大概率的路徑。
  回顧一下馬爾科夫假設:給定一個狀態序列,一個狀態發生的概率只依賴於前n個狀態。特別地,在一階馬爾可夫假設下,狀態X在一個狀態序列後發生的概率只取決於之前的一個狀態,即
   Pr (到達狀態A最可能的路徑) .Pr (X | A) . Pr (觀察狀態 | X)
  與此相同,路徑末端是AX的最可能的路徑將是到達A的最可能路徑再緊跟X。相似地,這條路徑的概率將是:
   Pr (到達狀態A最可能的路徑) .Pr (X | A) . Pr (觀察狀態 | X)
  因此,到達狀態X的最可能路徑概率是:
  6.1.2.3_a
  其中第一項是t-1時刻的局部概率delta,第二項是狀態轉移概率以及第三項是觀察概率。
  泛化上述公式,就是在t時刻,觀察狀態是kt,到達隱藏狀態i的最佳局部路徑的概率是:
     6.1.2.3_b
  這裏,我們假設前一個狀態的知識(局部概率)是已知的,同時利用了狀態轉移概率和相應的觀察概率之積。然後,我們就可以在其中選擇最大的概率了(局部概率delta)。

2d.反向指針,phi's
  考慮下面這個網格
   trellis.1
  在每一箇中間及終止狀態我們都知道了局部概率,delta(i,t)。然而我們的目標是在給定一個觀察序列的情況下尋找網格中最可能的隱藏狀態序列——因此,我們需要一些方法來記住網格中的局部最佳路徑。
  回顧一下我們是如何計算局部概率的,計算t時刻的delta's我們僅僅需要知道t-1時刻的delta's。在這個局部概率計算之後,就有可能記錄前一時刻哪個狀態生成了delta(i,t)——也就是說,在t-1時刻系統必須處於某個狀態,該狀態導致了系統在t時刻到達狀態i是最優的。這種記錄(記憶)是通過對每一個狀態賦予一個反向指針phi完成的,這個指針指向最優的引發當前狀態的前一時刻的某個狀態。
  形式上,我們可以寫成如下的公式
    6.1.2.4_a
  其中argmax運算符是用來計算使括號中表達式的值最大的索引j的。
  請注意這個表達式是通過前一個時間步驟的局部概率delta's和轉移概率計算的,並不包括觀察概率(與計算局部概率delta's本身不同)。這是因爲我們希望這些phi's能回答這個問題“如果我在這裏,最可能通過哪條路徑到達下一個狀態?”——這個問題與隱藏狀態有關,因此與觀察概率有關的混淆(矩陣)因子是可以被忽略的。

2e.維特比算法的優點
  使用Viterbi算法對觀察序列進行解碼有兩個重要的優點:
  1. 通過使用遞歸減少計算複雜度——這一點和前向算法使用遞歸減少計算複雜度是完全類似的。
  2.維特比算法有一個非常有用的性質,就是對於觀察序列的整個上下文進行了最好的解釋(考慮)。事實上,尋找最可能的隱藏狀態序列不止這一種方法,其他替代方法也可以,譬如,可以這樣確定如下的隱藏狀態序列:
    6.1.2.5_a
其中
    6.1.2.5_b
  這裏,採用了“自左向右”的決策方式進行一種近似的判斷,其對於每個隱藏狀態的判斷是建立在前一個步驟的判斷的基礎之上(而第一步從隱藏狀態的初始向量pi開始)。
  這種做法,如果在整個觀察序列的中部發生“噪音干擾”時,其最終的結果將與正確的答案嚴重偏離。
  相反, 維特比算法在確定最可能的終止狀態前將考慮整個觀察序列,然後通過phi指針“回溯”以確定某個隱藏狀態是否是最可能的隱藏狀態序列中的一員。這是非常有用的,因爲這樣就可以孤立序列中的“噪音”,而這些“噪音”在實時數據中是很常見的。

3.小結
  維特比算法提供了一種有效的計算方法來分析隱馬爾科夫模型的觀察序列,並捕獲最可能的隱藏狀態序列。它利用遞歸減少計算量,並使用整個序列的上下文來做判斷,從而對包含“噪音”的序列也能進行良好的分析。
  在使用時,維特比算法對於網格中的每一個單元(cell)都計算一個局部概率,同時包括一個反向指針用來指示最可能的到達該單元的路徑。當完成整個計算過程後,首先在終止時刻找到最可能的狀態,然後通過反向指針回溯到t=1時刻,這樣回溯路徑上的狀態序列就是最可能的隱藏狀態序列了。

維特比算法定義(Viterbi algorithm definition)


1、維特比算法的形式化定義
  維特比算法可以形式化的概括爲:
  對於每一個i,i = 1,... ,n,令:
     6.2.1_a
  ——這一步是通過隱藏狀態的初始概率和相應的觀察概率之積計算了t=1時刻的局部概率。
  對於t=2,...,T和i=1,...,n,令:
     6.2.1_b
  ——這樣就確定了到達下一個狀態的最可能路徑,並對如何到達下一個狀態做了記錄。具體來說首先通過考察所有的轉移概率與上一步獲得的最大的局部概率之積,然後記錄下其中最大的一個,同時也包含了上一步觸發此概率的狀態。
  令:
     6.2.1_c
  ——這樣就確定了系統完成時(t=T)最可能的隱藏狀態。
  對於t=T-1,...,1
  令:
     6.2.1_d
  ——這樣就可以按最可能的狀態路徑在整個網格回溯。回溯完成時,對於觀察序列來說,序列i1 ... iT就是生成此觀察序列的最可能的隱藏狀態序列。

  2.計算單獨的delta's和phi's
  維特比算法中的局部概率delta's的計算與前向算法中的局部概率alpha's的很相似。下面這幅圖表顯示了delta's和phi's的計算細節,可以對比一下前向算法3中的計算局部概率alpha's的那幅圖表:
  example.viterbi
(注:本圖及前向算法3中的相似圖存在問題,具體請見前向算法3文後評論,非常感謝讀者YaseenTA的指正)
  唯一不同的是前向算法中計算局部概率alpha's時的求和符號(Sigma)在維特比算法中計算局部概率delta's時被替換爲max——這一個重要的不同也說明了在維特比算法中我們選擇的是到達當前狀態的最可能路徑,而不是總的概率。我們在維特比算法中維護了一個“反向指針”記錄了到達當前狀態的最佳路徑,即在計算phi's時通過argmax運算符獲得。

總結(Summary)

  對於一個特定的隱馬爾科夫模型,維特比算法被用來尋找生成一個觀察序列的最可能的隱藏狀態序列。我們利用概率的時間不變性,通過避免計算網格中每一條路徑的概率來降低問題的複雜度。維特比算法對於每一個狀態(t>1)都保存了一個反向指針(phi),並在每一個狀態中存儲了一個局部概率(delta)。
  局部概率delta是由反向指針指示的路徑到達某個狀態的概率。
  當t=T時,維特比算法所到達的這些終止狀態的局部概率delta's是按照最優(最可能)的路徑到達該狀態的概率。因此,選擇其中最大的一個,並回溯找出所隱藏的狀態路徑,就是這個問題的最好答案。
  關於維特比算法,需要着重強調的一點是它不是簡單的對於某個給定的時間點選擇最可能的隱藏狀態,而是基於全局序列做決策——因此,如果在觀察序列中有一個“非尋常”的事件發生,對於維特比算法的結果也影響不大。
  這在語音處理中是特別有價值的,譬如當某個單詞發音的一箇中間音素出現失真或丟失的情況時,該單詞也可以被識別出來。

仍然需要說明的是,本節不是這個系列的翻譯,而是作爲維特比算法這一章的補充,將UMDHMM這個C語言版本的HMM工具包中的維特比算法程序展示給大家,並運行包中所附帶的例子。關於UMDHMM這個工具包的介紹,大家可以參考前向算法4中的介紹。

維特比算法程序示例如下(在viterbi.c中):
void Viterbi(HMM *phmm, int T, int *O, double **delta, int **psi,int *q, double *pprob)
{
  int i, j; /* state indices */
  int t; /* time index */

  int maxvalind;
  double maxval, val;

  /* 1. Initialization */

  for (i = 1; i <= phmm->N; i++)
  {
    delta[1][i] = phmm->pi[i] * (phmm->B[i][O[1]]);
    psi[1][i] = 0;
  }

  /* 2. Recursion */
  for (t = 2; t <= T; t++)   {     for (j = 1; j <= phmm->N; j++)
    {
      maxval = 0.0;
      maxvalind = 1;
      for (i = 1; i <= phmm->N; i++)
      {
        val = delta[t-1][i]*(phmm->A[i][j]);
        if (val > maxval)
        {
          maxval = val;
          maxvalind = i;
        }
      }

      delta[t][j] = maxval*(phmm->B[j][O[t]]);
      psi[t][j] = maxvalind;

    }
  }

  /* 3. Termination */

  *pprob = 0.0;
  q[T] = 1;
  for (i = 1; i <= phmm->N; i++)
  {
    if (delta[T][i] > *pprob)
    {
      *pprob = delta[T][i];
      q[T] = i;
    }
  }

  /* 4. Path (state sequence) backtracking */

  for (t = T - 1; t >= 1; t--)
    q[t] = psi[t+1][q[t+1]];

}

  在UMDHMM包中所生成的4個可執行程序中,testvit是用來測試維特比算法的, 對於給定的觀察符號序列及HMM,利用Viterbi 算法生成最可能的隱藏狀態序列。這裏我們利用UMDHMM包中test.hmm和test.seq來測試維特比算法,關於這兩個文件,具體如下:
  test.hmm:
--------------------------------------------------------------------
    M= 2
    N= 3
    A:
    0.333 0.333 0.333
    0.333 0.333 0.333
    0.333 0.333 0.333
    B:
    0.5 0.5
    0.75 0.25
    0.25 0.75
    pi:
    0.333 0.333 0.333
--------------------------------------------------------------------

  test.seq:
--------------------------------------------------------------------
    T= 10
    1 1 1 1 2 1 2 2 2 2
--------------------------------------------------------------------

  對於維特比算法的測試程序testvit來說,運行:
   testvit test.hmm test.seq
  結果如下:
  ------------------------------------
  Viterbi using direct probabilities
  Viterbi MLE log prob = -1.387295E+01
  Optimal state sequence:
  T= 10
  2 2 2 2 3 2 3 3 3 3
  ------------------------------------
  Viterbi using log probabilities
  Viterbi MLE log prob = -1.387295E+01
  Optimal state sequence:
  T= 10
  2 2 2 2 3 2 3 3 3 3
  ------------------------------------
  The two log probabilites and optimal state sequences
  should identical (within numerical precision).

  序列“2 2 2 2 3 2 3 3 3 3”就是最終所找到的隱藏狀態序列。好了,維特比算法這一章就到此爲止了。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章