專欄 | fastText原理及實踐

2021-03-01 機器之心

代價函數(cost function)如下:

在Softmax回歸中,類標是大於2的,因此在我們的訓練集

中,。給定一個測試輸入x,我們的假設應該輸出一個K維的向量,向量內每個元素的值表示x屬於當前類別的概率。具體地,假設形式如下:

代價函數如下:

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

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

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

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

下圖是一個分層Softmax示例:

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

其中:

表示sigmoid函數;

表示n節點的左孩子;

是一個特殊的函數,被定義為:

是中間節點的參數;X是Softmax層的輸入。

上圖中,高亮的節點和邊是從根節點到  的路徑,路徑長度

可以被表示為:

於是,從根節點走到葉子節點,實際上是在做了3次二分類的邏輯回歸。

通過分層的Softmax,計算複雜度一下從|K|降低到log|K|。

在文本特徵提取中,常常能看到n-gram的身影。它是一種基於語言模型的算法,基本思想是將文本內容按照字節順序進行大小為N的滑動窗口操作,最終形成長度為N的字節片段序列。看下面的例子:

我來到達觀數據參觀

相應的bigram特徵為:

我來 來到 到達 達觀 觀數 數據 據參 參觀

相應的trigram特徵為:

我來到 來到達 到達觀 達觀數 觀數據 數據參 據參觀


注意一點:n-gram中的gram根據粒度不同,有不同的含義。它可以是字粒度,也可以是詞粒度的。上面所舉的例子屬於字粒度的n-gram,詞粒度的n-gram看下面例子:

我 來到 達觀數據 參觀

相應的bigram特徵為:

我/來到 來到/達觀數據 達觀數據/參觀

相應的trigram特徵為:

我/來到/達觀數據 來到/達觀數據/參觀

n-gram產生的特徵只是作為文本特徵的候選集,你後面可能會採用信息熵、卡方統計、IDF等文本特徵選擇方式篩選出比較重要特徵。

你可能要問,這篇文章不是介紹fastText的麼,怎麼開始介紹起了word2vec?

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

漫談Word2vec之skip-gram模型

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

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

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

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

接著我們計算輸出層的每個節點:

這裡是矩陣的第j列,最後,將作為softmax函數的輸入,得到

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

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

這裡,表示目標單詞在詞庫V中的索引。

如何更新權重?

我們先對E關於求導:

函數表示:

於是,的更新公式:

如何更新權重W?

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

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

於是,的更新公式:

終於到我們的fastText出場了。這裡有一點需要特別注意,一般情況下,使用fastText進行文本分類的同時也會產生詞的embedding,即embedding是fastText分類的產物。除非你決定使用預訓練的embedding來訓練fastText分類模型,這另當別論。

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向量。

之前提到過,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非常類似,這裡也不展開了。

現在拋開那些不是很討人喜歡的公式推導,來想一想fastText文本分類的核心思想是什麼?

仔細觀察模型的後半部分,即從隱含層輸出到輸出層輸出,會發現它就是一個softmax線性多類別分類器,分類器的輸入是一個用來表徵當前文檔的向量;模型的前半部分,即從輸入層輸入到隱含層輸出部分,主要在做一件事情:生成用來表徵文檔的向量。那麼它是如何做的呢?疊加構成這篇文檔的所有詞及n-gram的詞向量,然後取平均。疊加詞向量背後的思想就是傳統的詞袋法,即將文檔看成一個由詞構成的集合。

於是fastText的核心思想就是:將整篇文檔的詞及n-gram向量疊加平均得到文檔向量,然後使用文檔向量做softmax多分類。這中間涉及到兩個技巧:字符級n-gram特徵的引入以及分層Softmax分類。

還有個問題,就是為何fastText的分類效果常常不輸於傳統的非線性分類器?

假設我們有兩段文本:

我 來到 達觀數據

俺 去了 達而觀信息科技

