前言
最近在做一些意圖識別方面的工作,所以嘗試一下用 fasttext 做一個文本分類器,學習記錄如下。
簡介
首先,我們使用 fasttext 的目的是什麼?是文本分類,即對一個詞語,給出它所屬於的類別。
文本分類的目標是將文檔(如電子郵件,博文,短信,產品評論等)分爲一個或多個類別。 這些類別可以是根據評論分數,垃圾郵件與非垃圾郵件來劃分,或者文檔的編寫語言。 如今,構建這種分類器的主要方法是機器學習,即從樣本中學習分類規則。 爲了構建這樣的分類器,我們需要標註數據,它由文檔及其相應的類別(也稱爲標籤或標註)組成。
什麼是 fasttext 呢?
FastText 是 Facebook 開源的一款快速文本分類器,提供簡單而高效的文本分類和表徵學習的方法,精度接近深度模型但是速度更快。
原理
原理這部分要跳過了,因爲網上的原理文章特別多,如果各位感興趣的話可以移步 google 搜索或者文末相關文章。我在那裏放了幾個鏈接。
至於本文,首先網上的原理文章講的普遍都不錯。其次我對原理的瞭解程度完全不能讓我在這裏清楚的寫出來,畢竟我只是個可憐的工程師。實現它,幹上線纔是我的宿命。
實際應用
首先要理解,fasttext 只是一個工具包,怎麼使用它,用什麼方式來實現它都是可選的。這裏我選擇的是使用命令行來訓練模型,之後用 java 語言提供在線服務。當然你可以選擇使用各種語言來進行訓練和服務,因爲有多種語言的 fasttext 包。
下載安裝
我們可以直接下載正式發佈的某個版本,
wget https://github.com/facebookresearch/fastText/archive/v0.1.0.zip
unzip v0.1.0.zip
我個人更加推薦直接 clone 它在 github 上的項目,即執行:
git clone [email protected]:facebookresearch/fastText.git
之後進入他的目錄,執行 make
即可。
安裝完畢之後,可以直接執行不帶任何參數的命令,可以獲取相關的幫助手冊。
處理數據
官網的教程是使用 傳送門 的一部分數據進行訓練,這當然可以,但是我覺得大家可能更想看一些中文的訓練樣本。
首先給大家介紹一下訓練樣本的格式。如下:
__label__name 呼 延 十
__label__name 張 偉
__label__city 北京
__label__city 西安
文本文件的每一行都包含一條訓練樣本,其後是相應的文檔。 所有標籤都以 label 前綴開始,這就是 fastText 如何識別標籤或單詞是什麼。 然後對模型進行訓練,以預測給定文檔的標籤。
注意,當你生成你的樣本之後,需要區分開訓練集和測試集,一般情況下我們使用訓練:測試=8:2
的比例。
我個人的訓練樣本中,包含城市名 (area), 人名 (name), 以及其他一些標籤。訓練樣本 4 千萬條,測試樣本 1 千萬條。基本上使用已經確定的一些詞典生成。爲了提升效果,樣本儘可能準確,且數量儘量多一些。
訓練
執行下面的命令,然後你會看到類似於下面的輸出,等待運行完成(其中 input 是你的訓練數據,output 是你輸出的模型文件名稱):
./fasttext supervised -input data.train -output model_name
Read 0M words
Number of words: 14598
Number of labels: 734
Progress: 100.0% words/sec/thread: 75109 lr: 0.000000 loss: 5.708354 eta: 0h0m
訓練完成之後,你可以這樣運行你的測試集來查看一些關鍵指標:
其中 test 之後緊接着是你的模型文件以及測試數據集。下面的指標是精確率和召回率。這個在後面解釋。
./fasttext test model_name.bin data.test
N 3000
P@5 0.0668
R@5 0.146
Number of examples: 3000
爲了直觀的測試一些常見 case 的結果,我們可以運行命令,交互式的進行一些測試。我的一些測試如下:
.
調優
首先這是對精確度和召回率的定義。
精確度是由 fastText 所預測標籤中正確標籤的數量。 召回率是所有真實標籤中被成功預測出的標籤數量。 我們舉一個例子來說明這一點:
Why not put knives in the dishwasher?
在 Stack Exchange 上,這句話標有三個標籤:equipment,cleaning 和 knives。 模型預測出的標籤前五名可以通過以下方式獲得:
>> ./fasttext predict model_cooking.bin - 5
前五名是 food-safety, baking, equipment, substitutions and bread.
因此,模型預測的五個標籤中有一個是正確的,精確度爲 0.20。 在三個真實標籤中,只有 equipment 標籤被該模型預測出,召回率爲 0.33。
毫無疑問,不論我們的目的是不是識別多個標籤,這兩個數值我們都要儘量高一些。
優化樣本
我們的樣本是程序生成的,這樣理論上來說不能保證正確,最好是人工標註,當然人工標註千萬級別的數據比較難,那麼我們至少應該對樣本進行一些基本的清理,比如單字去掉,符號去掉,統一小寫等等操作。只要是與你的分類無關的數據理論上都應該去掉。
更多的迭代和更好的學習速率
簡而言之,就是一些運行參數的變化,我們讓程序訓練更多輪,且更優的學習速率,加上這兩個參數-lr 1.0 -epoch 25
, 當然你可以根據實際情況進行不斷的調整及測試。
使用 n-gram
這是一個額外提高,在剛纔的模型中,訓練的時候是沒有加上n-gram
特徵的,也就是沒有考慮詞序的因素。這裏可以 簡單瞭解 n-gram.
這是最終執行的訓練命令:
./fasttext supervised -input data.train -output ft_model -epoch 25 -lr 1.0 -wordNgrams 2 -bucket 200000 -dim 50 -loss hs
這是我在我的測試集上的精確率和召回率:
N 10997060
P@1 0.985
R@1 0.985
經過以上幾個簡單的步驟,識別準確度已經到了 98.5%, 這其實是一個不錯的效果了,因爲我目前沒有確定是否使用這個方案來進行實際應用,所以到了 98.5%之後也沒有繼續進行優化了,如果後續有優化,我會來更新這篇文章。將所用到的優化方法記錄下來。
demo
首先我們在 pom 文件中引入:
<dependency>
<groupId>com.github.vinhkhuc</groupId>
<artifactId>jfasttext</artifactId>
<version>0.4</version>
</dependency>
然後簡單的寫一下就好了:
import com.github.jfasttext.JFastText;
/**
* Created by pfliu on 2019/11/17.
*/
public class FastTextDemo {
public static void main(String [] args){
JFastText jt = new JFastText();
jt.loadModel("/tmp/ft_model_5.bin");
String ret = jt.predict("呼 延 十");
System.out.println(ret);
}
}
python 代碼,更加簡單了:
當然記得先安裝一下:pip3 install fasttext
.
相關文章
完。
ChangeLog
2019-11-17 完成以上皆爲個人所思所得,如有錯誤歡迎評論區指正。
歡迎轉載,煩請署名並保留原文鏈接。
聯繫郵箱:[email protected]
更多學習筆記見個人博客或關注微信公衆號 < 呼延十 >------>呼延十