CRF++/CRF/條件隨機場的特徵函式模板
由於最近想實現CRF,學完了理論後就開始怎麼想怎麼實現,想參照CRF++的開源實現,但首先要解決的怎麼理解特徵模板,所以寫了此文,主要參考了2篇文章,在此感謝。
-
CRF++要求的訓練資料格式
對於訓練資料,首先需要多列,但不能不一致,既在一個檔案裡有的行是兩列,有的行是三列;其次第一列代表的是需要標註的“字或詞”,最後一列是輸出位"標記tag",如果有額外的特徵,例如詞性什麼的,可以加到中間列裡,所以訓練集或者測試集的檔案最少要有兩列。
例如:下面所有例子都是以下列的分詞資料舉例
2.關於特徵模板
CRF++的特徵模板通常長下面這個樣子:
“%x[行位置,
先來解釋以下Unigram特徵模板是什麼意思。
舉例:U00:%x[-2,0]
行-2代表是當前行的之前的第2個字元(觀測),
0代表第2列,如果遍歷到的行如下圖:
圖3.10.1
將產生以下的特徵函式:(注:下列偽碼的x代表觀測,y代表狀態,也就是貼的標籤)
If(y==’B’&&x==’人’) return 1 else return 0;
If(y==’E’&&x==’人’) return 1 else return 0;
If(y==’M’&&x==’人’) return 1 else return 0;
If(y==’S’&&x==’人’) return 1 else return 0;
算一算將產生4*65536(4是狀態個數,65536是不同字元的個數),如果狀態數和觀測數一樣這就對應於HMM的發射矩陣。
這什麼意思呢?學過HMM的知道,這類似於發射矩陣,統計狀態下的觀測分佈。
有人可能要問?U01:%x[-1,0],U02:%x[0,0]這2個會重複統計吧?確實是啊,目前我還不清楚為什麼這樣,我猜想這裡要表達的是,當前狀態下的觀測分佈不僅僅受當前觀測字元的影響,還受前第2個U02:%x[0,0],前第1個U01:%x[-1,0],後1個U03:%x[1,0]等的影響。
至於下面這種特徵模板:
我想是統計當前狀態下,視窗為3周圍觀測的分佈,
以圖3.10.1舉例產生下面的特徵函式:
if(x1==’民’&&x2==’網’&x3==’1’&y==’B’) return 1 else return 0;
if(x1==’民’&&x2==’網’&x3==’1’&y==’M’) return 1 else return 0;
if(x1==’民’&&x2==’網’&x3==’1’&y==’E’) return 1 else return 0;
if(x1==’民’&&x2==’網’&x3==’1’&y==’S’) return 1 else return 0;
這樣想想確實CRF比HMM一個發射矩陣表達了更多的資訊。
令人疑惑的是Bigram並沒有直接定義模板函式,只寫了一個B(如上圖),我在HanLp作者的部落格中找到這樣的解釋。如果只寫一個B的話,預設生成f(s', s),其中s'為t – 1時刻的標籤.也就是說,Bigram型別與Unigram大致機同,只是還要考慮到t – 1時刻的標籤.這意味著前一個output token和current token將組合成bigram features。
這樣的話唯一一個bigram特徵模板的所有特徵函式類似於HMM中的轉移矩陣。
還是以圖3.10.1舉例,將產生下列的特徵函式:下面y1是前一個狀態,y2是後一個狀態。
If(y1==’B’&&y2==’B’) return 1 else return 0; 當然這個特徵函式應該是不合理的,當前字元是Begin的狀態,下一個只能是Middle或者End。我們暫時不考慮是否演算法實現考慮了這個特徵函式,因為我也沒具體實現。
If(y1==’B’&&y2==’B’) return 1 else return 0;
If(y1==’B’&&y2==’M’) return 1 else return 0;
If(y1==’B’&&y2==’E’) return 1 else return 0;
If(y1==’B’&&y2==’S’) return 1 else return 0;
If(y1==’M’&&y2==’B’) return 1 else return 0;
If(y1==’M’&&y2==’M’) return 1 else return 0;
If(y1==’M’&&y2==’E’) return 1 else return 0;
If(y1==’M’&&y2==’S’) return 1 else return 0;
If(y1==’E’&&y2==’B’) return 1 else return 0;
If(y1==’E’&&y2==’M’) return 1 else return 0;
If(y1==’E’&&y2==’E’) return 1 else return 0;
If(y1==’E’&&y2==’S’) return 1 else return 0;
If(y1==’S’&&y2==’B’) return 1 else return 0;
If(y1==’S’&&y2==’M’) return 1 else return 0;
If(y1==’S’&&y2==’E’) return 1 else return 0;
If(y1==’S’&&y2==’S’) return 1 else return 0;
暫時學到這兒,等我實現了這個演算法將補充細節或者修正。