1. 程式人生 > >維特比算法

維特比算法

觀察 spa health 五個 normal 現在 .com 長度 ID

維特比算法(Viterbi algorithm)是在一個用途非常廣的算法,本科學通信的時候已經聽過這個算法,最近在看 HMM(Hidden Markov model) 的時候也看到了這個算法。於是決定研究一下這個算法的原理及其具體實現,如果了解動態規劃的同學應該很容易了解維特比算法,因為維特比算法的核心就是動態規劃。

對於 HMM 而言,其中一個重要的任務就是要找出最有可能產生其觀測序列的隱含序列。一般來說,HMM問題可由下面五個元素描述:

  1. 觀測序列(observations):實際觀測到的現象序列
  2. 隱含狀態(states):所有的可能的隱含狀態
  3. 初始概率(start_probability):每個隱含狀態的初始概率
  4. 轉移概率(transition_probability):從一個隱含狀態轉移到另一個隱含狀態的概率
  5. 發射概率(emission_probability):某種隱含狀態產生某種觀測現象的概率

下面以維基百科上的具體例子來說明:

想象一個鄉村診所。村民有著非常理想化的特性,要麽健康要麽發燒。他們只有問診所的醫生的才能知道是否發燒。 聰明的醫生通過詢問病人的感覺診斷他們是否發燒。村民只回答他們感覺正常、頭暈或冷。
假設一個病人每天來到診所並告訴醫生他的感覺。醫生相信病人的健康狀況如同一個離散馬爾可夫鏈。病人的狀態有兩種“健康”和“發燒”,但醫生不能直接觀察到,這意味著狀態對他是“隱含”的。每天病人會告訴醫生自己有以下幾種由他的健康狀態決定的感覺的一種:正常、冷或頭暈。這些是觀察結果。 整個系統為一個隱馬爾可夫模型(HMM)。
醫生知道村民的總體健康狀況,還知道發燒和沒發燒的病人通常會抱怨什麽癥狀。 換句話說,醫生知道隱馬爾可夫模型的參數。則這些上面提到的五個元素表示如下:

states = (Healthy, Fever)
 
observations = (normal, cold, dizzy)
 
start_probability = {Healthy: 0.6, Fever: 0.4}
 
transition_probability = {
   Healthy : {Healthy: 0.7, Fever: 0.3},
   Fever : {Healthy: 0.4, Fever: 0.6},
   }
 
emission_probability = {
   Healthy : {normal
: 0.5, cold: 0.4, dizzy: 0.1}, Fever : {normal: 0.1, cold: 0.3, dizzy: 0.6}, }

其對應的狀態轉移圖如下所示:

技術分享圖片

現在的問題是假設病人連續三天看醫生,醫生發現第一天他感覺正常,第二天感覺冷,第三天感覺頭暈。 於是醫生產生了一個問題:怎樣的健康狀態序列最能夠解釋這些觀察結果。維特比算法解答了這個問題。

首先直觀地看這個問題,在HMM中,一個觀測現象後面的對應的各個狀態都有一個概率值,我們只需要選擇概率值最大的那個狀態即可,但是這個概率值是跟前面一個狀態有關的(馬爾科夫假設),因此不能獨立考慮每個觀測現象。

為了從時間復雜度方面進行比較,現在將問題一般化:假設觀測序列的長度為 m,隱含狀態個數為 n。則有下面的隱含狀態轉移圖(下圖為了便於表示,將只畫出n = 3 的圖)。

技術分享圖片

假如采用窮舉法,窮舉出所有可能的狀態序列再比較他們的概率值,則時間復雜度是$O(n^m)$, 顯然這樣的時間復雜度是無法接受的,而通過維特比算法能把時間復雜度降到$O(m*n^2)$。

從動態規劃的問題去考慮這個問題,根據上圖的定義,記last_state為上一個觀測現象對應的各個隱含狀態的概率,curr_state為現在的觀測現象對應的各個隱含狀態的概率。則求解curr_state實際上只依賴於last_state。而他們的依賴關系可通過下面的python代碼表示出來:

for cs in states:
    curr_state[cs] = max(last_state[ls] * 
                         transition_probability[ls][cs] *             
                         emission_probability[cs][observation] 
                         for ls in states)

計算過程利用了轉移概率transition_probability和發射概率emission_probability,選出那個最有可能產生當前狀態cs的上一狀態ls

除了上面的計算,同時要為每個隱含狀態維護一個路徑pathpath[s]表示到達狀態s前的最優狀態序列。通過前面的計算選出那個最有可能產生當前狀態cs的上一狀態ls後,往path[cs]中插入ls。則依照這種方法遍歷完所有的觀測序列後,只需要選擇curr_state中概率值最大的那個state作為最終的隱含狀態,同時從path中取出path[state]作為該最終隱含狀態前面的狀態序列。

從上面的分析可知,觀測序列只需要遍歷一遍,時間復雜度為$O(m)$,而每次要計算當前各個狀態最可能的前一狀態,時間復雜度為$O(n^2)$,因此總體的時間復雜度為$O(m*n^2)$.

假如在NLP中應用HMM,則將詞序列看做是觀測到的現象,而詞性、標簽等信息看做是隱含狀態,那麽就可以通過維特比算法求解其隱含狀態序列,而這也是HMM在分詞,詞性標註,命名實體識別中的應用。其關鍵往往是找出上面提到的初始概率(start_probability)、轉移概率(transition_probability)、發射概率(emission_probability)。

而在通信領域中,假如將收到的編碼信息看作是觀測序列,對應的解碼信息為隱含狀態,那麽通過維特比算法也能夠找出概率最大的解碼信息。

需要註意的是維特比算法適用於多步驟多選擇的最優問題,類似於下面的網絡,《數學之美》中將其叫做“籬笆網絡(Lattice)”。每一步都有多個選擇,並且保留了前面一步各個選擇的最優解,通過回溯的方法找到最優選擇路徑。

技術分享圖片

這裏要強調的是viterbi算法可以用於解決HMM問題,但是也可以用於解決其他符合上面描述的問題。

轉自博文:http://wulc.me/2017/03/02/維特比算法/

維特比算法