fastText原理及實踐
fastText是Facebook於2016年開源的一個詞向量計算和文字分類工具,在學術上並沒有太大創新。 但是它的優點也非常明顯, 在文字分類任務中,fastText(淺層網路)往往能取得和深度網路相媲美的精度,卻在訓練時間上比深度網路快許多數量級。在標準的多核CPU上, 能夠訓練10億詞級別語料庫的詞向量在10分鐘之內,能夠分類有著30萬多類別的50多萬句子在1分鐘之內。
本文首先會介紹一些預備知識,比如softmax、ngram等,然後簡單介紹word2vec原理,之後來講解fastText的原理,並著手使用keras搭建一個簡單的fastText分類器,最後,我們會介紹fastText在達觀資料的應用。
NO.1 預備知識
1 Softmax迴歸
Softmax迴歸(Softmax Regression)又被稱作多項邏輯迴歸(multinomial logistic regression),它是邏輯迴歸在處理多類別任務上的推廣。
在邏輯迴歸中, 我們有m個被標註的樣本: ,其中
。因為類標是二元的,所以我們有
Line"/> 。我們的假設(hypothesis)有如下形式:
代價函式(cost function)如下:
在Softmax迴歸中,類標是大於2的,因此在我們的訓練集
中, 。給定一個測試輸入x,我們的假設應該輸出一個K維的向量,向量內每個元素的值表示x屬於當前類別的概率。具體地,假設
形式如下:
代價函式如下:
其中1{·}是指示函式,即1=1,1=0
既然我們說Softmax迴歸是邏輯迴歸的推廣,那我們是否能夠在代價函式上推匯出它們的一致性呢?當然可以,於是:
可以看到,邏輯迴歸是softmax迴歸在K=2時的特例。
2 分層Softmax
你可能也發現了,標準的Softmax迴歸中,要計算y=j時的Softmax概率: ,我們需要對所有的K個概率做歸一化,這在|y|很大時非常耗時。於是,分層Softmax誕生了,它的基本思想是使用樹的層級結構替代扁平化的標準Softmax,使得在計算
時,只需計算一條路徑上的所有節點的概率值,無需在意其它的節點。
下圖是一個分層Softmax示例:
樹的結構是根據類標的頻數構造的霍夫曼樹。K個不同的類標組成所有的葉子節點,K-1個內部節點作為內部引數,從根節點到某個葉子節點經過的節點和邊形成一條路徑,路徑長度被表示為 。於是,
就可以被寫成:
其中:
表示sigmoid函式;
表示n節點的左孩子;
是一個特殊的函式,被定義為:
是中間節點
的引數;X是Softmax層的輸入。
上圖中,高亮的節點和邊是從根節點到 的路徑,路徑長度
可以被表示為:
於是,從根節點走到葉子節點 ,實際上是在做了3次二分類的邏輯迴歸。
通過分層的Softmax,計算複雜度一下從|K|降低到log|K|。
3 n-gram特徵
在文字特徵提取中,常常能看到n-gram的身影。它是一種基於語言模型的演算法,基本思想是將文字內容按照位元組順序進行大小為N的滑動視窗操作,最終形成長度為N的位元組片段序列。看下面的例子:
我來到達觀資料參觀
相應的bigram特徵為:
我來 來到 到達 達觀 觀數 資料 據參 參觀
相應的trigram特徵為:
我來到 來到達 到達觀 達觀數 觀資料 資料參 據參觀
注意一點:n-gram中的gram根據粒度不同,有不同的含義。它可以是字粒度,也可以是詞粒度的。上面所舉的例子屬於 字粒度 的n-gram, 詞粒度 的n-gram看下面例子:
我 來到達觀資料參觀
相應的bigram特徵為:
我/來到 來到/達觀資料達觀資料/參觀
相應的trigram特徵為:
我/來到/達觀資料來到/達觀資料/參觀
n-gram產生的特徵只是作為文字特徵的候選集,你後面可能會採用資訊熵、卡方統計、IDF等文字特徵選擇方式篩選出比較重要特徵。
NO.2 Word2vec
你可能要問,這篇文章不是介紹fastText的麼,怎麼開始介紹起了word2vec?
最主要的原因是word2vec的CBOW模型架構和fastText模型非常相似。 於是,你看到facebook開源的fastText工具不僅實現了fastText文字分類工具,還實現了快速詞向量訓練工具。word2vec主要有兩種模型:skip-gram 模型和CBOW模型,這裡只介紹CBOW模型。
1 模型架構
CBOW模型的基本思路是:用上下文預測目標詞彙。架構圖如下所示:
輸入層由目標詞彙y的上下文單詞 組成,
是被onehot編碼過的V維向量,其中V是詞彙量;隱含層是N維向量h;輸出層是被onehot編碼過的目標詞y。輸入向量通過
維的權重矩陣W連線到隱含層;隱含層通過
維的權重矩陣
連線到輸出層。因為詞庫V往往非常大,使用標準的softmax計算相當耗時,於是CBOW的輸出層採用的正是上文提到過的分層Softmax。
2 前向傳播
輸入是如何計算而獲得輸出呢?先假設我們已經獲得了權重矩陣 和
(具體的推導見第3節),隱含層h的輸出的計算公式:
即:隱含層的輸出是C個上下文單詞向量的加權平均,權重為 W 。
接著我們計算輸出層的每個節點:
這裡 是矩陣
的第j列,最後,將
作為softmax函式的輸入,得到
:
3 反向傳播學習權重矩陣
在學習權重矩陣和過程中,我們首先隨機產生初始值,然後feed訓練樣本到我們的模型,並觀測我們期望輸出和真實輸出的誤差。接著,我們計算誤差關於權重矩陣的梯度,並在梯度的方向糾正它們。
首先 定義損失函式 ,objective是最大化給定輸入上下文,target單詞的條件概率。因此,損失函式為:
這裡, 表示目標單詞在詞庫V中的索引。
如何 更新權重 ?
我們先對E關於 求導:
函式表示:
於是, 的更新公式:
如何更新權重 W ?
我們首先計算E關於隱含層節點的導數:
然後,E關於權重的導數為:
於是, 的更新公式:
NO.3fastText分類
終於到我們的fastText出場了。這裡有一點需要特別注意,一般情況下,使用fastText進行文字分類的同時也會產生詞的embedding,即embedding是fastText分類的產物。除非你決定使用預訓練的embedding來訓練fastText分類模型,這另當別論。
1 字元級別的n-gram
word2vec把語料庫中的每個單詞當成原子的,它會為每個單詞生成一個向量。這忽略了單詞內部的形態特徵,比如:“apple” 和“apples”,“達觀資料”和“達觀”,這兩個例子中,兩個單詞都有較多公共字元,即它們的內部形態類似,但是在傳統的word2vec中,這種單詞內部形態資訊因為它們被轉換成不同的id丟失了。
為了克服這個問題,fastText使用了字元級別的n-grams來表示一個單詞。 對於單詞“apple”,假設n的取值為3,則它的trigram有:
“<ap”, “app”, “ppl”, “ple”, “le>”
其中,<表示字首,>表示字尾。於是,我們可以用這些trigram來表示“apple”這個單詞,進一步,我們可以用這5個trigram的向量疊加來表示“apple”的詞向量。
這帶來兩點好處:
1. 對於低頻詞生成的詞向量效果會更好。因為它們的n-gram可以和其它詞共享。
2. 對於訓練詞庫之外的單詞,仍然可以構建它們的詞向量。我們可以疊加它們的字元級n-gram向量。
2 模型架構
之前提到過,fastText模型架構和word2vec的CBOW模型架構非常相似。下面是fastText模型架構圖:
注意:此架構圖沒有展示詞向量的訓練過程。可以看到,和CBOW一樣,fastText模型也只有三層:輸入層、隱含層、輸出層(Hierarchical Softmax),輸入都是多個經向量表示的單詞,輸出都是一個特定的target,隱含層都是對多個詞向量的疊加平均。
不同的是,CBOW的輸入是目標單詞的上下文,fastText的輸入是多個單詞及其n-gram特徵,這些特徵用來表示單個文件;CBOW的輸入單詞被onehot編碼過,fastText的輸入特徵是被embedding過;CBOW的輸出是目標詞彙,fastText的輸出是文件對應的類標。
值得注意的是,fastText在輸入時,將單詞的字元級別的n-gram向量作為額外的特徵;在輸出時,fastText採用了分層Softmax,大大降低了模型訓練時間。 這兩個知識點在前文中已經講過,這裡不再贅述。
fastText相關公式的推導和CBOW非常類似,這裡也不展開了。
3 核心思想
現在拋開那些不是很討人喜歡的公式推導,來想一想fastText文字分類的核心思想是什麼?
仔細觀察模型的後半部分,即從隱含層輸出到輸出層輸出,會發現它就是一個softmax線性多類別分類器,分類器的輸入是一個用來表徵當前文件的向量;模型的前半部分,即從輸入層輸入到隱含層輸出部分,主要在做一件事情:生成用來表徵文件的向量。那麼它是如何做的呢?疊加構成這篇文件的所有詞及n-gram的詞向量,然後取平均。疊加詞向量背後的思想就是傳統的詞袋法,即將文件看成一個由詞構成的集合。
於是fastText的核心思想就是:將整篇文件的詞及n-gram向量疊加平均得到文件向量,然後使用文件向量做softmax多分類。 這中間涉及到兩個技巧:字元級n-gram特徵的引入以及分層Softmax分類。
4 關於分類效果
還有個問題,就是為何fastText的分類效果常常不輸於傳統的非線性分類器?
假設我們有兩段文字:
我 來到達觀資料
俺 去了 達而觀資訊科技
這兩段文字意思幾乎一模一樣,如果要分類,肯定要分到同一個類中去。但在傳統的分類器中,用來表徵這兩段文字的向量可能差距非常大。傳統的文字分類中,你需要計算出每個詞的權重,比如tfidf值, “我”和“俺” 算出的tfidf值相差可能會比較大,其它詞類似,於是,VSM(向量空間模型)中用來表徵這兩段文字的文字向量差別可能比較大。
但是fastText就不一樣了,它是用單詞的embedding疊加獲得的文件向量,詞向量的重要特點就是向量的距離可以用來衡量單詞間的語義相似程度 ,於是,在fastText模型中,這兩段文字的向量應該是非常相似的,於是,它們很大概率會被分到同一個類中。
使用詞embedding而非詞本身作為特徵,這是fastText效果好的一個原因;另一個原因就是 字元級n-gram特徵的引入對分類效果會有一些提升 。
NO.4 手寫一個fastText
keras是一個抽象層次很高的神經網路API,由python編寫,底層可以基於Tensorflow、Theano或者CNTK。它的優點在於:使用者友好、模組性好、易擴充套件等。所以下面我會用keras簡單搭一個fastText的demo版,生產可用的fastText請移步https://github.com/facebookresearch/fastText。
如果你弄懂了上面所講的它的原理,下面的demo對你來講應該是非常明瞭的。
為了簡化我們的任務:
1. 訓練詞向量時,我們使用正常的word2vec方法,而真實的fastText還附加了字元級別的n-gram作為特徵輸入;
2. 我們的輸出層使用簡單的softmax分類,而真實的fastText使用的是Hierarchical Softmax。
首先定義幾個常量:
VOCAB_SIZE = 2000
EMBEDDING_DIM =100
MAX_WORDS = 500
CLASS_NUM = 5
VOCAB_SIZE表示詞彙表大小,這裡簡單設定為2000;
EMBEDDING_DIM表示經過embedding層輸出,每個詞被分散式表示的向量的維度,這裡設定為100。比如對於“達觀”這個詞,會被一個長度為100的類似於[ 0.97860014, 5.93589592, 0.22342691, -3.83102846, -0.23053935, …]的實值向量來表示;
MAX_WORDS表示一篇文件最多使用的詞個數,因為文件可能長短不一(即詞數不同),為了能feed到一個固定維度的神經網路,我們需要設定一個最大詞數,對於詞數少於這個閾值的文件,我們需要用“未知詞”去填充。比如可以設定詞彙表中索引為0的詞為“未知詞”,用0去填充少於閾值的部分;
CLASS_NUM表示類別數,多分類問題,這裡簡單設定為5。
模型搭建遵循以下步驟:
1. 新增輸入層(embedding層) 。Embedding層的輸入是一批文件,每個文件由一個詞彙索引序列構成。例如:[10, 30, 80, 1000] 可能表示“我 昨天 來到達觀資料”這個短文字,其中“我”、“昨天”、“來到”、“達觀資料”在詞彙表中的索引分別是10、30、80、1000;Embedding層將每個單詞對映成EMBEDDING_DIM維的向量。於是:input_shape=(BATCH_SIZE, MAX_WORDS), output_shape=(BATCH_SIZE,MAX_WORDS, EMBEDDING_DIM);
2. 新增隱含層(投影層) 。投影層對一個文件中所有單詞的向量進行疊加平均。keras提供的GlobalAveragePooling1D類可以幫我們實現這個功能。這層的input_shape是Embedding層的output_shape,這層的output_shape=( BATCH_SIZE, EMBEDDING_DIM);
3. 新增輸出層(softmax層) 。真實的fastText這層是Hierarchical Softmax,因為keras原生並沒有支援Hierarchical Softmax,所以這裡用Softmax代替。這層指定了CLASS_NUM,對於一篇文件,輸出層會產生CLASS_NUM個概率值,分別表示此文件屬於當前類的可能性。這層的output_shape=(BATCH_SIZE, CLASS_NUM)
4. 指定損失函式、優化器型別、評價指標,編譯模型 。損失函式我們設定為categorical_crossentropy,它就是我們上面所說的softmax迴歸的損失函式;優化器我們設定為SGD,表示隨機梯度下降優化器;評價指標選擇accuracy,表示精度。
用訓練資料feed模型時,你需要:
1. 將文件分好詞,構建詞彙表 。詞彙表中每個詞用一個整數(索引)來代替,並預留“未知詞”索引,假設為0;
2. 對類標進行onehot化 。假設我們文字資料總共有3個類別,對應的類標分別是1、2、3,那麼這三個類標對應的onehot向量分別是[1, 0,0]、[0, 1, 0]、[0, 0, 1];
3. 對一批文字,將每個文字轉化為詞索引序列,每個類標轉化為onehot向量 。就像之前的例子,“我 昨天 來到達觀資料”可能被轉化為[10, 30,
80, 1000];它屬於類別1,它的類標就是[1, 0, 0]。由於我們設定了MAX_WORDS=500,這個短文字向量後面就需要補496個0,即[10, 30, 80, 1000, 0, 0, 0, …, 0]。因此,batch_xs的 維度為( BATCH_SIZE,MAX_WORDS),batch_ys的維度為(BATCH_SIZE, CLASS_NUM)。
下面是構建模型的程式碼,資料處理、feed資料到模型的程式碼比較繁瑣,這裡不展示。
NO.5fastText在達觀資料的應用
fastText作為誕生不久的詞向量訓練、文字分類工具,在達觀得到了比較深入的應用。主要被用在以下兩個系統:
1. 同近義詞挖掘。Facebook開源的fastText工具也實現了詞向量的訓練,達觀基於各種垂直領域的語料,使用其挖掘出一批同近義詞;
2.文字分類系統。 在類標數、資料量都比較大時,達觀會選擇fastText來做文字分類,以實現快速訓練預測、節省記憶體的目的。
關於作者
王江,達觀資料自然語言處理工程師,負責達觀NLP底層開發、私有化應用系統開發等工作。主要參與大型系統的開發,對機器學習、NLP等領域有濃厚興趣。