隱馬爾科夫-維特比算法


概念介紹:

  繼上篇貝葉斯(http://www.cnblogs.com/zhiranok/archive/2012/09/22/native_bayes.html)后,一直想完成隱馬爾科夫這篇,一是一直沒有時間完成python的示例實現代碼,二是想找一個區別於天氣的隱馬爾科夫例子。區別於貝葉斯,隱馬爾科夫模型是基於時序的概率模型,本文只關注於一階隱馬爾科夫模型,即某一時刻的狀態值只跟上一時刻的狀態值有關。該模型可以用三元組表示:λ = (A, B,π ), 其中:

  • A:為狀態轉移概率矩陣
  • B:為觀察概率矩陣,或稱為概率矩陣
  • π:為初始概率矩陣 

舉一個例子來說明。

  • 假設有一只電動玩具狗,它只會干三件事:汪汪叫(W),跑來跑去(R),睡覺(S)。則觀察狀態集合V為{W, R, S}, 則觀察狀態數目M=3 .
  • 經過了解得知,電動玩具狗是受情緒控制的,它會無聊(B),高興(H),生氣(A),故狀態集合Q={B, H,A}, 狀態數目N=3
  • 分析這只玩具狗后得知其狀態轉移概率矩陣為:

  • 混淆矩陣為:

  • 初始概率矩陣為:π = (0.2, 0.4, 0.4)

維特比算法

  假設一天中觀察到玩具狗的行為序列為{W,R,S,R,S}, 求最可能的情緒狀態序列是什么。這是典型的隱馬爾科夫解碼問題,下面使用維特比算法求解。

  •  維特比變量 : 使t時刻為狀態i的最佳狀態序列的概率值,遞推公式:

 

  

  •  輔助變量   表示t時刻為狀態i時的前一時刻t-1時的最佳狀態,注意, 為t時刻為i的最佳的概率,而為最佳狀態值,由此也可知 記錄了到達此點的最佳上一個時刻的狀態點路徑,故分配T*N數組存儲,用於最后回溯路徑得到最終結果,動態規划的思想。

  

   

Python 實現代碼:

 

class yieldmrkf_t:
    def __init__(self, A, B, Pi, OSet, QSet):
        self.A  = A # 轉移概率矩陣
        self.B  = B # 混淆概率矩陣
        self.Pi = Pi # 初始概率矩陣
        self.N  = len(Pi) # 隱狀態數量
        self.M  = len(B) / self.N # 觀察狀態數量
        self.OsetVal = OSet
        self.QSetVal = QSet
        self.QSet = []
        self.Oset = []
        for i in range(0, self.N):
            self.QSet.append(i)
        for i in range(0, self.M):
            self.Oset.append(i)
    def dump(self):
        strA = "A:"
        i = 0
        for k in self.A:
            if i % self.N == 0:
                strA = strA + "\n"
            strA = strA + " " + str(k)
            i = i + 1
        print(strA)
        i = 0
        strB = "B:"
        for k in self.B:
            if i % self.M == 0:
                strB = strB + "\n"
            strB = strB + " " + str(k)
            i = i + 1
        print(strB)
        print("Pi:", self.Pi, "N:", self.N, "M:", self.M)
    def get_a(self, i, j):
        return self.A[i*self.N + j]
    def get_b(self, o, i):
        return self.B[i*self.M + o]
    def get_delta(self, delta_set, t, i):
        return delta_set[t*self.N + i]
    def convertOState(self, OStateSet_Val):
        dest = []
        for k in OStateSet_Val:
            for i in range(0, self.M):
                if k == self.OsetVal[i]:
                    dest.append(i)
        return dest
    def decode(self, OStateSet_Val):
        OStateSet = self.convertOState(OStateSet_Val)
        T = len(OStateSet)
        # 初始化t= 1 的情況
        delta_set = []
        fai_set   = []
        for i in self.QSet:
            delta_1_i = self.Pi[i] * self.get_b(OStateSet[0], i)
            delta_set.append(delta_1_i)
            fai_set.append(0)
        # 遞推求的delta 和fai
        for t in range(1, T):
            for i in self.QSet:
                fai_t_i   = 0
                tmp_fai_i = 0
                tmp_delta = 0
                for j in self.QSet:
                    #compute fai
                    tmp = self.get_delta(delta_set, t - 1, j) * self.get_a(j, i)
                    if tmp > tmp_fai_i:
                        tmp_fai_i = tmp
                        fai_t_i   = j
                    #compute delta
                    tmp = tmp * self.get_b(OStateSet[t], i)
                    if tmp > tmp_delta:
                        tmp_delta = tmp
                fai_set.append(fai_t_i)
                delta_set.append(tmp_delta)
        #select last i
        tmp_rate_i_T = 0
        i_T = 0
        for i in self.QSet:
            tmp = self.get_delta(delta_set, T-1, i)
            if tmp > tmp_rate_i_T:
                tmp_rate_i_T = tmp
                i_T = i
        i_dest = []
        i_dest.append(i_T)
        for tmp_t in range(1, T):
            t = T - tmp_t
            i_dest.append(fai_set[(t) * self.N + i_dest[len(i_dest) - 1]])

        dest = []
        for n in range(0, T):
            dest.append(self.QSetVal[i_dest[(T-n) - 1]])
        return dest

OSet = ['W', 'R', 'S']
QSet = ['B','H', 'A']
O    = ['W', 'R', 'S', 'R', 'S']
A  = [0.5, 0.2, 0.3, 0.3, 0.5, 0.2, 0.2, 0.3, 0.5]
B  = [0.5, 0.2, 0.3, 0.4, 0.1, 0.5, 0.7, 0.1, 0.2]
Pi = [0.2, 0.4, 0.4]
o = yieldmrkf_t(A, B, Pi, OSet, QSet)
o.dump()
dest = o.decode(O)
print("output:", dest

 

輸出結果:

A:
0.5 0.2 0.3
0.3 0.5 0.2
0.2 0.3 0.5
B:
0.5 0.2 0.3
0.4 0.1 0.5
0.7 0.1 0.2
('Pi:', [0.2, 0.4, 0.4], 'N:', 3, 'M:', 3)
('output:', ['A', 'H', 'H', 'H', 'H'])

總結

  • 隱馬爾科夫適用於時序概率模型,“隱”的含義是既可觀察的狀態序列和隱藏(不可觀察的)狀態序列存在一定關系
  • 本文探究了隱馬爾科夫的解碼問題,分析實現了維特比算法
  • 隱馬爾科夫的概率計算問題和模型參數學習問題待以后探究。

更多精彩文章 http://h2cloud.org


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM