雙層LSTM+CRF做實體識別,詳細過程,看不懂我自罰三杯!!!

BiLSTM+CRF:

如果看了之後還看不懂,我自罰三杯!!!

參考的是國外一個很好的博客,原文鏈接:https://createmomo.github.io/2017/12/06/CRF-Layer-on-the-Top-of-BiLSTM-7/

現在抽空學習一下知識圖譜方面的知識

1、Introduction

1.1 開始之前:

       假設我們有兩個實體類別:person+location。在我們的數據集中,我們有五個標籤,B-person、I-person、B-location、I-  location以及標籤O。在一個句子x(小明生活在北京)中,小明是一個person實體,北京是一個location實體。其他的元素如“生”“活”“在”都屬於O。

1.2 BiLSTM-CRF模型:

                              

         BilSTM-CRF模型輸入:wi是句子中每一個元素,轉換成字向量之後作爲輸入。

         BilSTM-CRF模型輸出:每一個元素相對應的標籤。

         BiLSTM模型輸出:每一個元素對每個標籤的概率,下圖中黃色部分。這些會作爲CRF的輸入。

                                    

1.3 如果沒有CRF層

如果沒有CRF層,我們貌似也可以BiLSTM層每個元素輸出的最大概率標籤當做最後結果,如下圖所示,w0的最大概率輸出標籤是B-person,那麼直接把這個元素最後結果當做B-person,相應的w1是I-person,等等。

                                    

上面說的貌似是正確的,但這種情況下元素之間的標籤不存在約束關係,即B-person之後絕對不能跟B-person,I-person之前絕對不能是I-organization,所以就會出現下面的錯誤。

                                 

1.4 CRF層能夠學習到上面所說的限制關係

CRF層能夠對最後的結果加上一些限制來確保結果是正確的,這些限制可以在訓練過程中通過訓練集自動學習得到。這些限制可能有:

  1. 句子中的第一個字可能是B-或者O,不能是I-
  2. B-label I-label2 I-label3中,label1、label2、label3應該是相同的實體label。也就是B-person後面不能跟I-location
  3. O後面不能跟I-label,這是明顯的。

2 、CRF層:

      在CRF層,存在兩種類型的scores,這個兩種scores是crf層重要部分。

2.1 Emission score

      Emission scores主要來自於BiLSTM層,如下圖所示,第一個元素對於B-person的得分是1.5。

                          

      爲了方便觀察,給每個label加 一個index。

我們使用xiyj來代表emission score,其中i表示第幾個元素,yj表示label的index。例如上上個圖中,xi=1,yj=2= xw1,B-organization=0.1,代表的是第二個元素是B-organization的得分。

2.2 Transition score

       tyiyj表示transition score,例如,tB-person,I-person=0.9意味着B-person到下一個字是I-person的概率是0.9,因此,transition包含所有標籤之間的轉移概率。爲了是transition矩陣更魯棒,我們新加兩個label,start和end,start表示一個句子的開始,並不是第一個字,end表示句子的結束。樣例如下圖所示:

顯然上述矩陣是存在一些限制關係的,如:transition矩陣從start到I-person和I-organization的概率是很低的,因爲第一個字應該以B-或者O-開始,而不是I-;B-person到I-organization的概率很低,因爲不能從一個label的開始到另一個標籤的中間;O-到I-的概率很低,因爲不可能呀!!!!那麼如何獲得這個矩陣呢?

實際上,transition矩陣是整個模型的一個參數,訓練之前,你可以隨機初始化這個矩陣,在訓練過程中,這個矩陣會不斷的更新,換言之,CRF層能夠學習到這個矩陣。

2.3 CRF lossfunction

        這一層的損失包含真實路徑和所有路徑的得分和,真實路徑應該是最高得分。(真實路徑也就是每個元素的真是標籤,舉個例子,一個句子有5個元素,標籤數量是7個,那麼路徑個數是7^5,如下圖所示,每條路徑都有一個得分,也可以說是一個概率,真實路徑只有一個,使其最大就好了)

      

那麼總得分就是Ptotal=P1+ P2+……+ Pn=eS1+ eS2+……+ eSn,e是自然對數,下一節會介紹如何計算Si。損失計算公式如下:

LossFunction=PRealPath/( P1+ P2+……+ Pn)

