一,介紹
隱馬爾科夫模型(Hidden Markov Model,以下簡稱HMM)是比較經典的機器學習模型了,它在語言識別,自然語言處理,模式識別等領域得到廣泛的應用。目前隨着深度學習的崛起,尤其是RNN,LSTM等神經網絡序列模型的火熱,HMM的地位有所下降。
使用HMM模型時我們的問題一般有這兩個特徵:1)我們的問題是基於序列的,比如時間序列,或者狀態序列。2)我們的問題中有兩類數據,一類序列數據是可以觀測到的,即觀測序列;而另一類數據是不能觀察到的,即隱藏狀態序列,簡稱狀態序列。我們常用的谷歌輸入法等就可以採用HMM模型,根據你之前的輸入,判斷你接下來要輸入什麼給出提示。
模型定義:
對於HMM模型,首先我們假設Q是所有可能的隱藏狀態的集合,V是所有觀測狀態的集合,即:
其中,N是可能的隱藏狀態數,M是所有的可能的觀察狀態數。
對於一個長度爲T的序列,I對應的狀態序列, O是對應的觀察序列,即:
其中,任意一個隱藏狀態it∈Q,任意一個觀察狀態ot∈V。
接着,我們做出以下假設:
1)齊次馬爾科夫鏈假設,即任意時刻的隱藏狀態只依賴於它前一個隱藏狀態。我們得到如果在時刻t的隱藏狀態是it=qi,在時刻t+1的隱藏狀態是it+1=qj, 則從時刻t到時刻t+1的HMM狀態轉移概率aij可以表示爲:
從而得到馬爾科夫鏈的狀態轉移矩陣A:
2) 觀測獨立性假設,即任意時刻的觀察狀態只僅僅依賴於當前時刻的隱藏狀態。如果在時刻t的隱藏狀態是it=qj, 而對應的觀察狀態爲ot=vk, 則該時刻觀察狀態vk在隱藏狀態qj下生成的概率爲bj(k)爲:
這樣bj(k)可以組成觀測狀態生成的概率矩陣B:
我們再獲得一個初始狀態t=1的初始狀態概率分佈Π:
根據上面的兩個假設和初始狀態就可以確定一個隱馬爾科夫模型。
確定HMM模型後,我們一共有三個經典的問題需要解決:
1) 評估觀察序列概率。即給定模型λ=(A,B,Π)和觀測序列O={o1,o2,...oT},計算在模型λ下觀測序列O出現的概率P(O|λ)。這個問題的求解需要用到前向後向算法。
2)模型參數學習問題。即給定觀測序列O={o1,o2,...oT},估計模型λ=(A,B,Π)的參數,使該模型下觀測序列的條件概率P(O|λ)最大。這個問題的求解需要用到基於EM算法的鮑姆-韋爾奇算法。
3)預測問題,也稱爲解碼問題。即給定模型λ=(A,B,Π)和觀測序列O={o1,o2,...oT},求給定觀測序列條件下,最可能出現的對應的狀態序列,這個問題的求解需要用到基於動態規劃的維特比算法。
二,代碼實現
前向算法:
輸入:HMM模型λ=(A,B,Π),觀測序列O=(o1,o2,...oT)
輸出:觀測序列概率P(O|λ)
1) 計算時刻1的各個隱藏狀態前向概率:
2) 遞推時刻2,3,...T時刻的前向概率:
3) 計算最終結果:
數據:
假設有三個盒子,裏面裝有白球和紅球如下:
盒子 | 1 | 2 | 3 |
紅球數 | 5 | 4 | 7 |
白球數 | 5 | 6 | 3 |
求O={紅,白,紅}概率
代碼:
import numpy as np
def FB():
data = [[5,4,7],[5,6,3]] # 初始數據
pi = np.mat([0.2,0.4,0.4]) # t=1時,初始狀態概率
A=np.mat([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]]) # 狀態轉移矩陣
B=np.mat([[0.5,0.5],[0.4,0.6],[0.7,0.3]]) # 觀察狀態矩陣
N=2;M=3;O=[0,1,0] # 求輸出O概率,對應爲{紅、白、紅}
a = np.multiply(pi,B[:,O[0]].T) # 第一步,時刻1的各個隱藏狀態前向概率
for i in range(1,M):
tmp = a.copy()
for j in range(M):
a[0,j]=np.multiply(tmp,A[:,j].T).sum(axis=1)*B[j,O[i]] # 第二步,遞推時刻2,3,...T時刻的前向概率
p=a.sum(axis=1) # 第三步,計算最終結果
return p
if __name__=="__main__":
p=FB()
print(p)
{紅,白,紅}出現概率爲:0.130218
後向算法:
輸入:HMM模型λ=(A,B,Π),觀測序列O=(o1,o2,...oT)
輸出:觀測序列概率P(O|λ)
1) 初始化時刻T的各個隱藏狀態後向概率:
2) 遞推時刻T−1,T−2,...1時刻的後向概率:
3) 計算最終結果:
代碼:
import numpy as np
# 後向算法
def BB():
pi = np.mat([0.2, 0.4, 0.4]) # t=1時,初始狀態概率
A = np.mat([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]]) # 狀態轉移矩陣
B = np.mat([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]]) # 觀察狀態矩陣
b=np.mat([1.0,1.0,1.0])
N = 2;M = 3;O = [0, 1, 0] # 求輸出O概率,對應爲{紅、白、紅}
i=M
while i>1:
tmp = b.copy()
for j in range(M):
ab = np.multiply(A[j,:],B[:,O[i-1]].T)
b[0,j]=np.multiply(ab,tmp).sum(axis=1) # 第二步,遞推時刻2,3,...T時刻的前向概率
i-=1
pib = np.multiply(b, pi)
return np.multiply(pib,B[:,0].T).sum(axis=1)
if __name__=="__main__":
p=BB()
print(p)
{紅,白,紅}出現概率爲:0.130218