先來解釋一下HMM的向前算法:
前向后向算法是前向算法和后向算法的統稱,這兩個算法都可以用來求HMM觀測序列的概率。我們先來看看前向算法是如何求解這個問題的。
前向算法本質上屬於動態規划的算法,也就是我們要通過找到局部狀態遞推的公式,這樣一步步的從子問題的最優解拓展到整個問題的最優解。在這里我們認為隨機過程中各個狀態St的概率分布,只與它的前一個狀態St-1有關,同時任何時刻的觀察狀態只僅僅依賴於當前時刻的隱藏狀態。
在t時刻我們定義觀察狀態的概率為:
αt(i)=P(o1,o2,...ot,it=qi|λ)
從下圖可以看出,我們可以基於時刻t時各個隱藏狀態的前向概率,再乘以對應的狀態轉移概率,即αt(j)aji就是在時刻t觀測到o1,o2,...ot,即時刻t隱藏狀態qj,qj總和再乘以該時刻的發射概率得到時刻t+1隱藏狀態qi的概率。
下面總結下前向算法。
輸入:HMM模型λ=(A,B,Π)λ=(A,B,Π),觀測序列O=(o1,o2,...oT)
輸出:觀測序列概率P(O|λ)
1) 計算時刻1的各個隱藏狀態前向概率:
2) 遞推時刻2,3,...T時刻的前向概率:

3) 計算最終結果:

從遞推公式可以看出,我們的算法時間復雜度是O(TN2),比暴力解法的時間復雜度O(TNT)少了幾個數量級。
實例說明:
3個盒子,每個盒子都有紅、白兩種球,具體情況如下:
盒子 1 2 3
紅球數 5 4 7
黑球數 5 6 3
按照下面的方法從盒子里抽球,開始的時候,從第一個盒子抽球的概率是0.2,從第二個盒子抽球的概率是0.4,從第三個盒子抽球的概率是0.4。以這個概率抽一次球后,將球放回。然后從當前盒子轉移到下一個盒子進行抽球。規則是:如果當前抽球的盒子是第一個盒子,則以0.5的概率仍然留在第一個盒子繼續抽球,以0.2的概率去第二個盒子抽球,以0.3的概率去第三個盒子抽球。如果當前抽球的盒子是第二個盒子,則以0.5的概率仍然留在第二個盒子繼續抽球,以0.3的概率去第一個盒子抽球,以0.2的概率去第三個盒子抽球。如果當前抽球的盒子是第三個盒子,則以0.5的概率仍然留在第三個盒子繼續抽球,以0.2的概率去第一個盒子抽球,以0.3的概率去第二個盒子抽球。如此下去,直到重復三次,得到一個球的顏色的觀測序列:

# -*- coding: UTF-8 -*-
import numpy as np def Forward(trainsition_probability,emission_probability,pi,obs_seq): """ :param trainsition_probability:trainsition_probability是狀態轉移矩陣 :param emission_probability: emission_probability是發射矩陣 :param pi: pi是初始狀態概率 :param obs_seq: obs_seq是觀察狀態序列 :return: 返回結果 """ trainsition_probability = np.array(trainsition_probability) emission_probability = np.array(emission_probability) pi = np.array(pi) Row = np.array(trainsition_probability).shape[0] F = np.zeros((Row,Col)) #最后要返回的就是F,就是我們公式中的alpha
F[:,0] = pi * np.transpose(emission_probability[:,obs_seq[0]]) #這是初始化求第一列,就是初始的概率*各自的發射概率
for t in range(1,len(obs_seq)): #這里相當於填矩陣的元素值
for n in range(Row): #n是代表隱藏狀態的
F[n,t] = np.dot(F[:,t-1],trainsition_probability[:,n])*emission_probability[n,obs_seq[t]] #對應於公式,前面是對應相乘
return F if __name__ == '__main__': trainsition_probability = [[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]] emission_probability = [[0.5,0.5],[0.4,0.6],[0.7,0.3]] pi = [0.2,0.4,0.4] #然后下面先得到前向算法,在A,B,pi參數已知的前提下,求出特定觀察序列的概率是多少?
obs_seq = [0,1,0] Row = np.array(trainsition_probability).shape[0] Col = len(obs_seq) F = Forward(trainsition_probability,emission_probability,pi,obs_seq) print F
對應結果:
[[ 0.1 0.077 0.04187 ]
[ 0.16 0.1104 0.035512]
[ 0.28 0.0606 0.052836]]