在訓練期間,參數的更新使這個比重越來越大。

  1. 如何計算每個路徑的得分
  2. 如何計算所有路徑的總得分
  3. 計算總得分的時候,有必要列出來所有路徑嗎(顯然是NO)

2.4 真實路徑

       在訓練過程中,lossFunction只需要兩個得分,真實路徑score+全部路徑的score。

真實路徑score的計算:句子有5個元素,7個label,真實路徑是START B-Person I-Person O B-Organization O END

Si=EmissionScore+TransitionScore

EmissionScore=(x0,START)+(x1,BPerson)+(x2,IPerson)+(x3,O)+(x4,BOrganization)+(x5,O)+(x6,END)     

x1,BPerson是第一個字是B-person的概率,這就是BiLSTM這一層的輸出呀

x0,STARTx6,END我們賦值爲0

TransitionScore=tSTART−>BPerson + tBPerson−>IPerson + tIPerson−>O + t0−>BOrganization + tBOrganization−>O + tO−>END

tBPerson−>IPersonCRFtransition的參數,表示B-personI-person的轉移概率

2.5 全路徑score

      可以計算出所有路徑的score然後相加得到全路徑的得分,但這樣的話計算量是相當大的,訓練是很耗時的。

      下面的例子會讓你瞭解如何快速計算全路徑的score,一步一步來,不着急,你會明白其中的奧妙。

Step1LossFunction=PRealPath/( P1+ P2+……+ Pn)

             LogLossFunction=log(PRealPath/( P1+ P2+……+ Pn))

             最小化

                         

Step2爲了更好的描述,我們假設我們的句子長度只有3。  X=[w0, w1, w2];兩個label={ l1, l2}

             假設emission score情況如下:xij表示wi是lj的概率,即BiLSTM層的輸出

                  

             Transition矩陣如下:tij表示label從i到j的概率

             

Step3: 我們的目標是計算log(eS1+ eS1+ ...+eSN)

            整個計算過程和動態規劃想類似。所有可能路徑的總得分w0是已經計算好的,然後我們計算w0->w1的總得分,再計算                w0->w1->w2。在下面的步驟中,你會看到兩個變量,obsprevious。previous儲存了前一步的結果,obs表示當前字的              信息。

w0

         obs=[x01, x02]

         previous=None

          如果我們句子只有一個字,我們就不需要從previous中獲取結果了,因此previous是None。那麼很顯然,所有路徑的得分            就是log(ex01+ ex02)。

w0->w1

         obs=[ x11, x12]

         previous=[x01, x02]

         1.把previous和obs擴展成矩陣:

                                          

            爲什麼要擴展呢?因爲擴展之後纔能有效計算所有路徑的總得分呀。

          2.計算previous、obs和transition score的和:

                                       

                                           

             舉個簡單的例子你就理解了,假設只有兩個元素,兩個label,那麼路徑是不是有4條,即上面scores裏面的東西,                         scores  裏面每個元素的得分就是一個路徑的得分,包括emission score和transition score,這也是爲什麼要把previous                 和obs擴展成矩陣了,因爲這樣元素之間的相加可以羅列出所有的矩陣呀。那麼下一次迭代的previous是什麼呢,就是我               們的scores呀,只不過樣式需要變換一下:

                               

              爲什麼要這種樣式呢?我們分步計算一下就知道了:

                

               最後這個結果和直接求e求和再求log的效果是一樣的。看着previous是兩個元素,實際上還有四條路徑。

w0->w1->w2

               接下來的迭代和上面的幾乎是一樣的了。

               obs=[ x21, x22]

                previous=[log(ex01+x11+t11+ ex02+x11+t21), log(ex01+x12+t12+ ex02+x12+t22)]

                1.把previous和obs擴展成矩陣:

                                                                    

                               

                 2.計算previous、obs和transition score的和:

                  

                   下一次迭代的previous就是:看着複雜,實際很簡單。

                  

                   分步計算可以知道,三個元素時,一共有8條路徑,

                  

                   發現沒?完整的8條路徑,就是全路徑的得分了!!!

