【Hanlp源碼分析】基於感知機實現人名性別預測

【Hanlp源碼分析】基於感知機實現人名性別預測

本文是分析github中著名的開源NLP工業級代碼——hanlp的實現細節,其作者是何晗。

0.總結

Get to the points first. The article comes from LawsonAbs!

  • part1:感知機算法簡介
  • part2:【Hanlp源碼分析】基於感知機實現人名性別預測

1.什麼是感知機算法?

  • 屬於監督學習算法
    比如在後面給出的實戰代碼中,我們給出了人名對應的性別,會根據這個預測是否準確去完成一次更新操作。

  • 屬於迭代式算法
    每次讀入一個樣本,執行預測,將預測結果與正確答案進行對比,計算誤差,根據誤差更信模型參數。

2.有什麼用途?

  • 可以用於問題分類

3.有什麼利弊?

  • 模型過於簡單
    參數較少的模型就容易出現**“不擬合”**的情況,同時,也會因爲數個偏離點而對迭代更新的參數有很大的影響。從而難以準確的預測結果,造成較大偏差。

  • 迭代偏差
    這裏說的迭代偏差是因爲我們總是傾向於取最後一次迭代的模型。
    每次迭代都產生一個模型,而且每個模型的對應的每個參數不一定相同。如果我們單純的取最後一次迭代產生的模型作爲“最優模型”的話,很有可能是 “補了西牆,拆了東牆”

3.怎麼改進?

針對上面敘述的問題,對應的改進方法有投票感知機和平均感知機,分別簡單敘述一下。

3.1 投票感知機

3.1.1 思想

每次迭代都會產生一個不同參數的模型,那麼這些模型間的準確率就不一樣,把這個準確率稱之爲權重。根據各個模型的權重可以得到每個模型的加權平均值。根據各個模型的加權平均值與參數相乘,得到最終的一個模型。

3.1.2 缺點

  • 計算開銷大
  • 存儲開銷大

3.2 平均感知機

3.2.1 思想

每次迭代都會產生一個不同參數的模型,最後得到的模型就取每次迭代模型的一個平均。【這個平均其實指的是模型參數的平均】【《自然語言處理入門》這本書中講的是:取多個模型權重的平均。我不是很理解。】

3.2.2 特點

  • 好實現
  • 藉助一定的方法【累積參數和,而不是傻傻的每迭代一次就算一次平均】,可以避免存儲中間模型,可以以更少內存得到最終的模型

下面開始講第二部分,分析感知機算法中最簡單的【樸素感知機】的代碼實現。因爲原作者用的是Java,所以會涉及到一些Java的語法知識。後期我會造出 python 版的輪子。


4.主要類

4.1 NameGenderClassification

在這裏插入圖片描述main() 是入口函數, trainAndEvaluate()中會訓練模型【classifier.train(…)】,會將得到的模型進行效果評估【classifier.evaluate(…)】。

4.2 PerceptronClassifier

這個抽象類中實現了 上述的 train方法。如下所示:
在這裏插入圖片描述
這裏主要做了幾件事兒:

  • 初始化一個特徵字典(featureMap),這個就是將人名中除去姓氏的名字做一個映射。
  • 讀取語料庫【 reandInstance(corpus,featureMap)
    這是很重要的一部分內容,其關鍵問題是:如何把語料庫信息轉換爲數據信息? 下面慢慢談。
    (1)corpus是語料庫的地址,爲了便於測試,這裏我用了一個自己編輯的語料庫做訓練集。內容如下:
    在這裏插入圖片描述
    這裏傳入 featureMap 的原因就是因爲在讀取語料庫時 將特徵寫入Map中。在看如何將語料信息轉換爲數據信息之前,有必要了解一下 類 Instance 中的定義,這裏的 Instance就代表是語料庫中的一行數據。
    在這裏插入圖片描述
    這裏的 Instance 包含兩個屬性:
    (1)特徵向量
    (2)標籤【即應該得到的正確分類結果】
    這裏的特徵向量存在方式很特別。通常的文字轉向量採用的編碼方式有one-hot編碼,但是這裏採用的是記錄下標的方式。這樣做是爲了減少內存開銷,加速計算。
    下面我以上面的語料庫舉個例子:由 “范仲淹,男”這行數據,可以得到一個兩個特徵=> 仲和淹。因爲它們都是第一次出現,所以就直接放到 featureMap 中,得到的就是0和1,因爲范仲淹是男性,所以最終得到的 Instance 實例就是 x=[0,1], y=-1。其中 x是一個LinkedList 型的對象。
    在這裏插入圖片描述

extractFeature方法featureList中的值如下所示:仲對應0,淹對應1…後面同樣的道理。
在這裏插入圖片描述其中會調用的幾個方法如下:
addFeature方法
在這裏插入圖片描述
注意到 readInstance 方法返回的是一個 Instance 的數組。如果用Instance[] instArray = new Instance[200]; //直接使用 Instance[] 去直接生成一個數組將顯得有寫生硬且浪費。

  • 根據參數 averagePerceptron 選擇是進行何種訓練方式?我這裏就分析樸素感知機,其他的都很相似,除了平均感知機做了一個簡單的內存和計算優化,也沒啥的。
    這裏是最主要的內容。下面我們慢慢談。

在這裏插入圖片描述這裏的感知機機制就是: y=w*x + b。提煉一下就得到y = wx,因爲代碼中存儲的特徵是下標值【其實際含義是:該值下標對應的值爲1】,所以直接採用y+=parameter[f]的這種形式就可以得到一個模擬結果。數組parameter[] 的初始值賦爲0。代碼如下:
在這裏插入圖片描述如果預測結果部隊,則需要對該預測過程涉及到的參數進行更新:
在這裏插入圖片描述這裏的更新過程也是結合了相關的推導進行了簡化。因爲只有預測錯了纔會對參數進行更新。分類討論一下:
當預測結果爲-1,而正確結果爲1時,因爲特徵向量x的值不可變,且其恆爲正,所以我們可以將w的值變大,從而得到一個更大結果值,所以可以直接進行parameter[f]+=y操作;
相應的,當預測結果爲1時,可得到相反的結論。

  • 最後評價這個模型的效果【evaluate(instanceList)
    跑出的結果如下所示:
    在這裏插入圖片描述

因爲訓練集合就一點兒數據,所得到的準確率很低,當將訓練集換成正常的語料庫之後,可以得到一個很好的預測效果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章