維特比演算法是一種動態規劃演算法。它用於尋找最有可能產生觀測事件序列的維特比路徑 隱含狀態序列，特別是在馬爾可夫資訊源上下文和隱馬爾可夫模型中。 術語 維特比路徑 和 維特比演算法 也被用於尋找觀察結果最有可能解釋相關的動態規劃演算法。例如在統計句法分析中動態規劃演算法可以被用於發現最可能的上下文無關的派生（解析）的字串，有時被稱為 維特比分析。 維特比演算法由安德魯維特比於 1967 年提出，用於在數字通訊鏈路中解卷積以消除噪音。 此演算法被廣泛應用於 CDMA 和 GSM 數字蜂窩網路、撥號調變解調器、衛星、深空通訊和 80211 無線網路中解卷積碼。現今也被常常用於語音識別、關鍵字識別、計算語言學和生物資訊學中。例如在語音（語音識別）中，聲音訊號做為觀察到的事件序列，而文字字串，被看作是隱含的產生聲音訊號的原因，因此可對聲音訊號應用維特比演算法尋找最有可能的文字字串。 演算法 假設給定隱式馬爾可夫模型（HMM）狀態空間 S，共有 k 個狀態，初始狀態 i 的機率為 pi_i ，從狀態 i 到狀態 j 的轉移機率為 a_ij。 令觀察到的輸出為 y_1dots y_T。 產生觀察結果的最有可能的狀態序列 x_1dotsx_T 由遞推關係給出：Xing E slide 11 begin arrayrcl V_1k mathrm Pbig y_1 k big cdot pi_k V_tk max_x in S left mathrm Pbig y_t k big cdot a_xk cdot V_t1xright end array 此處 V_tk 是前 t 個最終狀態為 k 的觀測結果最有可能對應的狀態序列的機率。 透過儲存向後指標記住在第二個等式中用到的狀態 x 可以獲得維特比路徑。宣告一個函式 mathrm Ptrkt ，它返回若 t 1 時計算 V_tk 用到的 x 值 或若 t1 時的 k 這樣 begin arrayrcl x_T argmax_x in S V_Tx x_t1 mathrm Ptrx_tt end array 這裡我們使用了的標準定義 演算法複雜度為 O TtimesleftSright2 例子 想象一個鄉村診所。村民有著非常理想化的特性，要麼健康要麼發燒。他們只有問診所的醫生的才能知道是否發燒。 聰明的醫生透過詢問病人的感覺診斷他們是否發燒。村民只回答他們感覺正常、頭暈或冷。 假設一個病人每天來到診所並告訴醫生他的感覺。醫生相信病人的健康狀況如同一個離散馬爾可夫鏈。病人的狀態有兩種 健康 和 發燒，但醫生不能直接觀察到，這意味著狀態對他是 隱含 的。每天病人會告訴醫生自己有以下幾種由他的健康狀態決定的感覺的一種：正常、冷或頭暈。這些是觀察結果。 整個系統為一個隱馬爾可夫模型 HMM。 醫生知道村民的總體健康狀況，還知道發燒和沒發燒的病人通常會抱怨什麼症狀。 換句話說，醫生知道隱馬爾可夫模型的引數。 這可以用 Python 語言表示如下 states Healthy Fever observations normal cold dizzy start_probability Healthy 06 Fever 04 transition_probability Healthy Healthy 07 Fever 03 Fever Healthy 04 Fever 06 emission_probability Healthy normal 05 cold 04 dizzy 01 Fever normal 01 cold 03 dizzy 06 在這段程式碼中，起始機率 start_probability 表示病人第一次到訪時醫生認為其所處的 HMM 狀態，他唯一知道的是病人傾向於是健康的。這裡用到的特定機率分佈不是均衡的，如轉移機率大約是 Healthy 057 Fever 043。 轉移機率 transition_probability 表示潛在的馬爾可夫鏈中健康狀態的變化。在這個例子中，當天健康的病人僅有 30 的機會第二天會發燒。放射機率 emission_probability 表示每天病人感覺的可能性。假如他是健康的，50 會感覺正常。如果他發燒了，有 60 的可能感覺到頭暈。 病人連續三天看醫生，醫生發現第一天他感覺正常，第二天感覺冷，第三天感覺頭暈。 於是醫生產生了一個問題：怎樣的健康狀態序列最能夠解釋這些觀察結果。維特比演算法解答了這個問題。 def viterbi obs states start_p trans_p emit_p V path Initialize for st in states V 0st start_p st emit_p stobs 0 path st st Run Viterbi when t 0 for t in range 1len obs Vappend newpath for curr_st in states paths_to_curr_st for prev_st in states paths_to_curr_stappend V t1prev_st trans_p prev_stcurr_st emit_p curr_stobs t prev_st curr_prob prev_state max paths_to_curr_st V tcurr_st curr_prob newpath curr_st path prev_state curr_st No need to keep the old paths path newpath for line in dptable V print line prob end_state max V 1st st for st in states return prob path end_state def dptable V Print a table of steps from dictionary yield 4 join states for t in range len V yield format t join 4fformat V tstate for state in V 0 函式 viterbi 具有以下引數 obs 為觀察結果序列，例如 normal cold dizzy； states 為一組隱含狀態； start_p 為起始狀態機率；trans_p 為轉移機率；而 emit_p 為放射機率。 為了簡化程式碼，我們假設觀察序列 obs 非空且 trans_p ij 和 emit_p ij 對所有狀態 ij 有定義。 在執行的例子中正向 維特比演算法使用如下 def example return viterbi observations states start_probability transition_probability emission_probability print example 維特比演算法揭示了觀察結果 normal cold dizzy 最有可能由狀態序列 Healthy Healthy Fever 產生。 換句話說，對於觀察到的活動，病人第一天感到正常，第二天感到冷時都是健康的，而第三天發燒了。 維特比演算法的計算過程可以直觀地由格圖表示。 維特比路徑本質上是穿過格式結構的最長路徑。 診所例子的格式結構如下，黑色加粗的是維特比路徑： 在實現維特比演算法時需注意許多程式語言使用浮點數計算，當 p 很小時可能會導致結果算術下溢。 避免這一問題的常用技巧是在整個計算過程中使用對數機率，在對數系統中也使用了同樣的技巧。 當演算法結束時，可以透過適當的冪運算獲得精確結果。 虛擬碼 首先是一些問題必要的設定。 設觀察值空間為 Oo_1o_2dotso_N、 狀態空間為 Ss_1s_2dotss_K 、 觀察值序列為 Yy_1y_2ldots y_T A 為 Ktimes K 轉移矩陣，其中 A_ij 為從狀態 s_i 轉移到 s_j 的轉移機率、 B 為 Ktimes N 放射矩陣 emission matrix，其中 B_ij 為在狀態 s_i 觀察到 o_j 的機率、 大小為 K 的初始機率陣列 pi ， pi_i 為 x_1 s_i 的機率。 我們稱路徑 Xx_1x_2ldotsx_T 為生成觀察值 Yy_1y_2ldots y_T 的狀態序列。 在這個動態規劃問題中，我們構造了兩個大小為 Ktimes T 的二維表 T_1 T_2 。 T_1 的每個元素，T_1 ij ，儲存生成 Yy_1y_2ldots y_j 時最有可能的路徑 hat Xhat x_1hat x_2ldotshat x_j ， hat x_js_i 的機率。 T_2 的每個元素，T_2 ij ，儲存最有可能路徑 hat Xhat x_1hat x_2ldotshat x_j1hat x_j forall j 2leq j leq T 的 hat x_j1 。 我們按 Kcdot ji 增序填充兩個表 T_1 ijT_2 ij。 T_1 ijmax_kT_1 kj1cdot A_kicdot B_iy_j T_2 ijargmax_kT_1 kj1cdot A_kicdot B_iy_j 輸入 觀察空間 Oo_1o_2dotso_N， 狀態 Ss_1s_2dotss_K ， 觀察序列 Yy_1y_2ldots y_T 若在 t 時間觀察值為 o_i ，則 y_ti 大小為 Kcdot K 的轉移矩陣 A ， A_ij 為從狀態 s_i 到 s_j 的轉移機率， 大小為 Kcdot N 的放射矩陣 B ， B_ij 為狀態 s_i 觀察到 o_j 的機率， 大小為 K 的初始機率陣列 pi ， pi_i 為 x_1 s_i 的機率， 輸出 最有可能的隱含狀態序列 Xx_1x_2ldotsx_T function VITERBI for each state do end for for do for each state do end for end for for do end for return end function 使用動態規劃的演算法 最長公共子序列 FloydWarshall 演算法 註釋 參考資料 note the Viterbi decoding algorithm is described in section IV Subscription required Category 最最佳化演算法 Category 動態規劃 Category 錯誤檢測與校正 Category 馬爾可夫模型