2.6 如果預測一個句子的label

      Step1emission score和transition score

                   假設句子還是三個字:X=[w0, w1, w2],且已經得到相應的emission score和transition score。

      Step2如果你瞭解Viterbi算法(之前瞭解過,貌似忘了,之前的博客有介紹HMM算法,和Viterbi差不多)。α0是歷史最好                        得分 。α1是相應標籤的indexs。

      w0

             obs=[x01, x02]

             previous=None

             現在我們只觀察到第一個字w0,如果obs=[ x01=0.2, x02=0.8],顯然,w0最好的結果就是l2。

      w0->w1

             obs=[ x11, x12]

             previous=[x01, x02]

            (1)老規矩,把previous和obs擴展成矩陣:、

                                      

                                                   

             (2)計算previous、obs和transition矩陣的和:

                           

                   到這裏你會不會覺得這和之前求總得分的步驟是一樣呀,不要着急,慢慢看。

                   previous=[max(scores[00], scores[10]), max(scores[01], scores[11])]

                   例如,如果我的得分是

                                   

                    那麼我們下一次迭代的previous就會變成

                     previous=[max(scores[00], scores[10]), max(scores[01], scores[11])] = [0.5, 0.4]

                     這裏previous存儲的是前一個字的每一個label的最大得分,和HMM很像啊啊啊啊啊!

                    Example Start

                           上述例子中,我們只有兩個label,這兩個label的index是0和1,。previous[0]表示到達前一個字是label1的最大                                值,同理,previous[1]表示到達前一個字是label2的最大值。每一次迭代中,變量previous存儲到達每一個                                    label的最大得分值。換言之,每一次迭代中,我們都存儲了到達每一個label的最優路徑。

                    Example End

                             我們上面提到過,我們還有兩個變量去存儲歷史信息α0和α1。

                            迭代時,我們把最優得分信息放入α0:

                            α0 = [(scores[10], scores[11])] = [(0.5, 0.4)]

                            α1中存入相應的列座標:

                            α1 = [(ColumnIndex(scores[10]), ColumnIndex(scores[11]))] = [(1, 1)]

                            如何解釋呢,l1的下標是0,l2的下標是1,所以(1, 1)=(l2, l2)表示當前字wi和li。具體來說就是對於w1                                    時,到達l1(這個l1是(l2, l2)中第一個元素l2所以在位置是0)的最大值的上一個標籤是l2,即到達0.5的路                                  徑是l(i-1) = l2 –> l(i) = l1。

                            到達l2(這個l2是(l2, l2)中第二個元素l2所以在位置是1)的最大值的上一個標籤是l2,即到達0.4的路徑是

                             l(i-1) = l2 –> l(i) = l2。

                             l(i-1)指的是字w(i-1)的標籤。相當於保存了路徑。

         w0->w1->w2

                      接下來的迭代和上面的幾乎是一樣的了。

                      obs=[ x21, x22]

                      previous=[0.5, 0.4]

                      1.把previous、obs擴展成矩陣:

                        

  1.                然後還是求和:

                                                          

  1.                然後計算找到最大值,更新previous:

                                              previous=[max(scores[00], scores[10]), max(scores[01], scores[11])]

                        假設這個得分是:

                                                     

                        那麼previous=[0.8, 0.9],實際上previous[0]和previous[1]中最大的一個就是最優路徑的得分

                        同時,我們需要更新α0和α1:

                        α0 = [(0,5, 0.4), (scores[10], scores[01])] = [(0,5, 0.4), (0,8 0.9)]

                        α1 = [(1, 1), (1, 0)]

                        我覺得我有必要再強調一下α1,現在到達w2的l1和l2的最優路徑分別是l2 –>l1 ->l2和l2 –>l2 ->l1

          Step3找到最高得分的最優路徑:

                       實際上面已經說過了,α1中保存的就是最優路徑,只要復現出來就ok了。算了,還是再說一遍吧。

                       w1->w2

                           α0 = [(0,5, 0.4), (0,8 0.9)]

                           α1 = [(1, 1), (1, 0)]

                           最大得分是0.9呀,相當於w2的 標籤是l2;再看α1,到達l2的上一個字w1的標籤是l1,所以最後一條連線就是                               l1- l2

                      w0->w1

                            上一個w1的標籤是l1,那麼到達l1的上一個字w0的標籤是l2,所以整個路徑就是l2 –>l1 ->l2。

3、Chainer Implementation

                終於到代碼實現了,但作者使用chainer實現的,所以不寫了吧,畢竟沒用過,改天貼上自己的代碼,整個算法過程肯定理解了吧。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章