Mark Chang's Blog

Machine Learning, Deep Learning and Python

Hidden Markov Model

1.Markov Model

Hidden Markov Modelnatural language processing 中,

常用於 part-of speech tagging

想要了解 Hidden Markov Model ,就要先了解什麼是 Markov Model

例如, 可以把語料庫中,各種字串的機率分佈,

看成是一個Random varaible 的 sequence , X=(X1,X2,...,XT)

其中, X 的值是 alphabet (字)的集合 : S={s1,s2,...,sn}

如果想要知道一個字串出現的機率, 則可以把字串拆解成Bigram, 逐一用前一個字,來推估下一個字的機率是多少

但是要先假設以下的 Markov Assumption

Limited Horizon : P(Xt+1=skX1,...,Xt)=P(Xt+1=skXt)Time Invariant : P(Xt+1=skXt)=P(X2=skX1)

其中,

Limited Horizon 的意思是,

每個 Xt+1 是什麼字 (si) 的機率, 只會受到上一個字 Xt 的影響

Time Invariant 的意思是,

每個 Xt+1 是什麼字 (si) 的機率, 和前一個字 Xt 的機率關係, 不會因為在字串中的位置不同, 而有所改變

註:事實上, 這兩種假設是為了簡化計算, 在真實的自然語言中, 以上兩種假設都不成立

做完以上兩個假設之後,

再用語料庫, 把上一個字是 si 時, 這個字是 sj 的機率, 建立成 Transition Matrix : A , 則 A 中的元素可以寫成:

ai,j=P(Xt+1=sjXt=si)

也可以用 Transition Diagram 來表示:

hmm1

如果想要計算字串 (s1,s2,...,sT)Model 中出現的機率, 可以從第一個字開始, 用 Transition Matrix 逐字推算下去

Initial State (第一個字)的機率, P(X1=s1)=πs1 , 則 Random sequence, (X1,X2,...,XT) ,的機率為:

P(X1=s1,X2=s2,...,XT=sT)=P(X1=s1)P(X2=ssX1=s1)...P(XT=sTXT1=sT1)=πs1Tt=2P(Xt=stXt1=st1)=πs1Tt=2aXt,Xt+1

舉個例子

假設有個 Markov Model,

alphabet 的集合為 S={0,1}

Initial State 的機率為 π0=0.2,π1=0.8

Transition Matrix

XtXt+10100.30.710.60.4

Transition Diagram 表示成:

hmm2

則在此 Model 中, 出現字串 1011 的機率為:

P(X1=1,X2=0,X3=1,X4=1)=π1×P(X2=0X1=1)×P(X3=1X2=0)×P(X4=1X3=1)=0.8×0.6×0.7×0.4=0.1344

2.Hidden Markov Model

所謂的 Hidden Markov Model , 就是從表面上看不到 state 是什麼

例如在做 part-of speech tagging 的時候, tagstate, 不知道哪個字要給哪個 tag

只能看到表面上的字, 從 words(observable) 去推斷 tag(hidden state) 是什麼

其中, observable 為一個集合 : O={o1,o2,...,on}

hidden state 為一集合 : Q={q1,q2,...,qn}