這兩段文本意思幾乎一模一樣,如果要分類,肯定要分到同一個類中去。但在傳統的分類器中,用來表徵這兩段文本的向量可能差距非常大。傳統的文本分類中,你需要計算出每個詞的權重,比如tfidf值, 「我」和「俺」 算出的tfidf值相差可能會比較大,其它詞類似,於是,VSM(向量空間模型)中用來表徵這兩段文本的文本向量差別可能比較大。

但是fastText就不一樣了,它是用單詞的embedding疊加獲得的文檔向量,詞向量的重要特點就是向量的距離可以用來衡量單詞間的語義相似程度,於是,在fastText模型中,這兩段文本的向量應該是非常相似的,於是,它們很大概率會被分到同一個類中。

使用詞embedding而非詞本身作為特徵,這是fastText效果好的一個原因;另一個原因就是字符級n-gram特徵的引入對分類效果會有一些提升 。

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數據到模型的代碼比較繁瑣,這裡不展示。

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

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

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

王江,達觀數據自然語言處理工程師,負責達觀NLP底層開發、私有化應用系統開發等工作。主要參與大型系統的開發,對機器學習、NLP等領域有濃厚興趣。

相關焦點

  • fastText原理及實踐
    本文首先會介紹一些預備知識,比如softmax、ngram等,然後簡單介紹word2vec原理,之後來講解fastText的原理,並著手使用keras
  • FastText的內部機制
    fasttext是一個被用於對詞向量和句子分類進行高效學習訓練的工具庫,採用c++編寫,並支持訓練過程中的多進程處理。你可以使用這個工具在監督和非監督情況下訓練單詞和句子的向量表示。這些訓練出來的詞向量,可以應用於許多處理數據壓縮的應用程式,或者其他模型的特徵選擇,或者遷移學習的初始化。
  • 【NLP實戰】手把手帶你fastText文本分類
    也就是我們常說的fastText。最讓人欣喜的這篇論文配套提供了fasttext工具包。這個工具包代碼質量非常高,論文結果一鍵還原,目前已經是包裝地非常專業了,這是fastText官網和其github代碼庫,以及提供了python接口,可以直接通過pip安裝。這樣準確率高又快的模型絕對是實戰利器。
  • fastText,智慧與美貌並重的文本分類及向量化工具
    它的官網(fasttext.cc)上是這樣介紹的: FastText is an open-source, free, lightweightlibrary that allows users to learn text representations and text classifiers.It works on standard, generic hardware
  • 文本分類經典論文:fasttext,textcnn解讀
    本文我們重點關注基於深度學習的文本分類,並為大家介紹文本分類中非常經典的fasttext和textcnn。文本分類是對給定文檔,對文檔進行歸類的過程,常見的文本分類任務是垃圾郵件識別和情感分析。文本分類的處理大致分為文本預處理、文本特徵提取、分類模型構建等。
  • fastText的源碼,看這一篇就夠了!
    使用一段時候開始研究源碼,除可以弄清楚原理外,還可以學習很多編程技巧,知其所以然。因此,本解析將會圍繞這些展開討論。1.4 fastText 為什麼如此快2 fastText與word2vec的異同如果有對word2vec原理不清楚的可以看這篇博客word2vec[2],詳細介紹了word2vec的數學原理。2.1 相同點了解word2vec的同學,可以發現fasttext的模型結構和思想基本一致,倒是省去了理解的步驟。
  • 使用Gensim來實現Word2Vec和FastText
    在下面的段落中,我將簡要描述這兩種方法的工作原理。Skip-gram對於Skip-gram,輸入是目標單詞,而輸出是目標單詞的上下文單詞。例如,假設窗口大小為5,在句子「I have a cute dog」中,輸入為「a」,而輸出為「I」、「have」、「cute」和「dog」。所有的輸入和輸出都是相同尺寸的獨熱編碼。
  • NLP中的詞向量對比:word2vec/glove/fastText/elmo/GPT/bert
    作者:JayLou,NLP算法工程師知乎專欄:高能NLP之路
  • 前端跨域請求原理及實踐
    這也是我們下面實踐的理論基礎。我們利用 NodeJs 創建了兩個伺服器,分別監聽 3000、 3001 埠(下面簡稱 伺服器3000 與 伺服器3001 ),由於埠號不一樣,這兩個伺服器以及伺服器上頁面通信構成了跨域請求。 在伺服器3000 上有如下的頁面:
  • fastText完美解決你的需求(上篇)
    僅這一篇文章,讓你了解word2vec的原理, CBOW、Skip-gram模型,以及目前業界最流行的文本分類算法——fastText。 2013年,Google的大牛Tomas Mikolov開源了word2vec算法,轟動一時(託馬斯大牛現在就職於FaceBook,並在16年中下旬開源了fastText算法,沒辦法,速度太快了)。
  • 樸素貝葉斯分類算法原理與實踐
    (點擊上方公眾號,可快速關注)來源: CodeMealscnblogs.com/fengfenggirl/p/classification_evaluate.html如有好文章投稿,請點擊 → 這裡了解詳情今天介紹一下樸素貝葉斯分類算法,講一下基本原理
  • Facebook 開源的快速文本分類器 FastTex
    1. fastText 原理fastText 方法包含三部分:模型架構、層次 Softmax 和 N-gram 特徵。下面我們一一介紹。fastText 模型輸入一個詞的序列(一段文本或者一句話),輸出這個詞序列屬於不同類別的概率。序列中的詞和詞組組成特徵向量,特徵向量通過線性變換映射到中間層,中間層再映射到標籤。fastText 在預測標籤時使用了非線性激活函數,但在中間層不使用非線性激活函數。
  • 第201115期【羅偉專欄】課堂中排列組合的教學實踐
    魏喜紅全國優秀教師,全國德育課優秀教師,陝西省教學名師,陝西省數學特級教師、陝西省教學能手,陝西省學科帶頭人實踐導師,教育部「國培計劃」專家庫專家,寶雞市學科帶頭人、骨幹教師、教學能手、百校行優秀班主任,寶雞中學模範班主任、立德樹人模範、高考質量優秀教師.陝西師範大學兼職副教授,西南大學碩士生導師,寶雞文理學院兼職副教授.主持省市級課題6項,發表論文20多篇
  • 如何用 fast.ai 高效批量推斷測試集?
    痛點通過咱們之前幾篇 fast.ai 深度學習框架介紹,很多讀者都認識到了它的威力,並且有效加以了利用。fast.ai 不僅語法簡潔,還包裹了很多實用的數據集與預訓練模型,這使得我們在研究和工作中,可以省下大量的時間。跟著教程跑一遍,你會發現做圖像、文本分類,乃至推薦系統,其實是非常簡單的事情。
  • Keras-TextClassification 文本分類工具包
    /data'step3: goto # Train&Usage(調用) and Predict&Usage(調用)keras_textclassification(代碼主體,未完待續...)
  • fast break
    His dunk on afast breaktied the game for the final time at 13-13, and his free throw 15 seconds later gave Houston a one-point lead.
  • text-indent用在input下英文無效的解決辦法
    text-indent是一個常用的css屬性,在任何瀏覽器下都可以使用。但是,最近同事寫代碼的時候發現了一個Bug,text-indent用在input下英文無效。 text-indent是一個常用的css屬性,在任何瀏覽器下都可以使用。但是,最近同事寫代碼的時候發現了一個Bug,text-indent用在input下英文無效。
  • 論德性倫理學的實踐原理的兩個基本含義
    實踐原理是一種內在觀點的德性倫理學的最基本的原理。它的第一個含義是,生活可以是實踐的,表明生活的實踐的可能性。實踐原理的第二個含義是,生活實踐可以是德性的,表明德性地生活的可能性。一個人如果沒有在他的生活中發展第一種可能性,就會受到人們指責。但是,當他通過生活充分展示出第二種可能性,他才受到稱讚。倫理學可以或明確或隱含地以生活的實踐的可能性和德性地生活的可能性作為它的基礎。