CRF算法
許多隨機變量組成一個無向圖G = {V, E},V表明頂點,E表明頂點間相連的邊,網絡
每一個頂點表明一個隨機變量,邊表明兩個隨機變量間存在相互影響關係(變量非獨立),函數
若是隨機變量根據圖的結構而具備對應的條件獨立性,學習
具體來講,兩個沒有邊鏈接隨機變量V一、V2,在其它隨機變量O都肯定的狀況下,是獨立的。優化
即 P(V1, V2 | O) = P(V1 | O) * P(V2 | O)spa
那麼這被稱爲【成對馬爾科夫性】,另有不一樣定義的【局部馬爾科夫性】、【全局馬爾科夫性】,它們互爲充要條件(此處無證實)orm
對於知足成對馬爾科夫性無向圖,能夠對最大團做定義文檔
一個最大團是一組隨機變量(頂點)的集合,且要知足兩個條件數學
(1).這一組頂點之間,兩兩都有邊相連it
(2).任意一個不在這組內的頂點,不能和該組頂點的每個都有邊相連
那麼一個無向圖G,能夠惟一地表示爲一個最大團的集合C = {C1, C2, ...}
咱們可能會對這組隨機變量的聯合分佈感興趣,好比計算P(V1=a,V2=b,V3=c...)
能夠證實,無向圖G的聯合分佈,能夠被最大團表示爲 phi1(C1)phi1(C2)....phin(Cn) / Z
其中,phi1~phin稱爲最大團C1~Cn上的勢函數,Z是全部可能的隨機變量取值組合下,phi1(C1)phi1(C2)....phin(Cn)的和
能夠看出來Z實際上就是一個歸一項
由於勢函數通常要求是嚴格正的,因此會用一種指數函數的形式來表示
即phi1(C1)phi1(C2)....phin(Cn) = exp(E1(C1))exp(E2(C2))...exp(En(Cn)) = exp(En(Cn) + E1(Cn) + ... + En(Cn))
其中這個E1~En,能夠看作是對某個最大團的隨機變量的當前取值的打分
總結起來,若是要求P(Y1Y2...Yn)的值,則應該計算當前每一個最大團的分數,求和,並執行softmax,softtmax的底是全部可能的變量值組合。
linear-CRF
線性的CRF,每一個Y都只和前一個或後一個隨機變量相連,
如 Y1——Y2——Y3——...Yn
每一個最大團都是鄰近的兩個隨機變量,如(Y1, Y2)、(Y二、Y3)等
線性CRF一般用於序列預測中,
好比,假設輸入爲X,輸出爲序列Y,每個隨機變量的取值都在T = {'B', 'E', 'M', 'O'}之中,
那麼計算某個特定序列的條件機率。
更具體地,好比計算
P('BMEOBMEO' | X) / P(Y | X) = exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)
∑Y exp(Y | X)這項做爲歸一項,實際是求一樣長度的全部序列組合的exp分數之和,
對於目標序列'BMEOBMEO',它長度爲8,那麼一樣長度的序列包括'BBBBBBBB'、'BBBBBBBM'等等....
linear-CRF的前向計算
這個一樣長度的全部序列,數量是很是巨大的,
確切地說,應該是O(|T|^n)的量級,|T|是狀態集的大小,n是序列長度。
若是每個序列都要計算一次分數,那稍長一點的序列計算時間都會長到沒法接受。
此時,根據linear-CRF圖結構的特性,能夠採用動態規劃的方式,減小重複計算量,下降時間複雜度。
考慮Score(Y1:n-1, X)和Score(Y1:n, X)的區別,在兩個無向圖中,後者比前者增長了兩條邊,
(1).邊Yn-1——Yn (2).邊X——Yn
因此Score(Y1:n, X) = Score(Y1:n-1, X) + E-tran(Yn-1, Yn) + E-emmi(X, Yn)
其中E(Yn-1, Yn)又可稱爲轉移分數,E(X, Yn)又可稱爲發射分數。
發現了該遞推關係之後,再思考一個很是重要的遞推中間變量:
記 g(k, tag) = exp(Score(Y1:k-1Yk = tag, X))
也就是,在時間點k上,Yk等於tag,可是前面的Y1:k-1狀態隨意的分數,
由於Y1:k-1狀態隨意,它實質上是Y1:k-1字序列全部可能組合,且Yk以tag爲結尾的分數和
具體地,g(3, 'B') = ∑(Y1:k-1) exp(Score(Y1:Y2Y3='B', X)) = exp(Score('BBB', X)) + exp(Score('BEB', X)) + exp(Score('BMB', X)) + ... + exp(Score('OOB', X))
最後一個等式,很容易計算到,有 4 * 4 = 16個加和項
定義了g(k, tag),很重要一個點就是計算遞推關係,
即,假如知道了g(k, tag),那對於計算g(k+1, Yk+1)又有什麼幫助呢?首先展開g(k+1, Yk+1)
g(k+1, Yk+1) = ∑(Y1:k) exp(Score(Y1:kYk+1, X))
= ∑(Y1:k) exp[Score(Y1:k, X) + E-tran(Yk, Yk+1) + E-emis(X, Yk+1)]
= ∑(Y1:k) exp[Score(Y1:k, X)]exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]
= ∑(Yk)∑(Y1:k-1) exp[Score(Y1:k-1Yk, X)]exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]
= ∑(Yk) g(k, Yk)exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]
這樣,就產生了g(k, tag)的遞推公式,也舉一個簡單的例子
g(3, 'B') = g(2, 'B')exp(E-tran('B', 'B'))exp(E-emis(X, 'B')) + g(2, 'E')exp(E-tran('E', 'B'))exp(E-emis(X, 'B')) + g(2, 'M')exp(E-tran('M', 'B'))exp(E-emis(X, 'B')) + g(2, 'O')exp(E-tran('O', 'B'))exp(E-emis(X, 'B'))
在這種狀況下,要計算全序列的exp分數和,就要先計算每一個時間點上,以某個狀態結束的全序列exp分數和,並向後遞推
每次遞推都要用前一個時間的全狀態,組合後一個時間的每一個狀態,故遞推一次時間複雜度爲O(|T|^2)
總時間複雜度爲O(n|T|^2),比起強行計算的O(|T|^n)大大減小
linear-CRF的數值優化
咱們獲得了重要的遞推公式
g(k+1, Yk+1) = ∑(Yk) g(k, Yk)exp[E-tran(Yk, Yk+1)]exp[E-emis(X, Yk+1)]
可是,大量exp的相乘,可能致使浮點運算的數值不穩定,故在代碼中,會採起一些方法優化數值穩定性
首先求和能夠寫成對向量的求和
sum(g(k, Yk+1)exp(E-tran('B', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'E')exp(E-tran('E', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'M')exp(E-tran('M', Yk+1))exp(E-emis(X, Yk+1)) + g(k, 'O')exp(E-tran('O', Yk+1))exp(E-emis(X, Yk+1)))
進一步,調研向量中的每一個份量,以第二個爲例
g(k, Yk+1)exp(E-tran('B', Yk+1))exp(E-emis(X, Yk+1))
= exp(log(g(k, 'E')exp(E-tran('E', Yk+1))exp(E-emis(X, Yk+1)))) #先log後exp,數值仍是同樣的
= exp(log(g(k, 'E')) + E-tran('E', Yk+1) + E-emis(X, Yk+1)) #log掉後兩項自帶的exp,直接能夠用分數相加
這個時候,能夠發現原來乘積的第一項,已經由g函數變成了log g函數,但等式左邊仍是g函數
若是想要保持兩邊一致,不妨左側也加上log,就會變成
log g(k+1, Yk+1) = log(sum(exp(vector))),其中vector = (log g(k, Yk+1)+E-tran('E', Yk+1) + E-emis(X, Yk+1))
右側這個log(sum(exp(xxx)))的計算,在pytorch裏有API,直接能夠看torch.logsumexp的文檔
實際上,這裏都尚未講到真正數值穩定計算的部分,只是作了恆等變換,變成方便觀察的形式,
對於logsumexp的數值穩定計算,假設其內部的vector爲(v1, v2, ...vn),且max(v1, v2, ...vn) = vmax,可進行以下變形
logsumexp([v1, v2, ..., vn])
= log(sum(exp([v1-vmax+vmax, v2-vmax+vmax, ..., vn-vmax+vmax])))
= log(sum([exp(vmax)exp(v1-vmax), exp(vmax)exp(v2-vmax), ... , exp(vmax)exp(vn-vmax)]))
= log(exp(vmax) * sum([exp(v1-vmax), exp(v2-vmax), ..., exp(vn-vmax)]))
= vmax + log(sum(exp[v1-vmax, v2-vmax, ..., vn-vmax]))
這樣子,(v1, v2, ..., vn)中的最大份量vmax將會被直接提出來,不進行一遍exp後再log的計算,
其他的較小值進行exp的計算,使得數值誤差儘量小,達到數值穩定的效果
linear-CRF的學習
在此前linear-CRF的計算過程當中,咱們可使用遞推公式(狀態轉移方程),使得計算指定序列P(Y | X)的時間複雜度降爲O(nT^2)
可是,使用遞推公式要求E-tran和E-emis函數是已知的
若是僅有觀測數據集(X, Y)對,卻不值得E-tran和E-emis,應如何計算E-tran和E-emis呢
實際上,當知道確切E-tran、E-emis時,計算出來的exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)能夠被認爲是條件機率
而不知道E-tran、E-emis時,根據初始化參數計算得的exp(score('BMEOBMEO', X)) / ∑Y exp(score(Y), X)則能夠被認爲是似然
求解E-tran、E-emis的過程,即對具體的數據集(X, Y)求使得exp(score(Y, X)) / ∑Y' exp(score(Y'), X)最大的E-train、E-emis參數
其實就是最大似然,可使用梯度降低等優化方法求解。實際操做中,會去最小化負對數似然,即,
minimize log(∑Y' exp(score(Y'), X)) - score(Y, X)
那具體的參數應該如何設置呢,按照流行的LSTM + linear-CRF的方法,
E-tran被直接設置爲一個 T * T 的參數矩陣,矩陣表明了序列狀態間的轉移分數
E-emis則不直接設置爲參數,而是由LSTM + dense_layer把X映射成一個feature,
feature的維度是 n * T,第一個維度表明時間(序列長度),第二維度表明每一個時間狀態上都有T個發射分數,
這T個發射分數則對應每一個時間段的E-emis
即E-emis(Yk, X) = E-emis(Yk, feature) = feature[k, tags.index(Yk)]
這樣,E-emis的參數便被暗含在LSTM + dense_layer的參數中
LSTM + linear-CRF的動機
既然如此,那麼可能出現疑問,爲何E-tran能夠單獨設置,E-emis卻不單獨設置呢?
換句話說,既然單純的linear-CRF就能完整解決一個序列預測的問題,爲何還要在前面加一個LSTM呢?
這個問題其實又能夠反過來問,既然單純的LSTM已經能夠完整解決一個序列預測的問題,爲何還要在後面加一個CRF呢?
實際上,這兩種方法的能力各有側重,有剛恰好能夠互補,因此在序列預測中被放在一塊兒,成爲了很是流行的結構。
LSTM的優勢是具備很是強大的特徵提取能力,由於它可使用許多非線性函數、上下文關係等,構建出高維又稠密的非線性特徵,
若是不使用LSTM的特徵提取,像E-trans同樣,設置一個純粹參數化的E-emis矩陣,
那這種矩陣相乘的特徵提取是線性的,且同時仍是稀疏的,也沒法結合X序列的上下文關係,效果差距很是很是大。
LSTM雖然具備以上特色,可是若是僅僅使用它進行序列預測,它則缺乏一個顯式地對轉移關係的建模。
很明顯地,LSTM只能模擬發射函數,卻不能模擬轉移函數,它能夠提取複雜的特徵,可是有時會對不合理的局部過於寬容。
例如,BMEO分詞標註中(能夠是分詞標註、實體標註,以分詞爲例),
B表明詞語開始,E表明詞語結束,M表明詞語中部,O表明單字詞,
邏輯上而言,一組距離最近的B和E的中間只能存在M,而像BB、MB這種局部結構,是絕對錯誤的,
但LSTM更關注整體的loss最小化,不顯式地對鄰近轉移關係進行建模,因此老是免不了出現這樣的局部小錯
linear-CRF則帶來了一個轉移矩陣參數,可以頗有效地解決這個問題。
這就是LSTM與linear-CRF配合使用的緣由,一句話總結,LSTM負責特徵提取,linear-CRF負責鄰近轉移關係管理。
可是寫到這裏還有一個有趣的思考:雖然linear-CRF要注重轉移關係,
可是E-trans是否能夠像E-emis同樣,使用一個複雜網絡來模擬,而不直接使用一個線性矩陣呢?
這個彷佛是一個頗有趣的話題,到時要去算算間複雜度是否能容許這種狀況下的前向計算,說不定是一個頗有趣的點?
linear-CRF的預測
在linear-CRF的計算問題中,剛剛已經討論了兩種,一個是機率計算問題,一個是參數學習問題
機率計算問題知道E-tran和E-emis,要計算P(Y | X),
參數學習問題知道一批(X, Y),但願參數估計E-tran,E-emis,
最後剩下一個預測問題,也稱解碼問題,模型訓練好之後,獲得了估計的E-tran,E-emis,此時來一個新的X,最可能的Y是什麼?
即,預測問題,知道E-tran,E-emis,X,要計算argmaxY P(Y | X)
這個式子能夠做一些簡化,
argmaxY P(Y | X)
= argmaxY exp(score(Y, X)) / ∑Y exp(score(Y), X)
= argmaxY exp(score(Y, X)) #normalize項對Y的取值不影響
= argmaxY score(Y, X) #exp是單調函數
這三個問題,實際上跟HMM的三個問題也是徹底對應的。
linear-CRF的預測問題,實際上和機率計算問題是極其相似的,
只不過前者是求最大的機率路線,後者是前全路線的機率和,
一樣地,若是不使用動態規劃方法,枚舉的時間複雜度是O(T^n),使用後時間複雜度是O(nT^2)
然而最大機率路線的算法還有個獨有的名字,也就是日常很是常見的viterbi算法233333
在前向機率計算時,咱們定義的遞推公式單元是
g(k, tag) = exp(Score(Y1:k-1Yk = tag, X))
思想是,只要知道了k時間點Yk爲特定狀態的全路線機率,就能夠知道k+1時間點Yk+1位特定狀態的全路線機率
同理,定義一個 h(k, tag) = argmax Y1:k-1 score(Y1:k-1Yk=tag, X)
思想是,只要知道了k時間點Yk爲特定狀態的最大機率路線,但願可以遞推出k+1時間點Yk+1位特定狀態的最大機率路線
假設,後者這個路線,在k時間點Yk要通過狀態t,且k時間點Yk通過狀態t的最大機率路線是Yt1:k-1,
那麼後者的路線一定是Yt1:k-1,Yk=t,Yk+1,不然,不存在更大機率的路線。
h(k+1, Yk+1)
= argmax Y:k score(Y1:kYk+1, X)
= argmax Y:k score(Y1:kYkYk+1, X)
= argmax Y:k-1Yk score(Y1:k-1Yk, X) + E-tran(Yk, Yk+1) + E-emis(Yk, X)
= Y1:k-1argmaxYk (argmax Y:k-1 score(Y1:k-1Yk, X) + E-tran(Yk, Yk+1) + E-emis(Yk, X))
= Y1:k-1argmaxYk (h(k, Yk) + E-tran(Yk, Yk+1) + E-emis(Yk, X))
這樣就能夠求得最大的機率路線