基於結構化平均感知機的分詞器Java實現算法
做者:hankcs性能
最近高產似母豬,寫了個基於AP的中文分詞器,在Bakeoff-05的MSR語料上F值有96.11%。最重要的是,只訓練了5個迭代;包含語料加載等IO操做在內,整個訓練一共才花費23秒。應用裁剪算法去掉模型中80%的特徵後,F值才降低不到0.1個百分點,體積控制在11兆。若是訓練一百個迭代,F值可達到96.31%,訓練時間兩分多鐘。學習
數據在一臺普通的IBM兼容機上獲得:優化
本模塊已集成到HanLP 1.6以上版本開源,文檔位於項目wiki中,歡迎使用!【hanlp1.7新版本已經發布,能夠去新版本查到看使用】spa
結構化預測設計
關於結構化預測和非結構化預測的區別一張講義說明以下:blog
更多知識請參考Neubig的講義《The Structured Perceptron》。文檔
本文實現的AP分詞器預測是整個句子的BMES標註序列,固然屬於結構化預測問題了。原型
感知機it
二分類
感知機的基礎形式如《統計學習方法》所述,是定義在一個超平面上的線性二分類模型。做爲原著第二章,實在是簡單得不能再簡單了。然而實際運用中,越簡單的模型每每生命力越頑強。
這裏惟一須要補充的是,感知機是個在線學習模型,學習一個訓練實例後,就能夠更新整個模型。
多分類
怎麼把二分類拓展到多分類呢?能夠用多個分類器,對於BMES這4種分類,就是4個感知機了。每一個感知機分別負責分辨「是否是B」「是否是M」「是否是E」「是否是S」這4個二分類問題。在實現中,固然沒必要傻乎乎地建立4個感知機啦。把它們的權值向量拼接在一塊兒,就能夠輸出「是B的分數」「是M的分數」「是E的分數」「是S的分數」了。取其最大者,就能夠初步實現多分類。但在分詞中,還涉及到轉移特徵和HMM-viterbi搜索算法等,留到下文再說。
平均感知機
平均感知機指的是記錄每一個特徵權值的累計值,最後平均得出最終模型的感知機。爲何要大費周章搞個平均算法出來呢?
前面提到過,感知機是個在線學習模型,學習一個訓練實例後,就能夠更新整個模型。假設有10000個實例,模型在前9999個實例的學習中都完美地獲得正確答案,說明此時的模型接近完美了。但是最後一個實例是個噪音點,樸素感知機模型預測錯誤後直接修改了模型,致使前面9999個實例預測錯誤,模型訓練前功盡棄。
有什麼解決方案呢?一種方案是投票式的,即記錄每一個模型分類正確的次數,做爲它的得票。訓練結束時取得票最高的模型做爲最終模型。但這種算法是不實際的,若是訓練5個迭代,10000個實例,那麼就須要儲存50000個模型及其票數,太浪費了。
最好用的方法是平均感知機,將這50000個模型的權值向量累加起來,最後除以50000就好了,這樣任什麼時候候咱們只額外記錄了一個累加值,很是高效了。關於平均感知機的詳情請參考《200行Python代碼實現感知機詞性標註器》。雖然那篇文章是講解詞性標註的,但相信做爲萬物靈長的讀者必定擁有觸類旁通的泛化能力。
語言模型
HMM
咱們不是在講解感知機分詞嗎?怎麼跟HMM扯上關係了?
其實任何基於序列標註的分詞器都離不開隱馬爾科夫鏈,即BMES這四個標籤之間的Bigram(乃至更高階的n-gram)轉移機率。做爲其中一員的AP分詞器,也不例外地將前一個字符的標籤做爲了一個特徵。該特徵對預測當前的標籤毫無疑問是有用的,好比前一個標籤是B,當前標籤就毫不多是S。
這種相似於y[i-1]的特徵在線性圖模型中通常稱爲轉移特徵,而那些不涉及y[i-1]的特徵一般稱爲狀態特徵。
viterbi
因爲AP分詞器用到了轉移特徵,因此確定少不了維特比搜索。從序列全體的準確率考慮,搜索也是必不可少的。給定隱馬爾可夫模型的3要素,我用Java寫了一段「可運行的僞碼」:
上述實現是個重視條理勝於效率的原型,古人云「過早優化是魔鬼」。相信聰明的讀者必定能看懂這裏面在幹什麼。
特徵提取
定義字符序列爲x,標註序列爲y。
轉移特徵
轉移特徵就是上面說的y[i-1]。
狀態特徵
我一共使用了7種狀態特徵:
在鄧知龍的《基於感知器算法的高效中文分詞與詞性標註系統設計與實現》中提到,要利用更復雜的字符n-gram、字符類別n-gram、疊字、詞典等特徵。但在個人實踐中,除了上述7種特徵外,我每減小一個特徵,個人AP分詞器的準確率就提升一點,也許是語料不一樣吧,也許是特徵提取的實現不一樣。總之,主打精簡、高效。
訓練
迭代數目其實不須要太多,在3個迭代內模型基本就收斂了:
第4個迭代彷佛幫了倒忙,但萬幸的是,咱們使用的是平均感知機。權值平均以後,模型的性能反而有所提高。
此時模型大小:
模型裁剪
《基於感知器算法的高效中文分詞與詞性標註系統設計與實現》提到的模型裁剪策略是有效的,我將壓縮率設爲0.2,即壓縮掉20%的特徵,模型準確率沒有變化:
因爲我使用了隨機shuffle算法,因此每次訓練準確率都略有微小的上下波動。此時能夠看到模型裁剪過程花了額外的1分鐘,裁剪完畢後準確率維持96.11不變。
此時模型大小:
裁減掉50%如何呢?
此時模型大小:
可見裁剪了80%的特徵,體積從54M降低到11M,模型的準確率才跌了不到0.1個百分點!這說明大部分特徵都是沒用的,特徵裁剪很是有用、很是好用!
Reference
鄧知龍 《基於感知器算法的高效中文分詞與詞性標註系統設計與實現》