【NLP】深度学习文本分类|模型代码技巧
文本分類是NLP的必備入門任務,在搜索、推薦、對話等場景中隨處可見,并有情感分析、新聞分類、標簽分類等成熟的研究分支和數據集。
本文主要介紹深度學習文本分類的常用模型原理、優缺點以及技巧,是「NLP入門指南」的其中一章,之后會不斷完善,歡迎提意見:
https://github.com/leerumor/nlp_tutorialP.S. 有基礎的同學可以直接看文末的技巧
Fasttext
論文:https://arxiv.org/abs/1607.01759 代碼:https://github.com/facebookresearch/fastTextFasttext是Facebook推出的一個便捷的工具,包含文本分類和詞向量訓練兩個功能。
Fasttext的分類實現很簡單:把輸入轉化為詞向量,取平均,再經過線性分類器得到類別。輸入的詞向量可以是預先訓練好的,也可以隨機初始化,跟著分類任務一起訓練。
Fasttext直到現在還被不少人使用,主要有以下優點:
模型本身復雜度低,但效果不錯,能快速產生任務的baseline
Facebook使用C++進行實現,進一步提升了計算效率
采用了char-level的n-gram作為附加特征,比如paper的trigram是 [pap, ape, per],在將輸入paper轉為向量的同時也會把trigram轉為向量一起參與計算。這樣一方面解決了長尾詞的OOV (out-of-vocabulary)問題,一方面利用n-gram特征提升了表現
當類別過多時,支持采用hierarchical softmax進行分類,提升效率
對于文本長且對速度要求高的場景,Fasttext是baseline首選。同時用它在無監督語料上訓練詞向量,進行文本表示也不錯。不過想繼續提升效果還需要更復雜的模型。
TextCNN
論文:https://arxiv.org/abs/1408.5882 代碼:https://github.com/yoonkim/CNN_sentenceTextCNN是Yoon Kim小哥在2014年提出的模型,開創了用CNN編碼n-gram特征的先河。
模型結構如圖,圖像中的卷積都是二維的,而TextCNN則使用「一維卷積」,即filter_size * embedding_dim,有一個維度和embedding相等。這樣就能抽取filter_size個gram的信息。以1個樣本為例,整體的前向邏輯是:
對詞進行embedding,得到[seq_length, embedding_dim]
用N個卷積核,得到N個seq_length-filter_size+1長度的一維feature map
對feature map進行max-pooling(因為是時間維度的,也稱max-over-time pooling),得到N個1x1的數值,拼接成一個N維向量,作為文本的句子表示
將N維向量壓縮到類目個數的維度,過Softmax
在TextCNN的實踐中,有很多地方可以優化(參考這篇論文[1]):
Filter尺寸:這個參數決定了抽取n-gram特征的長度,這個參數主要跟數據有關,平均長度在50以內的話,用10以下就可以了,否則可以長一些。在調參時可以先用一個尺寸grid search,找到一個最優尺寸,然后嘗試最優尺寸和附近尺寸的組合
Filter個數:這個參數會影響最終特征的維度,維度太大的話訓練速度就會變慢。這里在100-600之間調參即可
CNN的激活函數:可以嘗試Identity、ReLU、tanh
正則化:指對CNN參數的正則化,可以使用dropout或L2,但能起的作用很小,可以試下小的dropout率(<0.5),L2限制大一點
Pooling方法:根據情況選擇mean、max、k-max pooling,大部分時候max表現就很好,因為分類任務對細粒度語義的要求不高,只抓住最大特征就好了
Embedding表:中文可以選擇char或word級別的輸入,也可以兩種都用,會提升些效果。如果訓練數據充足(10w+),也可以從頭訓練
蒸餾BERT的logits,利用領域內無監督數據
加深全連接:原論文只使用了一層全連接,而加到3、4層左右效果會更好[2]
TextCNN是很適合中短文本場景的強baseline,但不太適合長文本,因為卷積核尺寸通常不會設很大,無法捕獲長距離特征。同時max-pooling也存在局限,會丟掉一些有用特征。另外再仔細想的話,TextCNN和傳統的n-gram詞袋模型本質是一樣的,它的好效果很大部分來自于詞向量的引入[3],因為解決了詞袋模型的稀疏性問題。
DPCNN
論文:https://ai.tencent.com/ailab/media/publications/ACL3-Brady.pdf 代碼:https://github.com/649453932/Chinese-Text-Classification-Pytorch上面介紹TextCNN有太淺和長距離依賴的問題,那直接多懟幾層CNN是否可以呢?感興趣的同學可以試試,就會發現事情沒想象的那么簡單。直到2017年,騰訊才提出了把TextCNN做到更深的DPCNN模型:
上圖中的ShallowCNN指TextCNN。DPCNN的核心改進如下:
在Region embedding時不采用CNN那樣加權卷積的做法,而是對n個詞進行pooling后再加個1x1的卷積,因為實驗下來效果差不多,且作者認為前者的表示能力更強,容易過擬合
使用1/2池化層,用size=3 stride=2的卷積核,直接讓模型可編碼的sequence長度翻倍(自己在紙上畫一下就get啦)
殘差鏈接,參考ResNet,減緩梯度彌散問題
憑借以上一些精妙的改進,DPCNN相比TextCNN有1-2個百分點的提升。
TextRCNN
論文:https://dl.acm.org/doi/10.5555/2886521.2886636 代碼:https://github.com/649453932/Chinese-Text-Classification-Pytorch除了DPCNN那樣增加感受野的方式,RNN也可以緩解長距離依賴的問題。下面介紹一篇經典TextRCNN。
模型的前向過程是:
得到單詞 i 的表示
通過RNN得到左右雙向的表示 和
將表示拼接得到 ,再經過變換得到
對多個 進行 max-pooling,得到句子表示 ,在做最終的分類
這里的convolutional是指max-pooling。通過加入RNN,比純CNN提升了1-2個百分點。
TextBiLSTM+Attention
論文:https://www.aclweb.org/anthology/P16-2034.pdf 代碼:https://github.com/649453932/Chinese-Text-Classification-Pytorch從前面介紹的幾種方法,可以自然地得到文本分類的框架,就是先基于上下文對token編碼,然后pooling出句子表示再分類。在最終池化時,max-pooling通常表現更好,因為文本分類經常是主題上的分類,從句子中一兩個主要的詞就可以得到結論,其他大多是噪聲,對分類沒有意義。而到更細粒度的分析時,max-pooling可能又把有用的特征去掉了,這時便可以用attention進行句子表示的融合:
BiLSTM就不解釋了,要注意的是,計算attention score時會先進行變換:
其中 是context vector,隨機初始化并隨著訓練更新。最后得到句子表示 ,再進行分類。
這個加attention的套路用到CNN編碼器之后代替pooling也是可以的,從實驗結果來看attention的加入可以提高2個點。如果是情感分析這種由句子整體決定分類結果的任務首選RNN。
HAN
論文:https://www.aclweb.org/anthology/N16-1174.pdf 代碼:https://github.com/richliao/textClassifier上文都是句子級別的分類,雖然用到長文本、篇章級也是可以的,但速度精度都會下降,于是有研究者提出了層次注意力分類框架,即Hierarchical Attention。先對每個句子用 BiGRU+Att 編碼得到句向量,再對句向量用 BiGRU+Att 得到doc級別的表示進行分類:
方法很符合直覺,不過實驗結果來看比起avg、max池化只高了不到1個點(狗頭,真要是很大的doc分類,好好清洗下,fasttext其實也能頂的(捂臉。
BERT
BERT的原理代碼就不用放了叭~
BERT分類的優化可以嘗試:
多試試不同的預訓練模型,比如RoBERT、WWM、ALBERT
除了 [CLS] 外還可以用 avg、max 池化做句表示,甚至可以把不同層組合起來
在領域數據上增量預訓練
集成蒸餾,訓多個大模型集成起來后蒸餾到一個上
先用多任務訓,再遷移到自己的任務
其他模型
除了上述常用模型之外,還有Capsule Network[4]、TextGCN[5]等紅極一時的模型,因為涉及的背景知識較多,本文就暫不介紹了(嘻嘻)。
雖然實際的落地應用中比較少見,但在機器學習比賽中還是可以用的。Capsule Network被證明在多標簽遷移的任務上性能遠超CNN和LSTM[6],但這方面的研究在18年以后就很少了。TextGCN則可以學到更多的global信息,用在半監督場景中,但碰到較長的需要序列信息的文本表現就會差些[7]。
技巧
模型說得差不多了,下面介紹一些自己的數據處理血淚經驗,如有不同意見歡迎討論~
數據集構建
首先是標簽體系的構建,拿到任務時自己先試標一兩百條,看有多少是難確定(思考1s以上)的,如果占比太多,那這個任務的定義就有問題。可能是標簽體系不清晰,或者是要分的類目太難了,這時候就要找項目owner去反饋而不是繼續往下做。
其次是訓練評估集的構建,可以構建兩個評估集,一個是貼合真實數據分布的線上評估集,反映線上效果,另一個是用規則去重后均勻采樣的隨機評估集,反映模型的真實能力。訓練集則盡可能和評估集分布一致,有時候我們會去相近的領域拿現成的有標注訓練數據,這時就要注意調整分布,比如句子長度、標點、干凈程度等,盡可能做到自己分不出這個句子是本任務的還是從別人那里借來的。
最后是數據清洗:
去掉文本強pattern:比如做新聞主題分類,一些爬下來的數據中帶有的XX報道、XX編輯高頻字段就沒有用,可以對語料的片段或詞進行統計,把很高頻的無用元素去掉。還有一些會明顯影響模型的判斷,比如之前我在判斷句子是否為無意義的閑聊時,發現加個句號就會讓樣本由正轉負,因為訓練預料中的閑聊很少帶句號(跟大家的打字習慣有關),于是去掉這個pattern就好了不少
糾正標注錯誤:這個我真的屢試不爽,生生把自己從一個算法變成了標注人員。簡單的說就是把訓練集和評估集拼起來,用該數據集訓練模型兩三個epoch(防止過擬合),再去預測這個數據集,把模型判錯的拿出來按 abs(label-prob) 排序,少的話就自己看,多的話就反饋給標注人員,把數據質量搞上去了提升好幾個點都是可能的
長文本
任務簡單的話(比如新聞分類),直接用fasttext就可以達到不錯的效果。
想要用BERT的話,最簡單的方法是粗暴截斷,比如只取句首+句尾、句首+tfidf篩幾個詞出來;或者每句都預測,最后對結果綜合。
另外還有一些魔改的模型可以嘗試,比如XLNet、Reformer、Longformer。
如果是離線任務且來得及的話還是建議跑全部,讓我們相信模型的編碼能力。
少樣本
自從用了BERT之后,很少受到數據不均衡或者過少的困擾,先無腦訓一版。
如果樣本在幾百條,可以先把分類問題轉化成匹配問題,或者用這種思想再去標一些高置信度的數據,或者用自監督、半監督的方法。
魯棒性
在實際的應用中,魯棒性是個很重要的問題,否則在面對badcase時會很尷尬,怎么明明那樣就分對了,加一個字就錯了呢?
這里可以直接使用一些粗暴的數據增強,加停用詞加標點、刪詞、同義詞替換等,如果效果下降就把增強后的訓練數據洗一下。
當然也可以用對抗學習、對比學習這樣的高階技巧來提升,一般可以提1個點左右,但不一定能避免上面那種尷尬的情況。
總結
文本分類是工業界最常用的任務,同時也是大多數NLPer入門做的第一個任務,我當年就是啥都不會,從訓練到部署地實踐了文本分類后就順暢了。上文給出了不少模型,但實際任務中常用的也就那幾個,下面是快速選型的建議:
實際上,落地時主要還是和數據的博弈。數據決定模型的上限,大多數人工標注的準確率達到95%以上就很好了,而文本分類通常會對準確率的要求更高一些,與其苦苦調參想fancy的結構,不如好好看看badcase,做一些數據增強提升模型魯棒性更實用。
最后,歡迎大家來NLP卷王群一起學習~
參考資料
[1]
A Sensitivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classification: https://arxiv.org/pdf/1510.03820.pdf
[2]卷積層和分類層,哪個更重要?: https://www.zhihu.com/question/270245936
[3]從經典文本分類模型TextCNN到深度模型DPCNN: https://zhuanlan.zhihu.com/p/35457093
[4]揭開迷霧,來一頓美味的Capsule盛宴: https://kexue.fm/archives/4819
[5]Graph Convolutional Networks for Text Classification: https://arxiv.org/abs/1809.05679
[6]膠囊網絡(Capsule Network)在文本分類中的探索: https://zhuanlan.zhihu.com/p/35409788
[7]怎么看待最近比較火的 GNN?: https://www.zhihu.com/question/307086081/answer/717456124
---
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯 本站知識星球“黃博的機器學習圈子”(92416895) 本站qq群704220115。 加入微信群請掃碼:總結
以上是生活随笔為你收集整理的【NLP】深度学习文本分类|模型代码技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度技术Win11 64位最新旗舰版镜像
- 下一篇: 【学术相关】国内考博需要怎么准备?难度大