【NLP】NLP文本分类落地实战五大利器!
作者?|?周俊賢??
整理?|?NewBeeNLP
文本分類是NLP領域的最常見工業(yè)應用之一,也是本人在過去的一年中接觸到最多的NLP應用,本文「從工業(yè)的角度淺談實際落地中文本分類的種種常見問題和優(yōu)化方案」。
由于,項目中的數(shù)據(jù)涉密,所以拿公開的兩個數(shù)據(jù)集進行實驗講解:今日頭條的短文本分類和科大訊飛的長文本分類,數(shù)據(jù)集的下載見github的鏈接。
https://github.com/zhoujx4/NLP-Series-text-cls
今日頭條的短文本數(shù)據(jù)示例如下,通過新聞的標題對新聞進行分類:
可以看到短文本分類的大部分數(shù)據(jù)都是很短的,經(jīng)過EDA,發(fā)現(xiàn)99%以上的數(shù)據(jù)在40個字符以下。
科大訊飛的長文本數(shù)據(jù)示例如下,通過APP的簡介對APP進行類別分類:
經(jīng)過EDA探索,發(fā)現(xiàn)大部分數(shù)據(jù)長度在512以上,超過了Bert等模型的最大輸入長度。
再看看數(shù)據(jù)集的label個數(shù)、訓練集、驗證集和測試集的數(shù)量分布:
| 標簽個數(shù) | 15個 | 119個 |
| 訓練集數(shù) | 229605條 | 10313條 |
| 驗證集數(shù) | 76534條 | 2211條 |
| 測試集數(shù) | 76536條 | 2211條 |
可以看到短文本是屬于樣本充足的情況,20多W條訓練數(shù)據(jù)只需分成15個類,長文本分類屬于樣本不算充足的情況,1W條訓練數(shù)據(jù)要分成119個類,其中數(shù)據(jù)集還有標簽不平衡的問題。
首先搭建Baseline,Baseline用Roberta_base版本,把最后一層Transformer的輸出進行mean和max后進行拼接,再連接全連接層,最后進行標簽分類,由于Bert限制最大長度為512,對于長文本來說,可以通過「transfomrer-XL等改造模型」或者通過「截取字符」(從前面截取,或從中間截取,或從末尾截取)或「把文本進行分塊」,分別輸入模型中,再取概率平均,對于一般的任務,個人主要采用截取字符的方法,因為實現(xiàn)起來簡單。
用Micro F1值作為評價標準,分數(shù)如下。
| baseline | 0.8932 | 0.5579 |
可以看到長文本由于標簽類別多,加上標簽數(shù)據(jù)不太充分,難度比短文本難不少。
1、數(shù)據(jù)增強
1.1 EDA(Easy Data Augmentation)
圖像任務中,有隨機裁剪、翻轉、改變飽和度等操作,同樣地,文本也有不少的增強方法,如同義詞替換,回譯,近音字替換,隨機插入,隨機交換,隨機刪除等等,這里說一下個人平時用得做多,也認為效果最好的兩個,「同義詞替換」和「回譯」
1.1.1 同義詞替換:
做法可以是維護一個同義詞表,如哈工大的發(fā)布的同義詞詞典。在每次訓練的時候,樣本有一定的概率對里面的詞語進行替換。如"自動駕駛、醫(yī)療、能源……一季度融資最多的人工智能公司" -> "自動駕車、醫(yī)術、能源……一季度融資最多的人工智能公司"。根據(jù)經(jīng)驗,「有條件的話最好用項目領域的同義詞詞典」,如做醫(yī)療的文本,就用醫(yī)療的同義詞詞典,做金融領域的就用金融的同義詞詞典,而不是用一個通用的字典。
還有種做法是用詞向量進行替換,如上面的句子中,我們對"駕駛"一次進行同義詞替換,發(fā)現(xiàn)在詞向量表中,離"駕駛"余弦距離最近的一詞是"行駛",所以就把"駕駛"替換成"行駛",當然這樣做的話需要預先訓練一個詞向量表,還是那句話,最好用你目前手頭任務領域的文本來訓練詞向量。
也可以用Bert等模型來進行替換,如把上面的句子隨機MASK掉一些字,變成"自[MASK]駕駛、醫(yī)療、能源……一季[MASK]融資最多的人工智[MASK]公司",再讓Bert對MASK掉的字進行預測,這樣又得到新的一個樣本。
1.1.2 回譯
做法很簡單,把中文翻譯成英文或法文或日本,再翻譯回中文,如下面的句子,先翻譯成英文,再翻譯回中文,"自動駕駛、醫(yī)療、能源……一季度融資最多的人工智能公司" -> "第一季度融資最多的自動駕駛儀、醫(yī)療保健、能源人工智能公司",有時回譯能得到語法結構不同的句子,如被動句變成主動句,有效增強了樣本的多樣性。不過個人覺得,長文本并不適用于回譯,想想一個500多字的長文本,經(jīng)過回譯后,上下文是否還通順是個問題,當然也可以隨機對長文本中的單句進行回譯,而不是把整個長文本進行回譯。
實際項目中取哪種數(shù)據(jù)增強方法,個人感覺是都要進行實驗嘗試,但無論進行何種嘗試,把握一點就是「增強后的樣本要和測試集的樣本分布相似」,其實這也是無論做圖像任務、檢測任務還是機器學習的任務都通用的一點,假如你增強后的樣本與真實要預測的樣本出入很大,你還讓模型去學,那怎么可能會帶來正向的效果呢?對吧。
這里的實驗,采用了同義詞替換這個增強方法,用的同義詞表就是上文提到的哈工大,用的是nlpcda庫(貌似做中文文本增強的庫不多,本人還沒找到幾個用得比較順手的,當然也可以自己寫數(shù)據(jù)增強這部分的代碼,并不復雜),
| baseline | 0.8932 | 0.5579 |
| +數(shù)據(jù)增強(同義詞替換) | 0.8945 | 0.5742 |
可以看到經(jīng)過數(shù)據(jù)增強后,分數(shù)都有所上漲,其實可以說幾乎所有的任務,做數(shù)據(jù)增強都會帶來正向的效果,但這個效果有多大的提升,就很依賴做數(shù)據(jù)增強的方法了,舉個例子,一個樣本"互聯(lián)網(wǎng)時代有隱私可言嗎?" ->"互聯(lián)網(wǎng)時代有心事可言嗎?",這個樣本的增強我認為效果有限,因為增強后已經(jīng)不是一個語義明了的句子了,還是那句話,「增強后的樣本要和實際預測的樣本分布要相似」,這樣才能得到比較好的正向效果。
1.2 對抗訓練
實質(zhì)上,對抗訓練用于文本這幾年基本成為算法比賽獲獎方案的標配,如FGM、PGD、YOPO、FreeLB 等一些系列的思想。個人認為對抗訓練屬于數(shù)據(jù)增強的一部分,因為在深度學習進行文本分類中,無外乎將字或詞映射成向量作為模型輸入。
如輸入為詞的模型,"互聯(lián)網(wǎng)時代有隱私可言嗎?"分詞后是[互聯(lián)網(wǎng),時代,有,隱私,可言,嗎,?],每個詞在word embedding詞表中找到對應的向量作為模型的輸入,“隱私”替換成“秘密”,只是在輸入的時候,把"隱私"這個詞的向量用"秘密"的詞向量作為替換,那自然有個思想,「既然增強的目的是使模型的輸入發(fā)生改變,那為何不能直接從原本的字向量中加入噪聲擾動呢」?
添加噪聲擾動的思想想到了,也有個問題,噪聲有很多種,是加入高斯噪聲、還是均值噪聲還是其它?其中對抗訓練的思想就是「往損失函數(shù)上升的方向,在embedding層添加擾動」,對抗訓練有很多可供學習的代碼和博文[2][3],這里就不再細說了。值得注意的是,添加對抗訓練后,訓練時間會近乎成倍增常,就拿FGM來說,每一次更新參數(shù),都進行了兩次后向傳播。在大部分場景下,基本都會加上FGM,基本都能帶來正向的效果,而且FGM相對其它對抗方法,所耗時間也較少。
| baseline | 0.8932 | 0.5579 |
| +FGM對抗訓練 | 0.8970 | 0.5873 |
可以看到加上對抗訓練后,效果都有一定的提升。
2、數(shù)據(jù)去噪
大家都說算法工程師80%在洗數(shù)據(jù),20%時間在跑模型,實質(zhì)上,以我的個人經(jīng)驗來說,這個說法也是有道理的,一個AI應用,一周的時間要解決的話,在準備數(shù)據(jù)層面可能會花3~4天。特別是做久了之后,很多模型的組件,方法論都已成型,想比較不同方法的效果,從以往積累的項目庫里把相關代碼抽出來,就可以跑來做實驗了,時間成本很低。而且做項目,最后常常會發(fā)現(xiàn),制約模型效果再上一步的,往往是最數(shù)據(jù)質(zhì)量,所以洗數(shù)據(jù)尤為關鍵,想想假如你在一個準確率只有80%的訓練集上訓練模型,你覺得你訓練出來的模型最后在測試集的準確率能超過80%嗎?
通常,接到一個AI需求,假如要訓練機器學習或深度學習的模型,標注數(shù)據(jù)是必不可少的,來源可以是已有的人工標注,沒有的話,只能自己或者找實習生標注進行打標,假如需要的標注樣本多的話,還可以請眾包公司進行標注。就拿文本分類來說,人工標注準確率有95%就已經(jīng)很好了。
怎么清洗標注錯誤的數(shù)據(jù)呢?這個問題其實本人還沒有很深的積累,常常優(yōu)先使用的方法是「根據(jù)業(yè)務規(guī)則洗」,就拿前段時間做的一個工單分類的項目來說(以往是人工分類,客戶想用AI的方法進行自動分類),以往確實積累了幾萬條人工分類過的樣本,但以往的工作人員很多是憑經(jīng)驗進行隨機分類的,所以在看數(shù)據(jù)的時候,看的我皺眉頭,很多都是分類錯誤的,這時候,只能和客戶不斷溝通,拿更多的資料,思考從客戶角度,他們判斷類別的邏輯,從而把錯誤的樣本修正過來,這個過程很耗時,但也很重要,我想這也是實際做項目和打比賽的一個很大的不同。
除此之外,還有沒有更智能的清洗數(shù)據(jù)方法?有不少前沿的論文對這些方法進行過討論,如通過置信度清洗數(shù)據(jù)等等,但實際上,很多方法都僅僅能針對非常有限的場景,效果有限。
本人常常用的比較笨的方法是「交叉驗證清洗」,如"湖人拿到2020年NBA的總冠軍"這樣本,在訓練集上把它標注為"娛樂"新聞,很明顯是錯誤的,像這種錯誤,用交叉驗證的方法洗是最容易的,舉個例子,我們可以對訓練集訓練一個5折的模型,然后對訓練集進行預測,假如這個樣本在5折模型中都預測為"體育",則把該樣本的label從"娛樂"修正為"體育",用交叉驗證的方法能批量洗掉一些很明顯錯誤的樣本,但是這個閾值(出現(xiàn)5次還是4次以上就把該樣本修正)需要多做實驗。
3、類別不平衡
針對類別不平均的問題,有過采樣、欠采樣、改造損失函數(shù)等方法入手。實際項目落地時,還需要考慮客戶的需求,例如某個標簽的樣本很少,導致這個樣本的召回率、精確率都比較低,但可能客戶不太關心這個標簽的精確性,這時候也沒必要花太多時間糾結如何改善。
個人經(jīng)驗來說,我會比較傾向使用改造函數(shù)函數(shù)來調(diào)接樣本不平衡的問題,因為無論是過采樣或者欠采樣,都會導致樣本噪聲這個問題,而改造損失函數(shù),如調(diào)整不同樣本的權重,采用Focal Loss等等函數(shù)都能有限減少不平衡的問題。
關于類別不平衡的問題,有更深入的思考再補充。
4、半監(jiān)督學習
思考上文提到的文本數(shù)據(jù)增強的方法,無論一個樣本經(jīng)過同義詞替換,還是回譯,還是隨機交換詞語的位置生成多個樣本,其實人還是能判斷出這幾個樣本來源同一個句子,從這個角度出發(fā),數(shù)據(jù)增強帶來的效果有限,想想假如訓練集只有100條樣本,無論你怎么做增強,本質(zhì)上,樣本的來源其實就是那100條,這樣模型訓練出來的效果也有限。這時候,就體現(xiàn)出半監(jiān)督學習的重要性,如何把海量的無標注數(shù)據(jù)納入進模型訓練。
前段時間,本人接到一個機器閱讀理解的項目,客戶提供了3W條無標注數(shù)據(jù),花了一天辛辛苦苦標注了1000條,但由于時間關系,客戶說2天必須出結果,還剩下一天要馬上進行模型訓練,這時候就把剩下的2.9W條無標注數(shù)據(jù)拋棄掉嗎?實質(zhì)上,就要考慮半監(jiān)督的方法了。
這里用到的方法是谷歌在2019年的一篇論文:《Unsupervised Data Augmentation for Consistency Training》。
思想很簡單,對于標注好的樣本一樣用交叉熵作為損失函數(shù),對于沒標注的樣本,則用Consistency Loss。
4.1、Consistency Loss(一致性損失)
拿一個例子來說明UDA中的一致性損失,如現(xiàn)在只有【體育,娛樂,金融,政治】四個分類,某個樣本"詹姆斯超喬丹論調(diào)遭麥蒂吐槽:為什么人們總會忘記科比?",在模型訓練過程中,模型判斷出的該樣本屬于四個類別的概率分別為【0.5, 0.15, 0.15, 0.2】,這時候?qū)υ摌颖具M行數(shù)據(jù)增強(這也是論文標題出現(xiàn)Data Augmentation的原因,原論文用了同義詞替換和回譯兩種方法),樣本變成"詹姆斯強于喬丹論調(diào)遭麥蒂埋怨:為什么人們總會遺忘科比?"。一致性的意思就是認為,「增強后的樣本跟原來的樣本語義相同,這時候模型的輸出概率就應該保持一致」,所以增強后的樣本的概率分布應該要去擬合【0.5, 0.15, 0.15, 0.2】這一概率分布。在論文中,「用原樣本的輸出概率分布和增強樣本的輸出概率分布的KL散度損失與有標簽樣本的交叉熵損失進行聯(lián)合訓練」。
在UDA方法中,還有許多訓練的細節(jié),如Sharpening Predictions、TSA(TRAINING SIGNAL ANNEALING)等等,下面簡單介紹一下這些細節(jié)。
4.2、Sharpening Predictions
半監(jiān)督學習的大部分論文中,除了Consistency思想,其實還是一種思路是最小化熵,還是拿一個樣本進行舉例,如"用攝影記錄當紅女星楊冪成長之路"這一無標簽樣本,還是【體育,娛樂,金融,政治】四分類,把樣本輸入模型,模型其實不是直接輸出概率,而是不同的數(shù)值,如【0.50, 1.05, -0.56, 0.01】,把這些數(shù)據(jù)經(jīng)過Sofrmax才得到概率分布【0.27, 0.47, 0.09, 0.17】,這時候同上面的思想一樣,我們把樣本進行數(shù)據(jù)增強后輸入模型,讓輸出的概率去擬合【0.27, 0.47, 0.09, 0.17】這一概率分布。
但在這里我們有個不同的處理,在原樣本的Softmax過程中,我們引入Sharpening Predictions,「Softmax( l(X) / τ )」 計算,其中l(wèi)(X)表示結果邏輯分布概率,即上面的【0.50, 1.05, -0.56, 0.01】,τ 表示溫度。τ 越小,分布越Sharper。如τ =0.6,【0.50, 1.05, -0.56, 0.01】每個元素都除以τ,變?yōu)椤?.83, 1.75, -0.93, 0.02】,再經(jīng)過Softmax,得到分類概率為【0.24, 0.61, 0.04, 0.11】,可以看到τ 取小于1的數(shù),Softmax輸出的概率分布會「更"Sharpening",即為更陡峭,熵也越低」(思考一下,概率分布陡峭了,不確定自然也少了,熵也自然少了)。
為啥要引入Sharpening Predictions?「我認為是為了讓模型輸出能更明確,或者說就是讓熵盡可能小」,讓模型更 傾向輸出【0.97, 0.01, 0.01, 0.01】這種明確性更高的、低熵的概率分布,而不是【0.7, 0.1, 0.1, 0.1】這種相對來說不是很明確的概率分布,增加模型的魯棒性。
4.3、TSA(TRAINING SIGNAL ANNEALING)
思考一個問題,假如你現(xiàn)在只有50個標注樣本和20K個無標注樣本,假如不經(jīng)過任何處理,直接進行聯(lián)合訓練,很可能的情況是,模型會對50個標注樣本過擬合,因為標注樣本數(shù)量實在太少了,所以這里引入TSA。
舉個例子,我們?nèi)SA=0.5,對于某個標注樣本"去年A股上市公司高管薪酬比拼:金融和房地產(chǎn)業(yè)最高",還是【體育,娛樂,金融,政治】四分類,其真實標簽為"金融",模型輸出的概率分布為【0.1, 0.1, 0.7, 0.1】,由于其真實標簽的概率為0.7>0.5,所以我們不把該樣本的損失考慮進行,只有其真實標簽的概率小于TSA的樣本的損失我們才用來進行反向傳播,通過這一方法,「減緩模型對于少量標簽樣本過擬合的步伐」。TSA系數(shù)是隨著訓練過程不斷增加的。
具體的,假如分類問題很簡單,標注樣本相對無標注樣本很少的情況下,就用指數(shù)增長,在前期,TSA系數(shù)增常很慢,維持在一個很低的值,盡可能不把容易學習的標注樣本的損失考慮進去,避免模型對標注樣本過擬合。
4.4、Confidence Mask
首先設定Confidence Mask系數(shù),如把Confidence Mask Coefficient=0.5,把無標注樣本輸入模型,得到概率分布為【0.3, 0.25, 0.4, 0.05】,由于最大的類別概率也少于0.5,所以就不把該無標注樣本的 Consistency Loss 納入到反向傳播中。
UDA的詳細效果請看下表,
| 50條標注數(shù)據(jù) | 0.6443 |
| 50條標注數(shù)據(jù)+30W條無標注數(shù)據(jù)(無標注取自訓練集+驗證集+測試集) | 0.7410 |
| 100條標注數(shù)據(jù) | 0.7342 |
| 100條標注數(shù)據(jù)+30W條無標注數(shù)據(jù)(無標注取自驗證集+測試集) | 0.7877 |
| 20W條標注數(shù)據(jù) | 0.8933 |
| 20W條標注數(shù)據(jù)+10W條無標注數(shù)據(jù)(無標注取自驗證集+測試集) | 0.8920 |
可以看到引入半監(jiān)督學習,在缺少標注數(shù)據(jù)的情況下,提升巨大,但隨著標注數(shù)據(jù)的不斷增加,半監(jiān)督帶來的正向效果也在不斷減少,在原論文中討論過,「當標注數(shù)據(jù)充分的情況下,無監(jiān)督仍能帶來少量的提升」。
但在本實驗中,看最后兩行,可以發(fā)現(xiàn)標注數(shù)據(jù)充分的情況下,引入半監(jiān)督是沒有提升的,我估計是這里的數(shù)據(jù)增強做得太簡單了,這里的數(shù)據(jù)增強只是對句子中的詞進行同義詞替換, 而原論文用了一種考慮更細致的方法,思想是用TF-IDF進行統(tǒng)計,「樣本中對分類成功貢獻很大的詞,不進行替換」,更詳細的思想可以看原論文和論文源代碼。
5、模型輕量化
模型輕量化也是更實際落地常常碰到的問題,一般的AI項目,可能存在資源不充足的情況,如客戶提供的服務器不包括GPU,這時候就要在自己公司的服務器上把模型先訓練好,再遷移到客戶的服務器,用CPU部署,這時要考慮推斷速度是否滿足項目需求,也有可能是服務器可能不止部署你一個模型,還要部署其它系統(tǒng)應用,這時候給你留下的內(nèi)存就不足了。當然最好是項目前期,就像客戶說明需求的配置,讓客戶盡量滿足,但實際上,隨著項目的進展,很可能發(fā)生各種意外情況。
在實際部署中,本人比較傾向用docker這種微服務進行部署,通常一個bert模型加上docker需要的基礎環(huán)境,用CPU進行部署,把容器起起來后,占用的內(nèi)存會到2G左右,推斷速度大概在1~2秒/一個樣本。
模型輕量化也有幾種思路,如「模型剪枝」(把貢獻不高的神經(jīng)元去掉)、換「輕量化模型」(如用3層Bert代替原生的12層Bert、或者換Fasttext等輕量化模型)、「模型蒸餾」(TinyBert等蒸餾模型)。
想想在某個應用種,Bert模型能得到89%的準確率,FastText能得到85%的準確率,最終上線的時候你會考慮用哪個模型?不是說Bert不好,但畢竟它在某些資源有限的情形下,還是顯得太"重"了,但Bert可以作為一個性能標桿,用輕量化的模型不斷去逼近Bert的效果。
以上就是實際落地中,文本分類常遇到的問題和相應的解決方法。本文會不斷完善。
參考
nlpcda庫 https://pypi.org/project/nlpcda/
【煉丹技巧】功守道:NLP中的對抗訓練 + PyTorch實現(xiàn) https://zhuanlan.zhihu.com/p/91269728
一文搞懂NLP中的對抗訓練FGSM/FGM/PGD/FreeAT/YOPO/FreeLB/SMART https://zhuanlan.zhihu.com/p/103593948
《Unsupervised Data Augmentation for Consistency Training》 http://cn.arxiv.org/pdf/1904.12848v5
-?END?-
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統(tǒng)計學習方法》的代碼復現(xiàn)專輯 AI基礎下載機器學習的數(shù)學基礎專輯黃海廣老師《機器學習課程》視頻課本站qq群851320808,加入微信群請掃碼:
總結
以上是生活随笔為你收集整理的【NLP】NLP文本分类落地实战五大利器!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小老鼠艾尔的新毯子
- 下一篇: Spring事务配置实例