則表示當某個字的 tagi時, 這個字為 ok 的機率, 可用 Output Matrix : B 表示, 則` B$ 中的元素可以寫成:

bi(ok)=P(Xt=okqt=i)

則當上一個 tagj 時, 這個字的 tagi 的機率為:

aj,i=P(qt=iqt1=j)

則我們可以算在上一個 tagj 時, 這個字的 tagi , 且這個字為ok 的機率:

P(qt=iqt1=j)(Xt=okqt=i)=aj,i×bi(k)

如果我們要計算, 出現字串 (o1,o2,...,oT)tag(r1,r2,...,rT) 的機率:

P(X1=o1,X2=o2,...,XT=oT,q1=r1,q2=r2,...,qT=rT)=P(q1=r1)P(X1=o1q1=r1)×P(q2=r2q1=r1)P(X2=o2q2=r2)×...×P(qT=rTqT1=rT1)P(XT=oTqT=rT)=πr1P(X1=o1q1=r1)Tt=2P(qt=rtqt1=rt1)P(Xt=otqt=rt)=πr1br1(o1)Tt=2art1,rtbrt(ot)

如果要求出這個字串最有可能個 tag ,

則找出 r 的序列, 可以讓 P(X1=o1,X2=o2,...,XT=oT,q1=r1,q2=r2,...,qT=rT) 為最大值

argmaxri,rm,rnQπribri(o1)Tt=2arn,rmbrm(ok)

舉個例子,

有個研究者, 想根據某地人們生活日記中, 記載每天吃冰淇淋的數量, 來推斷當時的天氣變化如何

在某個地點有兩種天氣, 分別是 HotCold , 而當地的人們會記錄他們每天吃冰淇淋的數量, 數量分別為 1 , 23 ,

則可以把天氣變化的機率, 以及天氣吃冰淇淋數量的關係, 用 Hidden Markov Model 表示,

由於天氣是未知的, 為 hidden state , 天氣的集合為 Weather={HOT,COLD}

天氣的 Transition Matrix :

DaytDayt+1HOTCOLDHOT0.70.3COLD0.40.6

而冰淇淋數量是已知的, 為 observable , 冰淇淋數量的集合為 Icecream={1,2,3}

天氣變化對於冰淇淋數量的 Output Matrix :

WeatherIcecream123HOT0.20.40.4COLD0.50.40.1

Initial State 的機率為 πHOT=0.8,πCOLD=0.2

根據這個 Model , 假設有個吃冰淇淋的記錄 (3,1,3) , 想要預測當時的天氣如何,

例如, 出現天氣序列為 HCH 且 冰淇淋的記錄為 (3,1,3) 的機率如下

P(X1=3,X2=1,X3=3,q1=H,q2=C,q3=H)=P(q1=H)P(X1=3q1=H)×P(q2=Cq1=H)P(X2=1q2=C)×P(q3=Hq2=C)P(X3=3q3=H)=0.8×0.4×0.3×0.5×0.4×0.4=0.00768

如果有冰淇淋的記錄 (3,1,3) , 但不知道當時天氣如何, 想要預測當時的天氣如何,

可以把所有可能的天氣序列都列出來:

HHH HHC HCH HCC CHH CHC CCH CCC

然後分別計算, 哪個天氣序列和冰淇淋的記錄為 (3,1,3) 共同發生的機率, 看看哪個機率最高

3.Implementation

接著來實作 Hidden Markov Model

根據上一個例子, 建立出以下的 Model 以及演算法

hmm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
_STATE=['H','C']
_PI={'H':.8, 'C':.2}
_A={ 'H':{'H':.7, 'C':.3 }, 'C':{'H':.4,'C':.6} }
_B={'H':{1:.2,2:.4,3:.4}, 'C':{1:.5,2:.4,3:.1} }

def p_aij(i, j):
    return _A[i][j]

def p_bik(i, k):
    return _B[i][k]

def p_pi(i):
    return _PI[i]

def seq_probability(obs_init):
    seq_val=[];
    def rec(obs, val_pre, qseq_pre):
        if len(obs) >0:
            for q in _STATE:
                if len(qseq_pre) == 0 :
                    val = val_pre * p_pi(q) * p_bik(q, obs[0])
                else:
                    q_pre = qseq_pre[-1]
                    val = val_pre * p_aij(q_pre,q) * p_bik(q, obs[0])
                qseq = qseq_pre + [q]
                rec(obs[1:], val, qseq)
        else:
            seq_val.append((qseq_pre, val_pre))
    rec(obs_init, 1, [])
    for (seq,val) in seq_val:
        print 'seq : %s , value : %s'%(seq, val)
    print 'max_seq : %s  max_val : %s'%( reduce(lambda x1,x2: x2 if x2[1] > x1[1] else x1, seq_val))

其中,

_STATE=['H','C'] 是天氣的種類

_PI={'H':.8, 'C':.2}initial state 的機率

_A={ 'H':{'H':.7, 'C':.3 }, 'C':{'H':.4,'C':.6} }Transition Matrix

_B={'H':{1:.2,2:.4,3:.4}, 'C':{1:.5,2:.4,3:.1} }Output Matrix

p_aij(i, j) , p_bik(i, k) , p_pi(i)Model 和演算法的interface

seq_probability(obs_init) 是計算 sequence probability 的演算法

這個演算法,會根據 observable 把每種天氣序列的機率都算出來, 並求出最有可能的序列是哪個

接著到interactive mode試看看剛剛的例子

輸入了冰淇淋的記錄 (3,1,3) , 程式會把每種可能的天氣序列都列出來, 並求得最有可能者, 如下:

hmm.py
1
2
3
4
5
6
7
8
9
10
11
>>> import hmm
>>> hmm.seq_probability([3,1,3])
seq : ['H', 'H', 'H'] , value : 0.012544
seq : ['H', 'H', 'C'] , value : 0.001344
seq : ['H', 'C', 'H'] , value : 0.00768
seq : ['H', 'C', 'C'] , value : 0.00288
seq : ['C', 'H', 'H'] , value : 0.000448
seq : ['C', 'H', 'C'] , value : 4.8e-05
seq : ['C', 'C', 'H'] , value : 0.00096
seq : ['C', 'C', 'C'] , value : 0.00036
max_seq : ['H', 'H', 'H']  max_val : 0.012544

程式算出答案, 最有可能的序列為 ['H', 'H', 'H'] ,機率為 0.012544

其實, 把所有的序列都列出來, 這樣的演算法是非常沒有效率的

假設序列長度為 T, stateN 種, 則所有可能的序列有 NT

事實上, 我們要求機率最高的序列, 不需要把所有的序列都算出來, 用 Dynamic Programming 的技巧, 就可以了,

有一種演算法, 叫 Viterbi Algorithm 是將 Dynamic Programming 應用於 Hidden Markov Model

想知道什麼是 Viterbi Algorithm , 請看:Natural Language Processing – Viterbi Algorithm

4. Reference

本文參考至兩本教科書

Foundations of Statistical Natural Language Processing

Speech and Language Processing

以及台大資工系 陳信希教授的 自然語言處理 課程講義

Comments