摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA
https://www.cnblogs.com/zhibei/p/9391014.html
CRF(Conditional Random Field),即條件隨機場。經常被用於序列標注,其中包括詞性標注,分詞,命名實體識別等領域。
Viterbi算法,即維特比算法。是一種動態規划算法用於最可能產生觀測時間序列的-維特比路徑-隱含狀態序列,特別是在馬爾可夫信息源上下文、隱馬爾科夫模型、條件隨機場中
一、CRF基本概念
我們以命名實體識別NER為例,先介紹下NER的概念:
這里的label_alphabet中的b代表一個實體的開始,即begin;m代表一個實體的中部,即mid;e代表一個實體的結尾,即end;o代表不是實體,即None;<start>和<pad>分表代表這個標注label序列的開始和結束,類似於機器翻譯的<SOS>和<EOS>。
這個就是word和label數字化后變成word_index,label_index。最終就變成下面的形式:
因為label有7種,每一個字被預測的label就有7種可能,為了數字化這些可能,我們從word_index到label_index設置一種分數,叫做發射分數emit:
看這個圖,有word_index 的 1 -> 到label_index 的 4的小紅箭頭,像不像發射過來的?此時的分數就記作emit[1][4]。
另外,我們想想,如果單單就這個發射分數來評價,太過於單一了,因為這個是一個序列,比如前面的label為o,那此時的label被預測的肯定不能是m或s,所以這個時候就需要一個分數代表前一個label到此時label的分數,我們叫這個為轉移分數,即T:
如圖,橫向的label到label箭頭,就是由一個label到另一個label轉移的意思,此時的分數為T[4][4]。
此時我們得出此時的word_index=1到label_index=4的分數為emit[1][4]+T[4][4]。但是,CRF為了全局考慮,將前一個的分數也累加到當前分數上,這樣更能表達出已經預測的序列的整體分數,最終的得分score為:
score[1][4] = score[0][4]+emit[1][4]+T[4][4]
所以整體的score就為:
最后的公式為這樣的:
其中X為word_index序列,y為預測的label_index序列。
因為這個預測序列有很多種,種類為label的排列組合大小。其中只有一種組合是對的,我們只想通過神經網絡訓練使得對的score的比重在總體的所有score的越大越好。而這個時候我們一般softmax化,即:
其中分子中的s為label序列為正確序列的score,分母s為每中可能的score。
這個比值越大,我們的預測就越准,所以,這個公式也就可以當做我們的loss,可是loss一般都越小越好,那我們就對這個加個負號即可,但是這個最終結果手機趨近於1的,我們實驗的結果是趨近於0的,這時候log就派上用場了,即:
當然這個log也有平滑結果的功效。
二、計算過程
就是為了求得所有預測序列可能的得分和。我們第一種想法就是每一種可能都求出來,然后累加即可。可是,比如word長為10,那么總共需要計算累加10^7次,這樣的計算太耗時間了。那么怎么計算的時間快呢?這里有一種方法:
因為剛開始為<start>即為5,然后word_index為0的時候的所有可能的得分,即s[0][0],s[0][1]...s[0][6]中間的那部分。然后計算word_index為1的所有s[1][0],s[1][1]...s[1][6]的得分,這里以s[1][0]為例,即紅箭頭的焦點處:這里表示所有路徑到這里的得分總和。
這里每個節點,都表示前面的所有路徑到當前節點路徑的所有得分之和。所以,最后的s[4][6]即為最終的得分之和,即:
計算gold分數,即:S(X,y) 這事只要通過此時的T和emit函數計算就能得出,計算公式上面已經給出了:
然后就是重復上述的求解所有路徑的過程,將總和和gold的得分都求出來,得到loss,然后進行更新T,emit即可。(實現的話,其實emit是隱層輸出,不是更新的對象,之后的實現會講)
解碼過程,就是動態規划,但是在這種模型中,通常叫做維特比算法。如圖:
大概思路就是這次的每個節點不是求和,而是求max值和記錄此max的位置。就是這樣:
最后每個節點都求了出來,結果為:
最后,根據最后的節點,向前選取最佳的路徑。過程為:、
三、Viterbi(維特比)算法原理詳解
維特比算法是一種動態規划算法用於最可能產生觀測時間序列的-維特比路徑-隱含狀態序列,特別是在馬爾可夫信息源上下文和隱馬爾科夫模型中。術語“維特比路徑”和“維特比算法”也被用於尋找觀察結果最有可能解釋的相關動態規划算法。例如在統計句法分析中動態規划可以被用於發現最有可能的上下文無關的派生的字符串,有時被稱為“維特比分析”。
利用動態規划尋找最短路徑
動態規划是運籌學的一個分支,是求解決策過程最優化的數學方法,通常情況下應用於最優化的問題,這類問題一般有很多可行的解,每個解有一個值,而我們希望從中找到最優的答案。
在計算機科學領域,應用動態規划的思想解決的最基本的一個問題就是:尋找有向無環圖(籬笆網絡)當中兩個點之間的最短路徑(實際應用於地圖導航、語音識別、分詞、機器翻譯等等)
下面舉一個比較簡單的例子做說明:求S到E的最短路徑,如下圖(各點之間距離不相同):
我們知道,要找到S到E之間最短路徑,最容易想到的方法就是窮舉法。也就是把所有可能的路徑都例舉出來。從S走向A層共有4種走法,從A層走向B層又有4種走法,從B層走向C層又有4種走法,然后C層走向E點只有一種選擇。所以最終我們窮舉出了4*4*4=64種可能。顯然,這種方法必定可行,但在實際的應用當中,對於數量及其龐大的節點數和邊數的圖,其計算復雜度也將會變得非常大,而計算效率也會隨之降低。
因此,這里選擇適用一種基於動態規划的方式來尋找最佳路徑。
所謂動態規划。其核心就是“動態”的概念,把大的問題細分為多個小的問題,基於每一步的結果再去尋找下一步的策略,通過每一步走過之后的局部最優去尋找全局最優,這樣解釋比較抽象,下面直接用回剛剛的例子說明。如下圖:
首先,我們假設S到E之間存在一條最短路徑(紅色),且這條路徑經過C2點,那么我們便一定能夠確定從S到C2的64條(4*4*4=64)子路經當中,該子路經一定最短。(證明:反證法。如果S到C2之間存在一條更短的子路經,那么便可以用它來替代原先的路徑,而原來的路徑顯然就不是最短了,這與原假設自相矛盾)。
同理,我們也可以得出從S到B2點為兩點間最短子路經的結論。這時候,真相便慢慢浮出水面:既然如此,我們計算從S點出發到點C2的最短路徑,是不是只要考慮從S出發到B層所有節點的最短路徑就可以了?答案是肯定的!因為,從S到E的“全局最短”路徑必定經過這些“局部最短”子路經。沒錯!這就是上面提及到的通過局部最優的最優去尋找全局最優,問題的規模被不斷縮小!
接下來,要揭曉答案了!繼續看下圖:
回顧之前的分析:我們計算從S到C2點的最短路徑時候只需要考慮從S出發到B層所有節點的最短路徑,B層也是。對B2來說,一共有4條路線可達,分別是A1->B2,A2->B2,A3->B2, A4->B2。我們需要做的就是A2->B2這條路線保留,而其他3條刪掉(因為根據以上的分析,他們不可能構成全程的最短路線)。Ok,來到這里,我們會發現一個和小“漏洞”,這段S->A2->B2->C2->E的路線只是我一廂情願的假設,最短路徑下不一定是經過以上這些點。所以,我們要把每層的每個節點都考慮進來。
以下是具體做法:
step1:從點S出發。對於第一層的4個節點,算出他們的距離d(S,A1),d(S,A2),d(S,A3),d(S,A4),因為只有一步,所以這些距離都是S到它們各自的最短距離
step2:對於B層的所有節點(B1,B2,B3,B4),要計算出S到他們的最短距離。我們知道,對於特定的節點B2,從S到它的路徑可以經過A層的任何一個節點(A1,A2,A3,A4)。對應的路徑長就是d(S,B2)=d(S,Ai)+d(Ai,B2)(其中i=1,2,3,4)。由於A層有4個節點(即i有4個取值),我們要一一計算,然后找到最小值。這樣,對於B層的每個節點,都需要進行4次運算,而B層有4個節點,所以共有4*4=16次運算。
step3:這一步是該算法的核心。我們從step2計算得出的階段結果只保留4個最短路徑值(每個節點保留一個)。那么,若從B層走向C層來說,該步驟的級數已經不再是4*4,而是變成4!也就是說,從B層到C層的最短路徑只需要基於B層得出的4個結果來計算。這種方法一直持續到最后一個狀態,每一步計算的復雜度為相鄰兩層的計算復雜度為4*4乘積的正比!再通俗點說,連接着兩兩相鄰層的計算符合變成了“+”號,取代了原先的“*”號。用這種方法,只需要進行4*4*2=32次計算!
其實上述的算法就是著名的維特比算法,事實上非常簡單!
若假設整個網格的寬度為D,網格長度為N,那么弱適用窮舉法整個最短路徑的算法復雜度為O(D^N),而適用這種算法的計算復雜度為O(ND^2).試想一下,弱D與N都非常大,適用維特比算法的效率將會提高幾個數量級!、
---------------------
作者:Data_driver
來源:CSDN
原文:https://blog.csdn.net/qq_42189083/article/details/89350890
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!