長文本分類的總結

笨妞很少做文本分類,因爲工作中文本分類確實不怎麼用得到,唯一一個項目用到短文本分類,驗證集acc和f1都到90%以上,所以在笨妞印象中文本分類應該是很簡單的分類問題,都不屬於NLP問題。偶然碰到DC競賽中“達觀杯”文本分類大賽,嘗試了一下新聞類文本的分類。其實並沒有那麼簡單。

 

數據概況

“達觀杯”的主題是19類新聞分類,數據包含4個字段:id(文章索引)、article(字級別文章)、word_seg(詞級別文章)、class(類別),其中字和詞全部用數字代替。

以詞度量文章的長度,其分佈式這樣的:

總體來說,算是長文本吧,且長度分佈比較分散。

各類別的分佈是這樣的:

{'14': 6740, '3': 8313, '12': 5326, '13': 7907, '1': 5375, '10': 4963, '19': 5524, '18': 7066, '7': 3038, '9': 7675, '4': 3824, '17': 3094, '2': 2901, '8': 6972, '6': 6888, '11': 3571, '15': 7511, '5': 2369, '16': 3220}。

 

過程總結

之前做短文本分類的時候用了兩個模型——bilstm和cnn,兩個模型的驗證acc都在90%以上,所有首先考慮這兩個算法。回過頭去看,有這麼高的精度主要還是分類的文章規則性比較強,且屬於特定領域,詞量不多,類別差異可能比較明顯。

搜了一下別人對“文本分類”的總結,貌似中文,基於詞的效果會好於字。因此用第三個字段(詞級別文章)作爲訓練數據。首先訓練詞向量,分別訓練了200維和100維的詞向量做備用。

模型很快搭好,接下來設定輸入長度,一般是以最長的文本長度作爲輸入長度,然而這個數據中,最長的文本達到幾萬字,不太適合,於是設定最長爲1000(80%滿足)。

  1. 首先跑bilstm,沒有GPU,200維詞向量且詞向量在模型中不參與訓練,跑一輪需要20個小時左右,第一輪驗證準確率達到0.74的樣子,沒有勇氣跑第二輪了。

  1. 換上TextCNN,和bilstm相比,速度快到飛起來,30分鐘便可跑一輪,看別人說Textcnn做文本分類容易過擬合,於是採用了變換batch_size和lr,batch_size變化範圍(32, 64, 128, 256), lr從0.0005開始,val_loss連續2次不下降,則lr變爲原來的0.2倍。這樣訓練後,驗證集f1到了0.8,測試集預測後提交,f1只有0.74。CNN並聯和串聯都嘗試過,其中並聯比串聯更容易過擬合。

  2. doc2vec+mlp,這個沒什麼好說的,充數,驗證集f1爲0.7019。

  3. keras版本的fasttext。fasttext之前沒有接觸過,算是一個新收穫。fasttext也是mikolov大神的傑作,原生版的原理基本上和word2vec類似,採用cbow和skgram兩種模型,同樣是一個輸入層+一個隱藏層(映射)+softmax。不同的是,輸入不僅僅是詞,採用了ngram。原生的還需要安裝,於是自組了keras版本的,後來發現,不用原生的是大失誤。keras版本的,ngram設爲2,16G的內存就很喫緊了,原因在於,按照ngram=2遍歷,embedding層最大有幾百萬的節點,句子長度爲1000,算一算確實比較可怕。用ngram=1,跑下來,f1只能到0.72,放棄。

 

4. 機器學習經典文本分類算法嘗試

   tfidf+svm,選錯了svm的kernel,選了非線性kernel,tfidf特徵有100多萬維,用非線性kernel速度太慢了,且效果不好,即便壓縮到5000維,速度還是跟不上。後來別人給的baseline,用linearsvc,速度快,且測試集f1能到0.77。這就是經驗呀。 

tfidf+nb: 原本覺得樸素貝葉斯效果應該不會比mlp差的,但我做出來f1只有 0.59。

 

5. 文本inception:這是“看山杯”文本分類大賽第一名自創的模型,訓練過程中過擬合嚴重,訓練acc到0.92,驗證集val_acc只有0.75.

6. 原生版fasttext: 認真讀了一下fasttext的論文,並看了官網,發現原生版和自己的keras版本還是很不同的,原生版採用C語言,讀入文本沒有最大長度之分。所有數據全部讀進去,且可分bucket,不像一般的深度學習框架,需要對句子進行padding。同時,原生版處理學習率是從0.1開始,然後按照訓練步數來折算學習率的變化值,這也是keras不好操作的。不太明白的一點是:爲什麼word2vec和fasttext用0.1這麼大的學習率,loss也並不震盪。

用原生版fasttext分別訓練了字級別文章和詞級別文章,驗證集準確率分別是0.761和0.77,詞級別測試集f1也達到0.774。好悲傷,搞了這麼久才和人家的baseline同分。

 

想了一下,tfidf+svm和fasttext都有一個共同點——句子的長度對模型沒有影響。而這個數據集中,句子長度分佈太廣了,很難一個模型照顧到短的文本和長文本。那麼要不要做了個多輸入的CNN什麼的呢?想法雖好,但多通路選擇性輸入,訓練的時候怎麼反向傳播呢?好吧,暫時到這兒吧。

 

總結

在cnn和lstm中,嘗試了embedding層訓練和不訓練兩種,參與訓練速度會慢一些,效果也並沒有很好的提升。

複雜的模型未必會有很好的結果,簡單模型效果未必不理想,沒必要一味追求深度學習、複雜模型什麼的。選什麼樣的模型還是要根據數據來的。

同一類問題,不同的數據效果差異很大,不要小看任何一類問題,例如分類,我們通常覺得它很簡單,但有些數據並非你所想。本次“達觀杯”到目前爲止,第一名最高也只有0.80。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章