文本處理——fastText原理及實踐(四)

博文地址:https://zhuanlan.zhihu.com/p/32965521

fastText是Facebook於2016年開源的一個詞向量計算和文本分類工具,在學術上並沒有太大創新。但是它的優點也非常明顯,在文本分類任務中,fastText(淺層網絡)往往能取得和深度網絡相媲美的精度,卻在訓練時間上比深度網絡快許多數量級。在標準的多核CPU上, 能夠訓練10億詞級別語料庫的詞向量在10分鐘之內,能夠分類有着30萬多類別的50多萬句子在1分鐘之內。


本文首先會介紹一些預備知識,比如softmax、ngram等,然後簡單介紹word2vec原理,之後來講解fastText的原理,並着手使用keras搭建一個簡單的fastText分類器,最後,我們會介紹fastText在達觀數據的應用。


1. 預備知識

(1)Softmax迴歸

Softmax迴歸(Softmax Regression)又被稱作多項邏輯迴歸(multinomial logistic regression),它是邏輯迴歸在處理多類別任務上的推廣。


在邏輯迴歸中, 我們有m個被標註的樣本: \left\{ (x^{(1)},y^{(1)}),..., (x^{(m)},y^{(m)}) \right\} ,其中 x^{(i)}∈R^{n} 。因爲類標是二元的,所以我們有 y^{(i)}∈\left\{ 0,1\right\} 。我們的假設(hypothesis)有如下形式:h_θ (x)=\frac{1}{1+e^{-θ^T x }}

代價函數(cost function)如下:


在Softmax迴歸中,類標是大於2的,因此在我們的訓練集\left\{ \left( x^{(1)}, y^{(1)}\right),...,\left( x^{(m)}, y^{(m)}\right) \right\} 中, y^{(i)}\in\left\{ 1,2,...,K \right\} 。給定一個測試輸入x,我們的假設應該輸出一個K維的向量,向量內每個元素的值表示x屬於當前類別的概率。具體地,假設 h_{\theta}(x) 形式如下:

代價函數如下:

其中1{·}是指示函數,即1{true}=1,1{false}=0


既然我們說Softmax迴歸是邏輯迴歸的推廣,那我們是否能夠在代價函數上推導出它們的一致性呢?當然可以,於是:

可以看到,邏輯迴歸是softmax迴歸在K=2時的特例。


(2)分層Softmax

你可能也發現了,標準的Softmax迴歸中,要計算y=j時的Softmax概率: P(y=j) ,我們需要對所有的K個概率做歸一化,這在|y|很大時非常耗時。於是,分層Softmax誕生了,它的基本思想是使用樹的層級結構替代扁平化的標準Softmax,使得在計算 P(y=j) 時,只需計算一條路徑上的所有節點的概率值,無需在意其它的節點。


下圖是一個分層Softmax示例:


樹的結構是根據類標的頻數構造的霍夫曼樹。K個不同的類標組成所有的葉子節點,K-1個內部節點作爲內部參數,從根節點到某個葉子節點經過的節點和邊形成一條路徑,路徑長度被表示爲 L(y_{j}) 。於是, P(y_{j}) 就可以被寫成:


其中:

\sigma(·) 表示sigmoid函數;

LC(n) 表示n節點的左孩子;

⟦x⟧ 是一個特殊的函數,被定義爲:

\theta_{n(y_{j},l)} 是中間節點 n(y_{j},l) 的參數;

X是Softmax層的輸入

上圖中,高亮的節點和邊是從根節點到 y_{2} 的路徑,路徑長度 L(y_{2})=4,P(y_{2}) 可以被表示爲:

於是,從根節點走到葉子節點 y_{2} ,實際上是在做了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等文本特徵選擇方式篩選出比較重要特徵。


2. word2vec

你可能要問,這篇文章不是介紹fastText的麼,怎麼開始介紹起了word2vec?最主要的原因是word2vec的CBOW模型架構和fastText模型非常相似。於是,你看到facebook開源的fastText工具不僅實現了fastText文本分類工具,還實現了快速詞向量訓練工具。word2vec主要有兩種模型:skip-gram 模型和CBOW模型,這裏只介紹CBOW模型,有關skip-gram模型的內容請參考達觀另一篇技術文章:

