使用FastText構建你的第一個文本分類器!

前言

最近在做一些意圖識別方面的工作,所以嘗試一下用 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 即可。

安裝完畢之後,可以直接執行不帶任何參數的命令,可以獲取相關的幫助手冊。

2019-11-17-21-15-46

處理數據

官網的教程是使用 傳送門 的一部分數據進行訓練,這當然可以,但是我覺得大家可能更想看一些中文的訓練樣本。

首先給大家介紹一下訓練樣本的格式。如下:

__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 的結果,我們可以運行命令,交互式的進行一些測試。我的一些測試如下:
2019-11-17-21-34-34
.

調優

首先這是對精確度和召回率的定義。

精確度是由 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 代碼,更加簡單了:

2019-11-17-22-18-12

當然記得先安裝一下:pip3 install fasttext.

相關文章

fastText 原理及實踐

自然語言處理中 n-gram 模型


完。

ChangeLog

2019-11-17 完成

以上皆爲個人所思所得,如有錯誤歡迎評論區指正。

歡迎轉載,煩請署名並保留原文鏈接。

聯繫郵箱:[email protected]

更多學習筆記見個人博客或關注微信公衆號 < 呼延十 >------>呼延十

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