1 fasttext工具介紹
1.1 介紹
-
fasttext 是 Facebook AI Research(FAIR)開發的開源 NLP 工具包,專門用來解決文本相關任務,比如情感分析、文本分類(判斷新聞屬于體育/財經等)、識別“人名/地名”這類實體,甚至輔助機器翻譯;
-
其核心功能聚焦 2 件事:
-
文本分類:給文本貼標簽、分類別(比如判斷評論是“正面”還是“負面”);
-
訓練詞向量:把詞語轉換成計算機能理解的數字向量,捕捉詞語語義(比如 “國王”和“王后”的向量,會比“國王”和“蘋果”的向量更接近);
-
-
最大優勢:正如其名。它能在保證較高精度的前提下,大幅加速訓練和預測過程,處理大規模文本數據時效率更高;
-
優勢原因:
- fasttext工具包中內含的fasttext模型,模型結構簡單;
- 使用fasttext模型訓練詞向量時,使用層次softmax結構,來提升超多類別下的模型性能;
- 采用負采樣(negative sampling),每次訓練僅僅更新一小部分的權重,降低梯度下降過程中的計算量;
- fasttext模型過于簡單無法捕捉詞序特征,可采用n-gram特征提取文本特征以彌補模型缺陷提升精度。
1.2 安裝
-
安裝 Python 3.8.12 的 Conda 環境:
conda create -n py3812 python=3.8.12
-
激活環境:
conda activate py3812
-
若直接安裝官方源碼版,由于此處使用的是 Windows 操作系統,需要安裝 Visual Studio 或配置編譯環境,所以選擇安裝
fasttext-wheel
預編譯輪子版:pip install fasttext-wheel
-
推薦使用 Linux 系統,按照下面的方式安裝:
git clone https://github.com/facebookresearch/fastText.git cd fastText sudo pip install .
-
-
驗證:
(py3812) C:\Windows\System32>python Python 3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import fasttext >>>
1.3 fasttext模型架構
1.3.1 三層架構
-
fasttext 架構和 Word2Vec 里的CBOW 模型很像,但目標不同:
-
CBOW 是“預測中間詞”(比如用上下文猜中間的詞);
-
fasttext 是“預測文本標簽/類別”(比如判斷文本是“體育新聞”還是“財經新聞”);
-
-
fasttext 模型分 3 層:
-
輸入層:把文本拆成可計算的向量
-
輸入的是文檔 embedding 后的向量,而且不只是單個詞,還包含N-gram 特征;
-
作用:彌補模型“太簡單,抓不住詞序”的問題,用 N-gram 保留局部短語信息;
-
-
隱藏層:平均匯總
-
對輸入層的所有向量(單個詞 + N-gram 等),直接求和、平均,得到一個匯總后的向量;
-
特點:計算極簡單,沒有復雜的變換,所以速度快,但也會損失一些細節;
-
-
輸出層:預測文本的標簽/類別
-
輸出的是文檔對應的 label(標簽/類別),比如“正面情感”“體育分類”等;
-
關鍵優化:為了讓多分類更高效,沒用傳統的 Softmax,而是用層次 Softmax;
-
-
-
層次 Softmax(Hierarchical Softmax)
-
傳統 Softmax 計算多分類概率時,要遍歷所有類別算概率,類別越多越慢。fasttext 用哈夫曼樹優化;
-
把類別建成一棵樹,葉子節點是類別。計算概率時,只需要從根到葉子走一條路徑,不用遍歷所有類別,大幅減少計算量,讓預測/訓練速度飛起。
-
1.3.2 層次 Softmax
-
為什么層次 Softmax 比普通 Softmax 計算概率分布要快?
-
普通 Softmax 計算多分類概率時,要遍歷所有類別算指數、歸一化,類別越多越慢;
-
層次 Softmax 用**哈夫曼樹(帶權二叉樹)**重構計算方式,把“遍歷所有類別”改成“走一條路徑”,直接砍半計算量——這是它“更快”的本質;
-
哈夫曼樹:“讓高頻類別‘更近’”
-
所有單詞(或類別)掛在葉子節點,樹的構建按照“出現頻率”分配:頻率越高的單詞,離根節點越近(路徑越短);
-
效果:高頻詞計算時,少走很多“彎路”,整體平均計算步驟更少。
-
-
概率計算:從遍歷所有到走一條路
-
普通 Softmax(以計算單詞w2w_2w2?概率為例):分母要把所有VVV個類別的指數都算一遍,類別越多,計算量爆炸(比如10萬類別,就要算10萬次指數);
p(w2)=evw2∑i=1Vevwip(w2) = \frac{e^{v_{w2}}}{\sum_{i=1}^V e^{v_{w_i}}} p(w2)=∑i=1V?evwi??evw2?? -
層次Softmax(同樣算w2w_2w2?概率):把“算單個單詞概率”,拆成“走哈夫曼樹路徑上的多個二分類概率乘積”;
-
比如w2w_2w2?的路徑是“根→節點A→節點B→葉子w2w_2w2?”,每一步都是“左/右子樹”的二分類概率(類似“選左的概率是0.6,選右是0.4”),最后把這些概率相乘,就是w2w_2w2?的概率;
-
效果:不需要遍歷所有類別,只需要算“路徑長度”次二分類(路徑長度遠小于總類別數VVV),計算量直接砍半;
-
-
-
-
例:
-
哈夫曼樹結構
- 假設有3個詞w1w_1w1?,w2w_2w2?,w3w_3w3?,由于每個中間節點是一個二分類,則p(left)+p(right)=1p(left)+p(right)=1p(left)+p(right)=1
- 如圖:w3w_3w3?=0.4、w1=0.6?0.5=0.3w_1=0.6*0.5=0.3w1?=0.6?0.5=0.3、w2=0.6?0.5=0.3w_2=0.6*0.5=0.3w2?=0.6?0.5=0.3、w1+𝑤2+𝑤3=1w_1+ 𝑤_2+𝑤_3 = 1w1?+w2?+w3?=1
-
普通Softmax:要算ew1+ew2+ew3e^{w_1}+e^{w_2}+e^{w_3}ew1?+ew2?+ew3?,然后再歸一化;
-
層次Softmax:算w2w_2w2?概率時,走“根→右子樹→左子樹→w2w_2w2?”,概率是 “根選右(0.6)×下一層選左(0.5)×再下一層選左(0.3)”,最后相乘得到w2w_2w2?的概率;
-
-
總結:
-
層次Softmax把**“多分類問題”拆解成“多個二分類問題的乘積”**,不需要遍歷所有類別,計算量隨“哈夫曼樹深度”線性增長(而普通Softmax是隨類別數VVV線性增長);
-
代價:精度會略降(因為路徑拆分后,不是直接算所有類別概率),但換來的是速度大幅提升,尤其類別數極多(比如10萬+類別)時,優勢碾壓。
-
1.3.3 哈夫曼樹的簡介、構建和訓練
-
哈夫曼樹的本質是帶權路徑最短的二叉樹
-
WPL(Weighted Path Length):帶權路徑長度
WPL=∑(節點權重×該節點到根的路徑長度)WPL = \sum (\text{節點權重} \times \text{該節點到根的路徑長度}) WPL=∑(節點權重×該節點到根的路徑長度) -
WPL最小的二叉樹就是哈夫曼樹;
-
例:葉子節點是 3、5、7、9,構建哈夫曼樹后:WPL=3×3+5×3+7×2+9×1=47WPL = 3 \times 3 + 5 \times 3 + 7 \times 2 + 9 \times 1 = 47WPL=3×3+5×3+7×2+9×1=47,路徑越短,權重×長度的和越小;
-
-
例:假設有四個Label分別為:A~D,統計其在語料庫出現的頻數為A(5次)、B(9次)、C(7次)、D(3次)
-
步驟1:初始化森林。每個Label(A/B/C/D)單獨成樹,權重是它們的出現頻率(5、9、7、3);
-
步驟2:選權重最小的兩棵樹合并
-
第一次合并:選最小的 D(3) 和 A(5),合并成新樹,權重=3+5=8。此時森林里剩下:B(9)、C(7)、新樹(8);
-
第二次合并:選次小的 C(7) 和 新樹(8),合并成新樹,權重=7+8=15。此時森林里剩下:B(9)、新樹(15);
-
第三次合并:合并 B(9) 和 新樹(15),權重=9+15=24。此時森林只剩1棵樹——哈夫曼樹構建完成!
-
-
-
哈夫曼樹建好后,如何訓練哈夫曼樹?
-
構建好霍夫曼樹后,所有單詞都會掛在葉子節點上;
-
給每個葉子節點創建哈夫曼編碼:給每個節點編二進制碼
-
規則:左分支記0,右分支記1,從根到葉子的路徑上的0/1序列,就是該葉子節點的哈夫曼編碼;
-
例子:D的路徑是“根→右→右→左”,編碼可能是:110;
-
-
訓練模型:用路徑概率乘積優化參數
-
任務:比如用上下文預測單詞D,需要從根節點出發,沿著D的編碼路徑(比如110)走;
-
計算:每一步是二分類概率(走左/右的概率),把這些概率相乘,用極大似然估計(讓預測概率盡可能大)反向更新模型參數(比如中間節點的權重);
-
極大似然估計(Maximum Likelihood Estimation,MLE)是一種在統計學和機器學習中廣泛使用的參數估計方法,它的目標是利用已知的樣本數據,來估計模型中未知參數的值,使得模型產生這些樣本數據的概率最大;
基本思想
- 假設我們有一組來自某個概率分布的樣本數據,而這個概率分布由一些未知參數決定;
- 極大似然估計的核心想法是,找到這樣一組參數值,在這組參數值下,我們現有的樣本數據出現的可能性最大;
- 比如,我們拋一枚硬幣,不知道它是否是均勻的(即不知道正面朝上的概率 ppp 是多少),現在拋了10次,得到7次正面,3次反面。按照極大似然估計的思想,我們要找到一個 ppp 的值,使得出現 “7次正面,3次反面” 這種結果的概率最大;
計算步驟
- 確定似然函數:
- 對于離散型隨機變量,設樣本 X1,X2,…,XnX_1, X_2, \ldots, X_nX1?,X2?,…,Xn? 來自概率質量函數為 P(X;θ)P(X; \theta)P(X;θ) 的總體(其中 θ\thetaθ 是未知參數),似然函數 L(θ)L(\theta)L(θ) 就是在參數 θ\thetaθ 下,樣本出現的聯合概率,即 L(θ)=∏i=1nP(Xi;θ)L(\theta)=\prod_{i = 1}^{n}P(X_i; \theta)L(θ)=∏i=1n?P(Xi?;θ) ;
- 對于連續型隨機變量,設樣本 X1,X2,…,XnX_1, X_2, \ldots, X_nX1?,X2?,…,Xn? 來自概率密度函數為 f(X;θ)f(X; \theta)f(X;θ) 的總體,似然函數 L(θ)=∏i=1nf(Xi;θ)L(\theta)=\prod_{i = 1}^{n}f(X_i; \theta)L(θ)=∏i=1n?f(Xi?;θ) ;
- 對似然函數取對數:取對數后的對數似然函數 ln?L(θ)\ln L(\theta)lnL(θ) 與原似然函數在相同的參數值處取得極值,而且取對數后可以將連乘運算轉化為連加運算,簡化計算,即 ln?L(θ)=∑i=1nln?P(Xi;θ)\ln L(\theta)=\sum_{i = 1}^{n}\ln P(X_i; \theta)lnL(θ)=∑i=1n?lnP(Xi?;θ)(離散型)或 ln?L(θ)=∑i=1nln?f(Xi;θ)\ln L(\theta)=\sum_{i = 1}^{n}\ln f(X_i; \theta)lnL(θ)=∑i=1n?lnf(Xi?;θ)(連續型);
- 求對數似然函數的導數:對 ln?L(θ)\ln L(\theta)lnL(θ) 關于未知參數 θ\thetaθ 求導;
- 令導數為0,求解參數:通過求解導數為0的方程,得到使似然函數最大的參數估計值 θ^\hat{\theta}θ^ ;
示例:以拋硬幣為例,設正面朝上的概率為 ppp,拋 nnn 次硬幣,出現 kkk 次正面。每次拋硬幣是獨立的伯努利試驗,其概率質量函數為 P(X=1;p)=pP(X = 1; p)=pP(X=1;p)=p(正面朝上,X=1X = 1X=1 ),P(X=0;p)=1?pP(X = 0; p)=1 - pP(X=0;p)=1?p(反面朝上,X=0X = 0X=0 );
- 確定似然函數:拋 nnn 次硬幣,出現 kkk 次正面的似然函數為 L(p)=Cnkpk(1?p)n?kL(p)=C_{n}^{k}p^{k}(1 - p)^{n - k}L(p)=Cnk?pk(1?p)n?k,其中 Cnk=n!k!(n?k)!C_{n}^{k}=\frac{n!}{k!(n - k)!}Cnk?=k!(n?k)!n!? 是組合數;
- 取對數:對數似然函數為 ln?L(p)=ln?Cnk+kln?p+(n?k)ln?(1?p)\ln L(p)=\ln C_{n}^{k}+k\ln p+(n - k)\ln(1 - p)lnL(p)=lnCnk?+klnp+(n?k)ln(1?p) ;
- 求導數:對 ln?L(p)\ln L(p)lnL(p) 關于 ppp 求導,得到 dln?L(p)dp=kp?n?k1?p\frac{d\ln L(p)}{dp}=\frac{k}{p}-\frac{n - k}{1 - p}dpdlnL(p)?=pk??1?pn?k? ;
- 令導數為0求解:令 dln?L(p)dp=0\frac{d\ln L(p)}{dp}=0dpdlnL(p)?=0,解得 p^=kn\hat{p}=\frac{k}{n}p^?=nk? 。例如前面拋10次硬幣出現7次正面的情況,按照極大似然估計得到正面朝上的概率估計值為 710=0.7\frac{7}{10}=0.7107?=0.7 ;
在機器學習中的應用
- 在機器學習里,極大似然估計常用于估計模型參數。比如:
- 在邏輯回歸中,通過極大似然估計來確定模型中參數的值,使得模型對給定訓練數據的預測概率最大;
- 在樸素貝葉斯分類器中,也利用極大似然估計來估計各類別下特征的概率,從而進行分類預測 。
-
1.3.4 負采樣
-
為什么需要負采樣樣(Negative Sampling)?
- 訓練模型時,最大的痛點是計算量爆炸;
- 神經網絡經過一個訓練樣本的訓練, 它的權重就會進行一次調整;
- 比如利用 Skip-Gram 進行詞向量訓練,用 Softmax 算概率時,輸出層要對所有單詞 算指數、歸一化,每次訓練都要更新所有權重;
- 假設有詞匯量 1 萬,每次訓練就要算 1 萬次指數 + 反向傳播更新 1 萬組權重,訓練速度肉眼可見地慢,根本跑不動大規模數據;
- 訓練模型時,最大的痛點是計算量爆炸;
-
而負采樣的本質是砍計算量:
- 每次訓練時,不更新所有單詞的權重,只挑一小部分“負樣本”(不需要預測正確的單詞)和“正樣本”(需要預測正確的單詞)來更新;
- 相當于把“更新 1 萬次”砍成“更新 5 - 20 次”,直接讓訓練速度起飛;
-
以訓練詞向量的場景為例(輸入“hello”,輸出“man”):
-
傳統 Softmax 的問題
-
輸入“hello”,輸出層要預測“man”是正樣本(期望輸出 1),剩下 9999 個單詞都是負樣本(期望輸出 0);
-
用 Softmax 的話,得給這 9999 個負樣本都算概率、反向更新權重,計算量直接拉滿;
-
-
負采樣的操作
-
只挑一小部分負樣本:比如隨機選 5 個負樣本(比如“apple”“dog”“book”…),只更新這些負樣本 + 正樣本(“man”)的權重;
-
效果:原本要更新 10000 個權重,現在只更新 6 個(5 負 + 1 正),計算量直接砍到 0.06%(比如 300 萬權重,現在只算 1800 個);
-
-
-
負采樣的優勢
-
訓練速度爆炸提升:少更新 99% 的權重,訓練時間直接腰斬甚至更多,大規模數據也能跑起來;
-
模型更穩、泛化更好:加入“負樣本噪聲”(隨機選負樣本),相當于讓模型“見更多錯誤案例”,能模擬真實場景的噪聲,反而讓模型更魯棒(不容易過擬合),預測更準。
-
2 fasttext文本分類
2.1 文本分類介紹
-
概念
- 簡單說,就是給文本貼標簽、歸類:把郵件、帖子、評論、新聞……這類文本,按照規則分到對應的類別里(比如“這封郵件是垃圾郵件/正常郵件”“這條評論是正面/負面”);
- 關鍵點: 需要有監督學習。即訓練模型時,得先給一批文本標好標簽(比如人工標“垃圾郵件”“正面評論”),模型才能學怎么分類;
-
種類
-
二分類
-
特點:文本只能“非此即彼”,分到 2 個類別里的 1 個;
-
例子:判斷評論是“好評”還是“差評”;識別郵件是“垃圾郵件”還是“正常郵件”;
-
-
單標簽多分類
-
特點:文本從多個類別里選 1 個 標簽,多選一;
-
例子:識別“人名”屬于哪個國家(比如“張三”→“中國”;“瑪麗”→“美國”);新聞分類(“體育新聞”“財經新聞”選一個);
-
-
多標簽多分類
-
特點:文本可以同時貼多個標簽,多選多;
-
例子:一段討論“既聊美食,又聊體育、游戲”,就同時打“美食”“體育”“游戲”標簽。
-
-
2.2 使用fasttext做文本分類
2.2.1 獲取數據
-
數據集下載地址:
https://dl.fbaipublicfiles.com/fasttext/data/cooking.stackexchange.tar.gz && tar xvzf cooking.stackexchange.tar.gz
; -
本案例使用烹飪相關的數據集, 它是由 Facebook AI 實驗室提供的演示數據:
-
每行是標簽 + 文本內容結構
label AAA label BBB text1 text2...
- 比如:
label sauce label cheese How much does potato starch affect a cheese sauce recipe?
- 這里
label sauce label cheese
是標簽(代表文本分類類別,說明文本和 “醬料、奶酪” 相關),后半句是具體問題文本;
- 比如:
-
每條文本可對應多個標簽,屬于多標簽文本分類問題。
2.2.2 訓練集與驗證集的劃分
-
12404條數據作為訓練數據,3000條數據作為驗證數據:
-
可以使用一些系統指令,取出
cooking.stackexchange
中的從頭開始多少行或從尾部開始多少行,分別作為訓練集和數據集,以Linux為例:# 12404條數據作為訓練數據 $ head -n 12404 cooking.stackexchange.txt > cooking.train # 3000條數據作為驗證數據 $ tail -n 3000 cooking.stackexchange.txt > cooking.valid
2.2.3 訓練模型
-
將 PyCharm 切換至創建的 py3812 環境:
-
以管理員權限打開 Anaconda,然后激活 py3812 環境,再安裝 jupyter:
- 由于 Python 3.8 的版本有點老了,所以一些依賴問題需要自己處理;
ipykernel
是一個 Python 包,在 Jupyter 生態系統中扮演著關鍵角色,它的主要作用是作為 Jupyter Notebook、JupyterLab 等交互式開發環境與 Python 解釋器之間的橋梁;
pip install pywinpty==2.0.10 pip install jupyter conda install ipykernel
-
重啟 PyCharm(這同時也重啟了 Anaconda)
-
導包:
import fasttext
-
使用 fasttext 的
train_supervised
方法進行文本分類模型的訓練# 使用fasttext的train_supervised方法進行文本分類模型的訓練 model = fasttext.train_supervised(input="cooking_data/cooking.train")
2.2.4 模型的保存和重加載
# 模型的保存和重加載
model.save_model("cooking_data/model/model_cooking.bin")
model = fasttext.load_model("cooking_data/model/model_cooking.bin")
# 重加載后的模型使用方法
model.predict("Which baking dish is best to bake a banana bread ?", k=-1, threshold=0.01)
k=-1
表示返回所有可能分類(按預測概率排序);threshold=0.01
是概率閾值,分類預測概率 ≥0.01 才會被輸出;
(('__label__baking','__label__food-safety','__label__bread','__label__substitutions','__label__equipment','__label__chicken','__label__eggs','__label__storage-method','__label__cake','__label__sauce','__label__meat','__label__coffee','__label__chocolate','__label__freezing','__label__flavor','__label__cheese'),array([0.06340391, 0.04024106, 0.0361773 , 0.03421036, 0.02819154,0.01837722, 0.01678729, 0.01484748, 0.01481829, 0.01259199,0.01250622, 0.01226074, 0.01125562, 0.01081415, 0.01021101,0.01014362]))
2.2.5 使用模型進行預測并評估
model.predict("Which baking dish is best to bake a banana bread ?")
- 標簽:
__label__baking
→ 模型判斷文本屬于“烘焙”類別; - 概率:
0.0634
→ 模型對該分類的“置信度”,數值低,說明把握不大; - 預測正確,但是概率不大;
model.predict("Why not put knives in the dishwasher?")
- 預測錯誤;
# 為了評估模型到底表現如何, 下面在3000條的驗證集上進行測試
model.test("cooking_data/cooking.valid")
-
3000:驗證集樣本總數;
-
0.148:準確率(Precision) → 模型預測為 “正確” 的樣本中,實際真正確的比例。數值低(僅 14.8%),說明模型容易 “亂分類”,很多預測的標簽是錯的;
-
0.064:召回率(Recall) → 實際為正類的樣本中,被模型正確預測為正類的比例。數值極低(6.4%),說明大量真實正類樣本沒被模型識別出來。
-
由此可見:訓練出來的模型準確率非常低,需要模型調優,有以下方法
- 數據方面:重新處理數據
- 增加訓練輪數
- 調整學習率
- 增加n-gram特征
- 修改損失計算方式
- 自動超參數調優
- 實際生產中多標簽多分類問題的損失計算方式
2.3 fasttext模型調優
2.3.1 原始數據處理
-
通過查看數據,可以發現數據中存在許多標點符號與單詞相連以及大小寫不統一,這些因素對我們最終的分類目標沒有益處,反而是增加了模型提取分類規律的難度,因此我們選擇將它們去除或轉化;
-
如果使用的是 Linux 操作系統,可以使用終端執行下面的命令,進行簡單的數據預處理:
# 使標點符號與單詞分離并統一使用小寫字母 cat cooking.stackexchange.txt | sed -e "s/\([.\!?,'/()]\)/ \1 /g" | tr "[:upper:]" "[:lower:]" > cooking.preprocessed.txt head -n 12404 cooking.preprocessed.txt > cooking.pre.train tail -n 3000 cooking.preprocessed.txt > cooking.pre.valid
-
完成以上的數據處理操作后,進行訓練:
# 原始數據處理后的訓練 model = fasttext.train_supervised(input="cooking_data/cooking.train", epoch=25) model.test("cooking_data/cooking.pre.valid")
- 準確率提升到了 47%;
- 召回率提升到了 20%。
2.3.2 增加訓練輪次
# 增加訓練輪次
model = fasttext.train_supervised(input="cooking_data/cooking.train", epoch=50)
model.test("cooking_data/cooking.pre.valid")
2.3.3 調整學習率
# 調整學習率
model = fasttext.train_supervised(input="cooking_data/cooking.train", lr=1.0, epoch=50)
model.test("cooking_data/cooking.pre.valid")
2.3.4 增加n-gram特征
- 設置
train_supervised
方法中的參數 wordNgrams 來添加 n-gram 特征,默認是1,也就是沒有n-gram特征; - 下面將其設置為2意味著添加2-gram特征,這些特征幫助模型捕捉前后詞匯之間的關聯,更好的提取分類規則用于模型分類,當然這也會增加模型訓時練占用的資源和時間;
# 調整學習率
model = fasttext.train_supervised(input="cooking_data/cooking.train", lr=1.0, epoch=50, wordNgrams=2)
model.test("cooking_data/cooking.pre.valid")
2.3.5 修改損失計算方式
- 隨著不斷添加優化策略,模型訓練速度也越來越慢;
- 為了能夠提升 fasttext 模型的訓練效率,縮短訓練時間,可以設置
train_supervised
方法中的參數 loss 來修改損失計算方式(等效于輸出層的結構);- 默認是softmax層結構;
- 下面將其設置為
'hs'
,代表層次softmax結構,意味著輸出層的結構(計算方式)發生了變化,將以一種更低復雜度的方式來計算損失;
# 修改損失計算方式
model = fasttext.train_supervised(input="cooking_data/cooking.train", lr=1.0, epoch=50, wordNgrams=2, loss='hs')
model.test("cooking_data/cooking.pre.valid")
- 雖然精度和召回率稍有波動,但訓練時間能感受到明顯加快。
2.3.6 自動超參數調優
-
手動調節和尋找超參數是非常困難的,因為參數之間可能相關,并且不同數據集需要的超參數也不同;
-
因此可以使用 fasttext 的 autotuneValidationFile 參數進行自動超參數調優;
- autotuneValidationFile 參數需要指定驗證數據集所在路徑,它將在驗證集上使用隨機搜索方法尋找可能最優的超參數;
- 使用 autotuneDuration 參數可以控制隨機搜索的時間,默認是300s,根據不同的需求,可以延長或縮短時間;
-
注意:
- autotuneValidationFile 和 lr 參數不會直接沖突,但存在一定的優先級關系;
- autotuneValidationFile 開啟后,lr 等手動指定的參數會被視為初始值或候選值,自動調優過程可能會根據驗證集表現調整 lr 的值(例如增大或減小),最終選擇更優的學習率;
# 自動超參數調優
model = fasttext.train_supervised(input="cooking_data/cooking.train", lr=1.0, epoch=50, wordNgrams=2, loss='hs', autotuneValidationFile='cooking_data/cooking.pre.valid', autotuneDuration=600)
model.test("cooking_data/cooking.pre.valid")
2.3.7 實際生產中多標簽多分類問題的損失計算方式
- 針對多標簽多分類問題,使用 softmax 或者 hs 有時并不是最佳選擇,因為我們最終得到的應該是多個標簽,而softmax卻只能最大化一個標簽;
- 所以我們往往會選擇為每個標簽使用獨立的二分類器作為輸出層結構,對應的損失計算方式為
'ova'
,表示one vs all; - 這種輸出層的改變意味著我們在統一語料下同時訓練多個二分類模型,對于二分類模型來講,lr不宜過大,下面設置為0.2;
# 實際生產中多標簽多分類問題的損失計算方式
model = fasttext.train_supervised(input="cooking_data/cooking.train", lr=0.2, epoch=50, wordNgrams=2, loss='ova')
model.predict("Which baking dish is best to bake a banana bread ?", k=-1, threshold=0.5)
- 輸出結果輸出了它的三個最有可能的標簽。
3 fasttext詞向量遷移
3.1 介紹
-
**詞向量遷移(Word Vector Transfer)**概念:復用預訓練詞向量,加速模型開發
-
直接用別人在大規模語料(比如全網文本、維基百科)訓好的詞向量模型,不用自己從頭訓練;
-
舉例:你想做“美食評論分類”,但自己數據少。可以先下載 fasttext 預訓練的詞向量,再用自己的“美食評論數據”微調,這就是遷移;
-
-
fasttext 官方開源了兩類預訓練詞向量:
-
第一類(157 種語言)
-
訓練數據:CommonCrawl(超大網絡文本庫) + Wikipedia(維基百科)
-
訓練模式:CBOW
-
詞向量規格:300 維(每個單詞用 300 個數表示,維度越高語義信息越細)
-
獲取地址:
https://fasttext.cc/docs/en/crawl-vectors.html
-
-
第二類(294 種語言)
-
訓練數據:Wikipedia
-
訓練模式:Skipgram
-
詞向量規格:300 維
-
獲取地址:
https://fasttext.cc/docs/en/pretrained-vectors.html
-
-
-
詞向量遷移的優勢:省時間、省資源、提效果
-
不用自己訓:訓詞向量需要超大規模語料(比如幾十 GB 文本) + 超長訓練時間(可能跑幾天),普通開發者根本扛不住。直接用預訓練的,1 分鐘下載,直接開干;
-
語義基礎好:CommonCrawl、Wikipedia 是“通用語義富礦”,訓出來的詞向量已經包含“單詞的通用語義”(比如
apple
既知道是“蘋果”,也知道和fruit
相關)。你用這些詞向量做任務,相當于默認帶了“通用知識”,再用自己數據微調,效果比“從零訓”好很多; -
跨任務適配:不管你是做“情感分析”“文本分類”“機器翻譯”,都能先用預訓練詞向量打基礎,再針對具體任務微調。遷移性極強,適合小數據場景。
-
3.2 使用fasttext進行詞向量遷移
-
中文詞向量模型:
cc.zh.300.bin
;- 地址:dl.fbaipublicfiles.com/fasttext/vectors-crawl/crawl.zh.300.bin.gz;
- 大小:2.01GB
- 解壓縮后大小:6個多G
- 讀入到內存:需要8個G
-
使用fasttext進行詞向量遷移的步驟:
- 下載詞向量模型壓縮的 bin.gz 文件
- 解壓 bin.gz 文件到 bin 文件
- 加載 bin 文件獲取詞向量
- 利用鄰近詞進行效果檢驗
import fasttext
model = fasttext.load_model("model/cc.zh.300.bin")
# 查看前100個詞匯(這里的詞匯是廣義的, 可以是中文符號或漢字)
model.words[:100]
model.get_word_vector("音樂")
# 以'音樂'為例,返回的鄰近詞基本上與音樂都有關系,如樂曲、音樂會、聲樂等
model.get_nearest_neighbors("音樂")
[(0.6703276634216309, '樂曲'),(0.6565821170806885, '聲樂'),(0.6540279388427734, '音樂會'),(0.6502416133880615, '配樂'),(0.6501686573028564, '藝術'),(0.6489475965499878, '音樂人'),(0.6426260471343994, '音樂界'),(0.6395964026451111, '非音樂'),(0.639589250087738, '原聲'),(0.637651264667511, '交響樂')]
# 以'美術'為例,返回的鄰近詞基本上與美術都有關系,如藝術、繪畫、霍廷霄(滿城盡帶黃金甲的美術師)等
model.get_nearest_neighbors("美術")
[(0.724744975566864, '藝術'),(0.7165924310684204, '繪畫'),(0.7006476521492004, '中國畫系'),(0.6706337332725525, '版畫系'),(0.6470299363136292, '純藝'),(0.6455479860305786, '環藝系'),(0.6304370164871216, '美院'),(0.6295372247695923, '國畫系'),(0.6293253898620605, '鐘志鵬'),(0.627504825592041, '中國畫')]
# 以'周杰倫'為例,返回的鄰近詞基本上與明星有關系,如杰倫、周董、陳奕迅等
model.get_nearest_neighbors("周杰倫")
[(0.7129376530647278, '杰倫'),(0.6841713786125183, '周董'),(0.6783010959625244, '周杰倫'),(0.6644064784049988, '陳奕迅'),(0.6536471843719482, '張韶涵'),(0.6481418609619141, '葉惠美'),(0.6470388174057007, '周華健'),(0.643777072429657, '張靚穎'),(0.6342697143554688, '張惠妹'),(0.6318544149398804, '林俊杰')]