命名實體識別LSTM+CRF的前向計算推導


在用LSTM+CRF做命名實體識別任務時,由於pytorch框架的crf需要自己實現,網上的很多教程都跳過了一些關鍵部分導致自己難以理解。本文用來記錄自己的相關理解,僅針對線性鏈式的CRF。歡迎指正。

1. log linear model

CRF、MEMM、N元邏輯迴歸都屬於log linear model。我們先來理解這個大類。
p(yx;wJ)=exp(wJFJ(x,y))yYexp(wJFJ(x,y)) p ( y | x ; \boldsymbol { w }_{|J|} ) = \frac { \exp ( \boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} ( x , y ) ) } { \sum _ { y ^ { \prime } \in \mathcal { Y } } \exp \left( \boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} \left( x , y ^ { \prime } \right) \right) }
其中w\boldsymbol { w }爲模型參數,FJ(x,y)\boldsymbol { F }_{|J|}( x , y )爲給定輸入特徵xx,輸出標籤yy的特徵向量。

注意:這裏模型參數和特徵向量都爲J, 物理意義是該模型一共有J個特徵。點乘表示用這J個特徵計算一個分數。與NLP任務中輸入序列長度無關!

1.2 邏輯迴歸

各種log linear model模型的區別,僅僅是在特徵函數FJ(x,y)\boldsymbol { F }_{|J|}( x , y )的定義不同。對於邏輯迴歸,假設特徵x長度爲M, 標籤類別數爲N, 那麼J=MNJ=M*N。且Fj=flaten(x×Iy=C)F_j=flaten(\boldsymbol x \times \boldsymbol I_{y=C})

1.1 CRF與邏輯迴歸的區別

CRF與邏輯迴歸的不同,在於

  • (1)CRF的特徵函數FJ(x,y)\boldsymbol { F }_{|J|}( x , y )考慮了輸入數據中的時序信息
    FJ(x,y)=i=2TfJ(xi,yi,yi1)(1.1)\boldsymbol { F }_{|J|}( x , y )=\sum_{i=2}^Tf_{|J|}(x_i, y_i, y_{i-1}) \tag{1.1}
  • (2)CRF的y與x都增加了一個維度,即序列長度T

2. NER中的LSTM+CRF

2.1 CRF的特徵定義

對於NER任務中,序列長度爲T,標籤類別數爲n的數據,LSTM的輸出特徵矩陣BT×nB_{T\times n}作爲CRF層的輸入,Bi,jB_{i,j}爲第ii個時間步爲標籤jj的概率。NER任務的CRF中我們定義了兩個特徵函數:

  • 輸入特徵B (代碼中的feats, 可以理解爲發射概率矩陣)
  • 和轉移特徵A (代碼中的transition矩陣)

權重w=[1,1]w=[1,1]現在重寫CRF的特徵如下,並將其定義爲score:
score(yA,B)=wJFJ(x,y))=wi=2TfJ(xi,yi,yi1)=B1,y1+i=2T(Bi,yi+Ayi1,yi)\begin{aligned} score(y|A,B) &=\boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} ( x , y ) )\\ &=\boldsymbol { w } \cdot \sum_{i=2}^Tf_{|J|}(x_i, y_i, y_{i-1})\\ &=B_{1, y_1}+\sum_{i=2}^T(B_{i,y_i} + A_{y_{i-1},y_i}) \end{aligned}

理解了這兩個特徵,就成功的將CRF於NER任務結合了。下面要知道如何估計特徵參數,即反向傳播A和B。

2.2 參數估計

對於一個訓練樣本,有一個輸入序列x和一個tag序列y。x經過LSTM層得到特徵矩陣B。
我們的目標是求現有參數下的概率p(yA,B)p(\boldsymbol y|A, B),並最大化這個值,按照老規矩使用其負對數作爲loss, 回到log-linear model的定義,:
loss=log(p(yA,B))=log(exp(score(yA,B))y^exp(score(y^A,B)))=log(y^exp(score(y^A,B)))score(yA,B)=log_sum_exp(score(y^A,B)))\begin{aligned} loss &= -log(p(\boldsymbol y|A,B) )\\ &= -log(\frac{exp(score(y|A,B))}{\sum_{\hat y}exp(score(\hat y|A,B))})\\ &=log(\sum_{\hat y}exp(score(\hat y|A,B))) - score(y|A,B)\\ &=log\_sum\_exp(score(\hat y|A,B))) \end{aligned}

一旦loss確定,剩下的事就可以交給pytorch框架來自動優化了。但是上面這個loss怎麼計算呢?score(yA,B)score(y|A,B)這一項好說,線性複雜度O(T)。

2.3 全局正則項的計算推導

Z=log(y^exp(score(y^A,B)))Z = log(\sum_{\hat y}exp(score(\hat y|A,B)))這一項,如果用暴力計算,就是要先算出每一個時間步的所有可能路徑,複雜度爲O(TnT)O(Tn^T), 分類數稍多一點就會涼。需要想辦法消掉指數複雜度,而很巧的是,這確實可以在輸入序列上轉換爲子問題,從而使用動態規劃算法。根據上述score的計算公式,可以將輸入序列長度爲TT的正則項寫爲:
Z=log(y^exp(score(y^(1,T1)A,B)+score(y^(T1,T)A,B)))=log(y^(escore(y^(1,T1)A,B)escore(y^(T1,T)A,B)))Z=log(\sum_{\hat y}exp(score(\hat y^{(1,T-1)}|A,B)+score(\hat y^{(T-1,T)}|A,B)))\\ =log(\sum_{\hat y}(e^{score(\hat y^{(1,T-1)}|A,B)}\cdot e^{score(\hat y^{(T-1,T)}|A,B)}))
注意這裏score(y^(T1,T)A,B)=BT,yT+AyT1,yTscore(\hat y^{(T-1,T)}|A,B)=B_{T,y_T} + A_{y_{T-1},y_T},表示所有路徑在第T-1到第T步的分數,將其作爲係數,合併同類項:
Z(T)=log(escore(y^(T1,T)A,B))y^(escore(y^(1,T1)A,B))=Z(T1)+log_sum_exp(score(y^(T1,T)A,B))Z^{(T)}=log(\sum e^{score(\hat y^{(T-1,T)}|A,B)}) \sum_{\hat y}(e^{score(\hat y^{(1,T-1)}|A,B)})\\ =Z^{(T-1)}+log\_sum\_exp(score(\hat y^{(T-1,T)}|A,B))
到這裏就該知道是標準的動態規劃了。

參考文獻

  1. Pytorch Bi-LSTM + CRF 代碼詳解
  2. Bi-LSTM-CRF for Sequence Labeling
  3. Bi-LSTM Conditional Random Field Discussion
  4. 系列文章:CRF Layer on the Top of BiLSTM - 5
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章