基於結構化平均感知機的分詞器Java實現
基於結構化平均感知機的分詞器 Java實現
最近高產似母豬,寫了個基於 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新版本已經發布,可以去新版本查到看使用 】
結構化預測
關於結構化預測和非結構化預測的區別一張講義說明如下:
更多知識請參考 Neubig的講義《The Structured Perceptron》。
本文實現的 AP分詞器預測是整個句子的BMES標註序列,當然屬於結構化預測問題了。
感知機
二分類
感知機的基礎形式如《統計學習方法》所述,是定義在一個超平面上的線性二分類模型。作為原著第二章,實在是簡單得不能再簡單了。然而實際運用中,越簡單的模型往往生命力越頑強。
這裡唯一需要補充的是,感知機是個線上學習模型,學習一個訓練例項後,就可以更新整個模型。
多分類
怎麼把二分類擴充到多分類呢?可以用多個分類器,對於 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
鄧知龍 《基於感知器演算法的高效中文分詞與詞性標註系統設計與實現》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31524777/viewspace-2554485/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 分詞工具Hanlp基於感知機的中文分詞框架HanLP中文分詞框架
- 基於結構化感知機的詞性標註與命名實體識別框架詞性標註框架
- 雙向最大匹配演算法——基於詞典規則的中文分詞(Java實現)演算法中文分詞Java
- [Python] 基於 jieba 的中文分詞總結PythonJieba中文分詞
- 怎樣實現基於Trie樹和字典的分詞功能分詞
- 【Golang】基於beego/orm實現相同表結構不同表名的分表方法實現GolangORM
- 手寫實現java棧結構,並實現簡易的計算器(基於字尾演算法)Java演算法
- Java關於資料結構的實現:樹Java資料結構
- MapReduce實現與自定義詞典檔案基於hanLP的中文分詞詳解HanLP中文分詞
- 基於感知機的人名-性別預測系統 —— Python實現Python
- ElasticSearch中使用ik分詞器進行實現分詞操作Elasticsearch分詞
- torch--多層感知機實現影像分類
- Java關於資料結構的實現:雜湊Java資料結構
- 編譯器前端之如何實現基於DFA的詞法分析器編譯前端詞法分析
- 中文分詞工具之基於字標註法的分詞中文分詞
- 使用cjieba(結巴分詞庫)實現php擴充套件中文分詞JiebaPHP套件中文分詞
- Hanlp中使用純JAVA實現CRF分詞HanLPJavaCRF分詞
- elasticsearch之ik分詞器和自定義詞庫實現Elasticsearch分詞
- 感知機簡單實現
- 基於Java+SpringBoot+Mysql實現的古詩詞平臺功能設計與實現三JavaSpring BootMySql
- 基於hanlp的es分詞外掛HanLP分詞
- 基於sklearn的分類器實戰
- 基於Java Instrument的Agent實現Java
- NLP segment-03-基於 TF-IDF 實現關鍵詞提取 java 開源實現Java
- 62_索引管理_快速上機動手實戰修改分詞器以及定製自己的分詞器索引分詞
- 基於 HanLP 的 ES 中文分詞外掛HanLP中文分詞
- HanLP-實詞分詞器詳解HanLP分詞
- 樹結構與Java實現Java
- Java + SikuliX 基於影像實現自動化測試Java
- Hanlp分詞例項:Java實現TFIDF演算法HanLP分詞Java演算法
- 基於Sharding-Jdbc 實現的讀寫分離實現JDBC
- Android Gradle基於引數化配置實現差異化構建AndroidGradle
- 基於ARouter的Android元件化實現Android元件化
- Java實現資料結構之線性結構Java資料結構
- 基於 Probot 實現 GitHub NPM 釋出機器人?GithubNPM機器人
- 基於零信任架構的IDaaS實現架構
- php基於redis的list型資料結構實現ip限流操作PHPRedis資料結構
- 谷歌機器學習實戰的7個步驟:用於結構化資料的TensorFlow示例谷歌機器學習