?CRF簡介
CRF是序列標注場景中常用的模型,比HMM能利用更多的特征,比MEMM更能抵抗標記偏置的問題。
[gerative-discriminative.png]?
CRF訓練
這類耗時的任務,還是交給了用C++實現的CRF++。關于CRF++輸出的CRF模型,請參考《CRF++模型格式說明》。?
CRF解碼
解碼采用維特比算法實現。并且稍有改進,用中文偽碼與白話描述如下:
首先任何字的標簽不僅取決于它自己的參數,還取決于前一個字的標簽。但是第一個字前面并沒有字,何來標簽?所以第一個字的處理稍有不同,假設第0個字的標簽為X,遍歷X計算第一個字的標簽,取分數最大的那一個。
如何計算一個字的某個標簽的分數呢?某個字根據CRF模型提供的模板生成了一系列特征函數,這些函數的輸出值乘以該函數的權值最后求和得出了一個分數。該分數只是“點函數”的得分,還需加上“邊函數”的得分。邊函數在本分詞模型中簡化為f(s’,s),其中s’為前一個字的標簽,s為當前字的標簽。于是該邊函數就可以用一個4*4的矩陣描述,相當于HMM中的轉移概率。
實現了評分函數后,從第二字開始即可運用維特比后向解碼,為所有字打上BEMS標簽。?
實例
還是取經典的“商品和服務”為例,首先HanLP的CRFSegment分詞器將其拆分為一張表:
?
?
null表示分詞器還沒有對該字標注。
代碼
上面說了這么多,其實我的實現非常簡練:
?
?
?
標注結果
標注后將table打印出來:
?
最終處理
?
將BEMS該合并的合并,得到:
[商品/null, 和/null, 服務/null]
然后將詞語送到詞典中查詢一下,沒查到的暫時當作nx,并記下位置(因為這是個新詞,為了表示它的特殊性,最后詞性設為null),再次使用維特比標注詞性:
[商品/n, 和/cc, 服務/vn]
新詞識別
?
CRF對新詞有很好的識別能力,比如:
CRFSegment segment = new CRFSegment();
segment.enablePartOfSpeechTagging(true);
System.out.println(segment.seg("你看過穆赫蘭道嗎"));
輸出:
?
CRF標注結果
你 ??S ??
看 ??S ??
過 ??S ??
穆 ??B ??
赫 ??M ??
蘭 ??M ??
道 ??E ??
嗎 ??S ??
[你/rr, 看/v, 過/uguo, 穆赫蘭道/null, 嗎/y]
?
null表示新詞。
?