1. 維特比算法概述
維特比算法是一個通用的解碼算法,是基於動態規划的求序列最短路徑的方法。
第一個局部狀態是在時刻$t$隱藏狀態為$i$所有可能的狀態轉移路徑$i_1,i_2,...i_t$中的概率最大值。記為 $\delta_t(i)$:$$\delta_t(i) = \max_{i_1,i_2,...i_{t-1}}\;P(i_t=i, i_1,i_2,...i_{t-1},o_t,o_{t-1},...o_1|\lambda),\; i =1,2,...N$$
由$\delta_t(i)$的定義可以得到$\delta$的遞推表達式:$$\begin{align} \delta_{t+1}(i) & = \max_{i_1,i_2,...i_{t}}\;P(i_{t+1}=i, i_1,i_2,...i_{t},o_{t+1},o_{t},...o_1|\lambda) \\ & = \max_{1 \leq j \leq N}\;[\delta_t(j)a_{ji}]b_i(o_{t+1})\end{align}$$
第二個局部狀態由第一個局部狀態遞推得到。我們定義在時刻$t$隱藏狀態為$i$的所有單個狀態轉移路徑$(i_1,i_2,...,i_{t-1},i)$中概率最大的轉移路徑中第$t-1$個節點的隱藏狀態為$\Psi_t(i)$,其遞推表達式可以表示為:$$\Psi_t(i) = arg \; \max_{1 \leq j \leq N}\;[\delta_{t-1}(j)a_{ji}]$$
有了這兩個局部狀態,我們就可以從時刻0一直遞推到時刻$T$,然后利用$\Psi_t(i)$記錄的前一個最可能的狀態節點回溯,直到找到最優的隱藏狀態序列。
2. 維特比算法流程總結
現在我們來總結下維特比算法的流程:
輸入:HMM模型$\lambda = (A, B, \Pi)$,觀測序列$O=(o_1,o_2,...o_T)$
輸出:最有可能的隱藏狀態序列$I^*= \{i_1^*,i_2^*,...i_T^*\}$
1)初始化局部狀態:$$\delta_1(i) = \pi_ib_i(o_1),\;i=1,2...N$$$$\Psi_1(i)=0,\;i=1,2...N$$
2) 進行動態規划遞推時刻$t=2,3,...T$時刻的局部狀態:$$\delta_{t}(i) = \max_{1 \leq j \leq N}\;[\delta_{t-1}(j)a_{ji}]b_i(0_{t}),\;i=1,2...N$$$$\Psi_t(i) = arg \; \max_{1 \leq j \leq N}\;[\delta_{t-1}(j)a_{ji}],\;i=1,2...N$$
3) 計算時刻$T$最大的$\delta_{T}(i)$,即為最可能隱藏狀態序列出現的概率。計算時刻$T$最大的$\Psi_t(i)$,即為時刻$T$最可能的隱藏狀態。$$P* = \max_{1 \leq j \leq N}\delta_{T}(i)$$$$i_T^* = arg \; \max_{1 \leq j \leq N}\;[\delta_{T}(i)]$$
4) 利用局部狀態$\Psi(i)$開始回溯。對於$t=T-1,T-2,...,1$:$$i_t^* = \Psi_{t+1}(i_{t+1}^*)$$
最終得到最有可能的隱藏狀態序列$I^*= \{i_1^*,i_2^*,...i_T^*\}$
3. HMM維特比算法求解實例
下面我們仍然用隱馬爾科夫模型HMM中盒子與球的例子來看看HMM維特比算法求解。
我們的觀察集合是:$$V=\{紅,白\},M=2$$
我們的狀態集合是:$$Q =\{盒子1,盒子2,盒子3\}, N=3 $$
而觀察序列和狀態序列的長度為3.
初始狀態分布為:$$\Pi = (0.2,0.4,0.4)^T$$
狀態轉移概率分布矩陣為:
$$A = \left( \begin{array} {ccc} 0.5 & 0.2 & 0.3 \\ 0.3 & 0.5 & 0.2 \\ 0.2 & 0.3 &0.5 \end{array} \right) $$
觀測狀態概率矩陣為:
$$B = \left( \begin{array} {ccc} 0.5 & 0.5 \\ 0.4 & 0.6 \\ 0.7 & 0.3 \end{array} \right) $$
球的顏色的觀測序列:$$O=\{紅,白,紅\}$$
首先需要得到三個隱藏狀態在時刻1時對應的各自兩個局部狀態,此時觀測狀態為1:
$$\delta_1(1) = \pi_1b_1(o_1) = 0.2 \times 0.5 = 0.1$$
$$\delta_1(2) = \pi_2b_2(o_1) = 0.4 \times 0.4 = 0.16$$
$$\delta_1(3) = \pi_3b_3(o_1) = 0.4 \times 0.7 = 0.28$$
$$\Psi_1(1)=\Psi_1(2) =\Psi_1(3) =0$$
現在開始遞推三個隱藏狀態在時刻2時對應的各自兩個局部狀態,此時觀測狀態為2:
$$\delta_2(1) = \max_{1\leq j \leq 3}[\delta_1(j)a_{j1}]b_1(o_2) = \max_{1\leq j \leq 3}[0.1 \times 0.5, 0.16 \times 0.3, 0.28\times 0.2] \times 0.5 = 0.028$$
$$\Psi_2(1)=3$$
$$\delta_2(2) = \max_{1\leq j \leq 3}[\delta_1(j)a_{j2}]b_2(o_2) = \max_{1\leq j \leq 3}[0.1 \times 0.2, 0.16 \times 0.5, 0.28\times 0.3] \times 0.6 = 0.0504$$
$$\Psi_2(2)=3$$
$$\delta_2(3) = \max_{1\leq j \leq 3}[\delta_1(j)a_{j3}]b_3(o_2) = \max_{1\leq j \leq 3}[0.1 \times 0.3, 0.16 \times 0.2, 0.28\times 0.5] \times 0.3 = 0.042$$
$$\Psi_2(3)=3$$
繼續遞推三個隱藏狀態在時刻3時對應的各自兩個局部狀態,此時觀測狀態為1:
$$\delta_3(1) = \max_{1\leq j \leq 3}[\delta_2(j)a_{j1}]b_1(o_3) = \max_{1\leq j \leq 3}[0.028 \times 0.5, 0.0504 \times 0.3, 0.042\times 0.2] \times 0.5 = 0.00756$$
依最大概率計算結果: $$\Psi_3(1)=2$$
$$\delta_3(2) = \max_{1\leq j \leq 3}[\delta_2(j)a_{j2}]b_2(o_3) = \max_{1\leq j \leq 3}[0.028 \times 0.2, 0.0504\times 0.5, 0.042\times 0.3] \times 0.4 = 0.01008$$
依最大概率計算結果:$$\Psi_3(2)=2$$
$$\delta_3(3) = \max_{1\leq j \leq 3}[\delta_2(j)a_{j3}]b_3(o_3) = \max_{1\leq j \leq 3}[0.028 \times 0.3, 0.0504 \times 0.2, 0.042\times 0.5] \times 0.7 = 0.0147$$
依最大概率計算結果:$$\Psi_3(3)=3$$
此時已經到最后的時刻,我們開始准備回溯。此時最大概率為$\delta_3(3)$,從而得到$i_3^* =3$
由於$\Psi_3(3)=3$,所以$i_2^* =3$, 而又由於$\Psi_2(3)=3$,所以$i_1^* =3$。從而得到最終的最可能的隱藏狀態序列為:$(3,3,3)$
代碼實例
1 import numpy as np 2 def viterbi(trainsition_probability,emission_probability,pi,obs_seq): 3 #轉換為矩陣進行運算 4 trainsition_probability=np.array(trainsition_probability) 5 emission_probability=np.array(emission_probability) 6 pi=np.array(pi) 7 obs_seq = [0, 2, 3] 8 # 最后返回一個Row*Col的矩陣結果 9 Row = np.array(trainsition_probability).shape[0] 10 Col = len(obs_seq) 11 #定義要返回的矩陣 12 F=np.zeros((Row,Col)) 13 #初始狀態 14 F[:,0]=pi*np.transpose(emission_probability[:,obs_seq[0]]) 15 for t in range(1,Col): 16 list_max=[] 17 for n in range(Row): 18 list_x=list(np.array(F[:,t-1])*np.transpose(trainsition_probability[:,n])) 19 #獲取最大概率 20 list_p=[] 21 for i in list_x: 22 list_p.append(i*10000) 23 list_max.append(max(list_p)/10000) 24 F[:,t]=np.array(list_max)*np.transpose(emission_probability[:,obs_seq[t]]) 25 return F 26 27 if __name__=='__main__': 28 #隱藏狀態 29 invisible=['Sunny','Cloud','Rainy'] 30 #初始狀態 31 pi=[0.63,0.17,0.20] 32 #轉移矩陣 33 trainsion_probility=[[0.5,0.375,0.125],[0.25,0.125,0.625],[0.25,0.375,0.375]] 34 #發射矩陣 35 emission_probility=[[0.6,0.2,0.15,0.05],[0.25,0.25,0.25,0.25],[0.05,0.10,0.35,0.5]] 36 #最后顯示狀態 37 obs_seq=[0,2,3] 38 #最后返回一個Row*Col的矩陣結果 39 F=viterbi(trainsion_probility,emission_probility,pi,obs_seq) 40 print(F)
結果:
[[ 0.378 0.02835 0.00070875]
[ 0.0425 0.0354375 0.00265781]
[ 0.01 0.0165375 0.01107422]]
每列代表Dry,Damp,Soggy的概率,每行代表Sunny,Cloud,Rainy,所以可以看出最大概率的天氣為{Sunny,Cloud,Rainy}