漫談Word2vec之skip-gram模型 mp.weixin.qq.com/s/reT4


(1)模型架構

CBOW模型的基本思路是:用上下文預測目標詞彙。架構圖如下所示:

輸入層由目標詞彙y的上下文單詞 \left\{ x_{1},...,x_{c} \right\} 組成, x_{i} 是被onehot編碼過的V維向量,其中V是詞彙量;隱含層是N維向量h;輸出層是被onehot編碼過的目標詞y。輸入向量通過 V*N 維的權重矩陣W連接到隱含層;隱含層通過 N*V 維的權重矩陣 W' 連接到輸出層。因爲詞庫V往往非常大,使用標準的softmax計算相當耗時,於是CBOW的輸出層採用的正是上文提到過的分層Softmax。


(2)前向傳播

輸入是如何計算而獲得輸出呢?先假設我們已經獲得了權重矩陣 W 和 W^{'} (具體的推導見第3節),隱含層h的輸出的計算公式:

即:隱含層的輸出是C個上下文單詞向量的加權平均,權重爲W

接着我們計算輸出層的每個節點: u_{j}={v'}_{w_{j}}^{T}·h

這裏 {v'}_{w_{j}} 是矩陣 W’ 的第j列,最後,將 u_{j} 作爲softmax函數的輸入,得到 y_{j} :

(3)反向傳播學習權重矩陣

在學習權重矩陣和過程中,我們首先隨機產生初始值,然後feed訓練樣本到我們的模型,並觀測我們期望輸出和真實輸出的誤差。接着,我們計算誤差關於權重矩陣的梯度,並在梯度的方向糾正它們。


首先定義損失函數,objective是最大化給定輸入上下文,target單詞的條件概率。因此,損失函數爲:

這裏, j^{*} 表示目標單詞在詞庫V中的索引。

如何更新權重 W' ?

我們先對E關於 W_{ij}^{'} 求導:

⟦j=j^* ⟧ 函數表示:

於是, W_{ij}^{'} 的更新公式:

如何更新權重W

我們首先計算E關於隱含層節點的導數:

然後,E關於權重的導數爲:

於是, w_{ki} 的更新公式:

3. fastText分類


終於到我們的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特徵的引入對分類效果會有一些提升 。


4. 手寫一個fastText


keras是一個抽象層次很高的神經網絡API,由python編寫,底層可以基於Tensorflow、Theano或者CNTK。它的優點在於:用戶友好、模塊性好、易擴展等。所以下面我會用keras簡單搭一個fastText的demo版,生產可用的fastText請移步github.com/facebookrese。如果你弄懂了上面所講的它的原理,下面的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數據到模型的代碼比較繁瑣,這裏不展示。


5. fastText在達觀數據的應用


fastText作爲誕生不久的詞向量訓練、文本分類工具,在達觀得到了比較深入的應用。主要被用在以下兩個系統:

1. 同近義詞挖掘。Facebook開源的fastText工具也實現了詞向量的訓練,達觀基於各種垂直領域的語料,使用其挖掘出一批同近義詞;

2. 文本分類系統。在類標數、數據量都比較大時,達觀會選擇fastText 來做文本分類,以實現快速訓練預測、節省內存的目的。


編者注:

如對文本挖掘領域的技術實踐感興趣,可前往下載達觀研究院編寫而成的《達觀數據技術實踐特刊》,該書集合了當下最熱門的人工智能領域自然語言處理、個性化推薦、垂直搜索引擎三大方向的技術實踐總結,融合了達觀技術團隊在服務華爲、中興、招行、平安、京東雲等不同行業上百家企業後的技術感悟,是國內第一本系統介紹NLP、深度學習等AI技術實踐應用的電子刊,歡迎各位技術愛好者前往下載


發佈了45 篇原創文章 · 獲贊 128 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章