NLP大賽冠軍總結:300萬知乎多標簽文本分類任務(附深度學習源碼)
七月,酷暑難耐,認識的幾位同學參加知乎看山杯,均取得不錯的排名。當時天池AI醫療大賽初賽結束,官方正在為復賽進行平台調試,復賽時間一拖再拖。看着幾位同學在比賽中排名都還很不錯,於是決定抽空試一試。結果一發不可收拾,又找了兩個同學一起組隊(隊伍init)以至於整個暑假都投入到這個比賽之中,並最終以一定的優勢奪得第一名。 1. 比賽介紹這是一個文本多分類的問題:目標是“參賽者根據知乎給出的問題及話題標簽的綁定關系的訓練數據,訓練出對未標注數據自動標注的模型”。通俗點講就是:當用戶在知乎上提問題時,程序要能夠根據問題的內容自動為其添加話題標簽。一個問題可能對應着多個話題標簽,如下圖所示。
![]() 這是一個文本多分類,多label的分類問題(一個樣本可能屬於多個類別)。總共有300萬條問題-話題對,超過2億詞,4億字,共1999個類別。 1.1 數據介紹參考 https://biendata.com/competition/zhihu/data/ https://biendata.com/competition/zhihu/rules/?next_url=%2Fcompetition%2Fzhihu%2Fdata%2F
總的來說就是:
1.2 數據處理數據處理主要包括兩部分:
![]()
1.3 數據增強文本中數據增強不太常見,這里我們使用了shuffle和drop兩種數據增強,前者打亂詞順序,后者隨機的刪除掉某些詞。效果舉例如圖:
1.4 評價指標每個預測樣本,提供最有可能的五個話題標簽,計算加權后的准確率和召回率,再計算F1值。注意准確率是加權累加的,意味着越靠前的正確預測對分數貢獻越大,同時也意味着准確率可能高於1,但是F1值計算的時候分子沒有乘以2,所以0.5是很難達到的。
2 模型介紹建議大家先閱讀這篇文章,了解文本多分類問題幾個常用模型:用深度學習(CNN RNN Attention)解決大規模文本分類問題 https://zhuanlan.zhihu.com/p/25928551
2.1 通用模型結構文本分類的模型很多,這次比賽中用到的模型基本上都遵循以下的架構:
![]()
基本思路就是,詞(或者字)經過embedding層之后,利用CNN/RNN等結構,提取局部信息、全局信息或上下文信息,利用分類器進行分類,分類器的是由兩層全連接層組成的。 在開始介紹每個模型之前,這里先下幾個結論:
2.2 TextCNN這是最經典的文本分類模型,這里就不細說了,模型架構如下圖:
![]()
和原始的論文的區別就在於:
總之就是更深,更復雜。不過卷積核的尺寸設計的不夠合理,導致感受野差距過大。 2.3 TextRNN沒找到論文,我就憑感覺實現了一下:
![]()
相比於其他人的做法,這里的不同點在於:
2.4 TextRCNN參考原論文的實現,和RNN類似,也是兩層雙向LSTM,但是需要和Embedding層的輸出Concat(類似於resnet的shortcut直連)。
![]()
2.5 TextInception這個是我自己提出來的,參照TextCNN的思想(多尺度卷積核),模仿Inception的結構設計出來的,一層的Inception結構如下圖所示,比賽中用了兩層的Inception結構,最深有4層卷積,比TextCNN更深。
![]()
2.6 訓練方法要點:
2.7 各個模型分數計算訓練的時候,每個模型要么只訓練基於詞(word)的模型,要么只訓練基於字(char)的模型。各個模型的分數都差不多,這里不再單獨列出來了,只區分訓練的模型的類型和數據增強與否。
![]()
可以看出來
2.8 模型融合像這種模型比較簡單,數據量相對比較小的比賽,模型融合是比賽獲勝的關鍵。 在這里,我只使用到了最簡單的模型融合方法-----概率等權重融合。對於每個樣本,單模型會給出一個1999維的向量,代表着這個模型屬於1999個話題的概率。融合的方式就是把每一個模型輸出的向量直接相加,然后選擇概率最大的5個話題提交。結構如圖所示:
![]()
下面我們再來看看兩個模型融合的分數:
![]()
第一列的對比模型采用的是RNN(不采用數據增強,使用word作為訓練數據),第二列是四個不同的模型(不同的結構,或者是不同的數據)。 我們可以得出以下幾個結論:
總結: 差異性越大,模型融合效果越好。沒有差異性,創造條件也要制造差異性。 另外模型融合還有個規律:越往上越難提升,有些模型在你分數較低的時候,對融合提升很明顯,當你分數較高的時候就沒什么幫助,甚至會有干擾 2.9 MultiModel其實模型融合的方式,我們換一種角度考慮,其實就是一個很大的模型,每一個分支就像多通道的TextCNN一樣。那么我們能不能訓練一個超級大的模型?答案是可以的,但是效果往往很差。因為模型過於復雜,太難以訓練。這里我嘗試了兩種改進的方法。 第一種方法,利用預訓練好的單模型初始化復雜模型的某一部分參數,模型架構如圖所示:
![]()
但是這種做法會帶來一個問題: 模型過擬合很嚴重,難以學習到新的東西。因為單模型在訓練集上的分數都接近0.5,已經逼近理論上的極限分數,這時候很難接着學習到新的內容。這里采取的應對策略是采用較高的初始學習率,強行把模型從過擬合點拉出來,使得模型在訓練集上的分數迅速降低到0.4左右,然后再降低學習率,緩慢學習,提升模型的分數。 第二種做法是修改預訓練模型的embedding矩陣為官方給的embedding權重。這樣共享embedding的做法,能夠一定程度上抑制模型過擬合,減少參數量。雖然CNN/RNN等模型的參數過擬合,但是由於相對應的embedding沒有過擬合,所以模型一開始分數就會下降許多,然后再緩慢提升。這種做法更優。在最后提交模型復現成績的時候,我只提交了七個這種模型,里面包含着不同子模型的組合,一般包含3-4個子模型。這種方式生成的權重文件也比較小(600M-700M左右),上傳到網盤相對來說更方便。
![]()
2.10 失敗的模型或沒什么用的方法MultiMode只是我諸多嘗試的方法中比較成功的一個,其它方法大多以失敗告終(或者效果不明顯)
3 結束語我之前雖然學過CS224D的課程,也做了前兩次的作業,但是除此之外幾乎從來沒寫過自然語言處理相關的代碼,能拿第一離不開隊友的支持,和同學們不斷的激勵。 這次比賽入門對我幫助最大的兩篇文章是用深度學習(CNN RNN Attention)解決大規模文本分類問題 https://zhuanlan.zhihu.com/p/25928551 和deep-learning-nlp-best-practices http://ruder.io/deep-learning-nlp-best-practices/index.html 第一篇是北郵某學長(但我並不認識~)寫的,介紹了許多文本分類的模型(CNN/RNN/RCNN),對我入門幫助很大。 第二篇是國外某博士寫的,當時我已經把分數刷到前三,在家看到了這篇文章,嘆為觀止,解釋了我很多的疑惑,提到的很多經驗總結和我的情況也確實相符。https://zhuanlan.zhihu.com/p/28923961
|