Hanlp中使用純JAVA實現CRF分詞
Hanlp中使用純JAVA實現CRF分詞
與基於隱馬爾可夫模型的最短路徑分詞、N-最短路徑分詞相比,基於條件隨機場(CRF)的分詞對未登入詞有更好的支援。本文(HanLP)使用純Java實現CRF模型的讀取與維特比後向解碼,內部特徵函式採用 雙陣列Trie樹(DoubleArrayTrie)儲存,得到了一個高效能的中文分詞器。
開源專案
本文程式碼已整合到HanLP中開源:http://hanlp.com/
CRF簡介
CRF是序列標註場景中常用的模型,比HMM能利用更多的特徵,比MEMM更能抵抗標記偏置的問題。
CRF訓練
這類耗時的任務,還是交給了用C++實現的CRF++。關於
CRF解碼
解碼採用維特比演算法實現。並且稍有改進,用中文偽碼與白話描述如下:
首先任何字的標籤不僅取決於它自己的引數,還取決於前一個字的標籤。但是第一個字前面並沒有字,何來標籤?所以第一個字的處理稍有不同,假設第0個字的標籤為X,遍歷X計算第一個字的標籤,取分數最大的那一個。
如何計算一個字的某個標籤的分數呢?某個字根據CRF模型提供的模板生成了一系列特徵函式,這些函式的輸出值乘以該函式的權值最後求和得出了一個分數。該分數只是“點函式”的得分,還需加上“邊函式”的得分。邊函式在本分詞模型中簡化為f(s',s),其中s'為前一個字的標籤,
實現了評分函式後,從第二字開始即可運用維特比後向解碼,為所有字打上BEMS標籤。
例項
還是取經典的“商品和服務”為例,首先HanLP的CRFSegment分詞器將其拆分為一張表:
null表示分詞器還沒有對該字標註。
程式碼
上面說了這麼多,其實我的實現非常簡練:
標註結果
標註後將table打印出來:
最終處理
將BEMS該合併的合併,得到:
然後將詞語送到詞典中查詢一下,沒查到的暫時當作nx,並記下位置(因為這是個新詞,為了表示它的特殊性,最後詞性設為null
新詞識別
CRF對新詞有很好的識別能力,比如:
輸出:
null表示新詞。
轉載自hankcs的部落格